自適應閾值大津法(OTSU)介紹及程式碼實現
https://blog.csdn.net/a153375250/article/details/50970104
演算法原理
最大類間方差法是由日本學者大津於1979年提出的,是一種自適應的閾值確定法,又叫大津法,簡稱OTSU。
我用最簡單的方式解釋一下演算法原理:
這個演算法的思想就是假設閾值T將影象分成了前景和背景兩個部分。
求出這兩個部分的類間方差:
前景畫素個數佔比x(前景平均灰度 - 全圖平均灰度)2 + 背景畫素個數佔比x(背景平均灰度 - 全圖平均灰度)2
將閾值從0~255遍歷一次,使上述類間方差最大的閾值T即為所求。
類間方差計算
我們接下來將演算法原理中的類間方差化簡為一個比較簡單的形式,下面的過程也是程式碼實現的過程。
定義變數:
總畫素數:N
前景畫素數:fN
背景畫素數:bN
前景畫素灰度和:fSum
背景畫素灰度和:bSum
前景畫素平均灰度:fu
背景畫素平均灰度:bu
影象總灰度值:Sum
影象平均灰度:u
前景畫素佔比:fw
背景影象佔比:bw
類間方差:g
1
2
3
4
5
6
7
8
9
10
11
12
前景、背景佔比:
前景畫素佔比:fw = fN/N
背景畫素佔比:bw = bN/N
1
2
前景、背景佔比滿足:
fw + bw =1 (1)
1
圖片平均灰度值:
圖片灰度直方圖 : Histogram[256]
圖片總灰度值 Sum : for(i=0; i<N; i++){ Sum += Histogram[i];}
圖片平均灰度值 u : Sum/N
1
2
3
閾值為T時前景平均灰度:
閾值為T時前景畫素數 fN : for(i=0; i<=T; i ++) { fN += Histogram[i];}
閾值為T時前景畫素灰度和 fSum : for(i=0; i<=T; i++) { fSum += Histogram[i]*i;}
閾值為T時前景平均灰度 fu : fSum/fN
1
2
3
閾值為T時背景平均灰度:
閾值為T時背景畫素數 bN : N-fN
閾值為T時背景畫素灰度和 bSum : Sum-fSum
閾值為T時背景平均灰度 bu : bSum/bN
1
2
3
平均灰度滿足:
u = fu*fw + bu*bw (2)
1
類間方差:
類間方差 g:fw*(fu-u)^2+bw*(bu-u)^2 (3)
1
將(1)(2)帶入(3)式:
g = bw*fw*(fu-bu)^2
1
程式碼實現
假設讀入圖片為單通道Mat型灰度圖,我們可以用以下程式碼實現:
#include <opencv2/opencv.hpp>
#include <cv.h>
#include <highgui.h>
#include <cxcore.h>
using namespace std;
using namespace cv;
Mat otsuGray(const Mat src) {
Mat img = src;
int c = img.cols; //影象列數
int r = img.rows; //影象行數
int T = 0; //閾值
uchar* data = img.data; //資料指標
int ftNum = 0; //前景畫素個數
int bgNum = 0; //背景畫素個數
int N = c*r; //總畫素個數
int ftSum = 0; //前景總灰度值
int bgSum = 0; //背景總灰度值
int graySum = 0;
double w0 = 0; //前景畫素個數佔比
double w1 = 0; //背景畫素個數佔比
double u0 = 0; //前景平均灰度
double u1 = 0; //背景平均灰度
double Histogram[256] = {0}; //灰度直方圖
double temp = 0; //臨時類間方差
double g = 0; //類間方差
//灰度直方圖
for(int i = 0; i < r ; i ++) {
for(int j = 0; j <c; j ++) {
Histogram[img.at<uchar>(i,j)]++;
}
}
//求總灰度值
for(int i = 0; i < 256; i ++) {
graySum += Histogram[i]*i;
}
for(int i = 0; i < 256; i ++) {
ftNum += Histogram[i]; //閾值為i時前景個數
bgNum = N - ftNum; //閾值為i時背景個數
w0 = (double)ftNum/N; //前景畫素佔總數比
w1 = (double)bgNum/N; //背景畫素佔總數比
if(ftNum == 0) continue;
if(bgNum == 0) break;
//前景平均灰度
ftSum += i*Histogram[i];
u0 = ftSum/ftNum;
//背景平均灰度
bgSum = graySum - ftSum;
u1 = bgSum/bgNum;
g = w0*w1*(u0-u1)*(u0-u1);
if(g > temp) {
temp = g;
T = i;
}
}
for(int i=0; i<img.rows; i++)
{
for(int j=0; j<img.cols; j++)
{
if((int)img.at<uchar>(i,j)>T)
img.at<uchar>(i,j) = 255;
else
img.at<uchar>(i,j) = 0;
}
}
return img;
}
---------------------
作者:Easy-Sir
來源:CSDN
原文:https://blog.csdn.net/a153375250/article/details/50970104
版權宣告:本文為博主原創文章,轉載請附上博文連結!