二值化是圖像分割的一種方法窗慎。在二值化圖象的時候把大于某個臨界灰度值的像素灰度設為灰度極大值,把小于這個值的像素灰度設為灰度極小值,從而實現二值化靠粪。
根據閾值選取的不同蜡吧,二值化的算法分為固定閾值和自適應閾值。 比較常用的二值化方法則有:雙峰法占键、P參數法昔善、迭代法和OTSU法等。
1畔乙、雙峰法
在一些簡單的圖像中耀鸦,物體的灰度分布比較有規(guī)律,背景與目標在圖像的直方圖各自形成一個波峰啸澡,即區(qū)域與波峰一一對應袖订,每兩個波峰之間形成一個波谷。那么嗅虏,選擇雙峰之間的波谷所代表的灰度值T作為閾值洛姑,即可實現兩個區(qū)域的分割。如圖所示
在直方圖中我們可以明顯的看到兩個山峰狀的圖像分布皮服,山峰的頂點我們記為Hmax1和Hmax2楞艾,他們對應的灰度值分別為T1和T2,那么雙峰法圖像分割的思想就是找到圖像兩個山峰之間的谷地最低值龄广,即在[T1硫眯,T2]的灰度范圍內尋找閾值T,使其滿足對應的像素數目最少择同,表現在圖像上就是高度最低两入,用T對圖像進行分割或二值化。
2敲才、P參數法
2.1 原理
所謂P分位法圖像分割裹纳,就是在知道圖像中目標所占的比率Ratio時,循環(huán)不同的灰度值對圖像進行分割紧武,并計算對應的目標所占的比率剃氧,如果該比率與Ratio的差值足夠小,那么該閾值就是所求的最佳分割閾值阻星。
2.2 算法
算法過程如下:
- 已知目標圖像所占比率P朋鞍;
- 設定一閾值Th,它將圖像分割為兩部分妥箕,目標部分A和背景部分B滥酥,統(tǒng)計兩部分所包含的像素數目分別為Na和Nb;
-
將Th從1-254迭代矾踱,每改變一次Th 恨狈,計算一次Na,Nb呛讲,根據Na禾怠,Nb計算目標所占的比率P返奉,公式如下:
-
計算當前閾值對應的分割比率與已知比率的差值,若小于某閾值則停止迭代吗氏,否則芽偏,轉至3繼續(xù)進行,公式如下:
其中T為某一小數
3弦讽、迭代法
3.1 原理
迭代選擇法是首先猜測一個初始閾值污尉,然后再通過對圖像的多趟計算對閾值進行改進的過程。重復地對圖像進行閾值操作往产,將圖像分割為對象類和背景類被碗,然后來利用每一個類中的灰階級別對閾值進行改進。
3.2 算法
- 為全局閾值選擇一個初始估計值T(圖像的平均灰度)仿村。
- 用T分割圖像锐朴。產生兩組像素:G1有灰度值大于T的像素組成,G2有小于等于T像素組成蔼囊。
- 計算G1和G2像素的平均灰度值m1和m2焚志;
- 計算一個新的閾值:T = (m1 + m2) / 2;
- 重復步驟2和4,直到連續(xù)迭代中的T值間的差小于一個預定義參數為止。
3.3 代碼
/**
* 迭代法
*
* @param srcImg 灰度圖像
* @param maxIter 最大迭代次數
*/
+ (int)detechThreshold:(IplImage *)srcImg maxIterat:(int)maxIter{
//圖像信息
int height = srcImg->height;
int width = srcImg->width;
int step = srcImg->widthStep/sizeof(uchar);
uchar *data = (uchar*)srcImg->imageData;
int iDiffRec =0; //使用給定閥值確定的亮區(qū)與暗區(qū)平均灰度差異值, 根據需要返回
int F[256]={ 0 }; //直方圖數組
int iTotalGray=0;//灰度值和
int iTotalPixel =0;//像素數和
Byte bt;//某點的像素值
uchar iThrehold,iNewThrehold;//閥值畏鼓、新閥值
uchar iMaxGrayValue=0,iMinGrayValue=255;//原圖像中的最大灰度值和最小灰度值
uchar iMeanGrayValue1,iMeanGrayValue2;
//獲取(i,j)的值酱酬,存于直方圖數組F
for(int i=0;i<width;i++){
for(int j=0;j<height;j++){
bt = data[i*step+j];
if(bt<iMinGrayValue)
iMinGrayValue = bt;
if(bt>iMaxGrayValue)
iMaxGrayValue = bt;
F[bt]++;
}
}
iThrehold =0;
iNewThrehold = (iMinGrayValue+iMaxGrayValue)/2;//初始閥值
iDiffRec = iMaxGrayValue - iMinGrayValue;
for(int a=0;(abs(iThrehold-iNewThrehold)>0.5)&&a<maxIter;a++){ //迭代中止條件
iThrehold = iNewThrehold;
//小于當前閥值部分的平均灰度值
for(int i=iMinGrayValue;i<iThrehold;i++){
iTotalGray += F[i]*i;//F[]存儲圖像信息
iTotalPixel += F[i];
}
iMeanGrayValue1 = (uchar)(iTotalGray/iTotalPixel);
//大于當前閥值部分的平均灰度值
iTotalPixel =0;
iTotalGray =0;
for(int j=iThrehold+1;j<iMaxGrayValue;j++){
iTotalGray += F[j]*j;//F[]存儲圖像信息
iTotalPixel += F[j];
}
iMeanGrayValue2 = (uchar)(iTotalGray/iTotalPixel);
iNewThrehold = (iMeanGrayValue2+iMeanGrayValue1)/2; //新閥值
iDiffRec = abs(iMeanGrayValue2 - iMeanGrayValue1);
}
return iThrehold;
}
4. OTSU法
4.1 原理
最大類間方差法是由日本學者大津于1979年提出的,是一種自適應的閾值確定的方法,又叫大津法,簡稱OTSU。它是按圖像的灰度特性,將圖像分成背景和目標2部分云矫。背景和目標之間的類間方差越大,說明構成圖像的2部分的差別越大,當部分目標錯分為背景或部分背景錯分為目標都會導致2部分差別變小膳沽。因此,使類間方差最大的分割意味著錯分概率最小。對于圖像I(x,y),前景(即目標)和背景的分割閾值記作T,屬于前景的像素點數占整幅圖像的比例記為ω0,其平均灰度μ0;背景像素點數占整幅圖像的比例為ω1,其平均灰度為μ1泼差。圖像的總平均灰度記為μ,類間方差記為g贵少。
4.2 算法
假設圖像的背景較暗,并且圖像的大小為M×N,圖像中像素的灰度值小于閾值T的像素個數記作N0,像素灰度大于閾值T的像素個數記作N1,則有:
ω0=N0/ M×N (1)
ω1=N1/ M×N (2)
N0+N1=M×N (3)
ω0+ω1=1 (4)
μ=ω0μ0+ω1μ1 (5)
g=ω0(μ0-μ)2+ω1(μ1-μ)2 (6)
將式(5)代入式(6),得到等價公式: g=ω0ω1(μ0-μ1)^2 (7)采用遍歷的方法得到使類間方差最大的閾值T,即為所求呵俏。
4.3 代碼實現
代碼實現如下:
int OTSU(unsigned char* pGrayImg , int iWidth , int iHeight)
{
if((pGrayImg==0)||(iWidth<=0)||(iHeight<=0))return -1;
int ihist[256];
int thresholdValue=0; // ?–÷μ
int n, n1, n2 ;
double m1, m2, sum, csum, fmax, sb;
int i,j,k;
memset(ihist, 0, sizeof(ihist));
n=iHeight*iWidth;
sum = csum = 0.0;
fmax = -1.0;
n1 = 0;
for(i=0; i < iHeight; i++)
{
for(j=0; j < iWidth; j++)
{
ihist[*pGrayImg]++;
pGrayImg++;
}
}
pGrayImg -= n;
for (k=0; k <= 255; k++)
{
sum += (double) k * (double) ihist[k];
}
for (k=0; k <=255; k++)
{
n1 += ihist[k];
if(n1==0)continue;
n2 = n - n1;
if(n2==0)break;
csum += (double)k *ihist[k];
m1 = csum/n1;
m2 = (sum-csum)/n2;
sb = (double) n1 *(double) n2 *(m1 - m2) * (m1 - m2);
if (sb > fmax)
{
fmax = sb;
thresholdValue = k;
}
}
return(thresholdValue);
}
5堆缘、一維最大熵法
5.1 原理
一維最大熵法圖像分割就是利用圖像的灰度分布密度函數定義圖像的信息熵,通過優(yōu)化一定的熵準則得到熵最大時對應的閾值普碎,從而進行圖像分割的方法吼肥。
5.2 算法
算法過程:
- 對于一幅灰度圖像,灰度范圍為[0,L-1]麻车,求取圖像的最小灰度級min缀皱,最大灰度級max;
-
按照如下熵的公式求取灰度t對應的熵值动猬;
其中啤斗,pi表示灰度級i出現的概率。
- 計算t從最小灰度min到最大灰度max之間不同灰度級所對應的熵值E(t)赁咙,求取E(t)最大時所對應的灰度級t钮莲,該灰度級即為所求的閾值Th免钻。
5.3 代碼
代碼實現如下:
// 計算當前位置的能量熵
#define cvQueryHistValue_1D( hist, idx0 ) \((float)cvGetReal1D( (hist)->bins, (idx0)))
+ (double)caculateCurrentEntropy:(CvHistogram *)histogram currentThreshold:(int)threshold state:(EntropyState)state{
int start,end;
int total =0;
double cur_entropy =0.0;
if(state == Back){
start =0;
end = threshold;
}else{
start = threshold;
end =256;
}
for(int i=start;i<end;i++){
total += (int)cvQueryHistValue_1D(histogram,i);//查詢直方塊的值 P304
}
for(int j=start;j<end;j++)
{
if((int)cvQueryHistValue_1D(histogram,j)==0)
continue;
double percentage = cvQueryHistValue_1D(histogram,j)/total;
/*熵的定義公式*/
cur_entropy +=-percentage*logf(percentage);
/*根據泰勒展式去掉高次項得到的熵的近似計算公式
cur_entropy += percentage*percentage;*/
}
return cur_entropy;
}
//尋找最大熵閾值并分割
+ (int)maxEntropy:(IplImage *)srcImg{
/**
* 創(chuàng)建直方圖
*
* @param dims 直方圖維數的數目
* @param sizes 直方圖維數尺寸的組數
* @param type 直方圖的表示格式: CV_HIST_ARRAY 意味著直方圖數據表示為多維密集數組 CvMatND; CV_HIST_TREE 意味著直方圖數據表示為多維稀疏數組 CvSparseMat.
*/
int hist_size = 256;
CvHistogram *hist = cvCreateHist(1, &hist_size, CV_HIST_ARRAY);
cvCalcHist(&srcImg, hist);
double maxentropy = -1.0;
int max_index = -1;
// 循環(huán)測試每個分割點,尋找到最大的閾值分割點
for (int i=0; i < hist_size; i++) {
double backValue = [[self class] caculateCurrentEntropy:hist currentThreshold:i state:Back];
double frontValue = [[self class] caculateCurrentEntropy:hist currentThreshold:i state:Object];
double cur_entropy = backValue + frontValue;
if(cur_entropy>maxentropy){
maxentropy = cur_entropy;
max_index = i;
}
}
return max_index;
}
參考文章:
圖像二值化----otsu(最大類間方差法崔拥、大津算法)
圖像基本變換---圖像二值化(包含OSTU/迭代法/統(tǒng)計法/雙峰法/P分位法/最大熵法)
七種常見閾值分割代碼(Otsu极舔、最大熵、迭代法链瓦、自適應閥值拆魏、手動、迭代法慈俯、基本全局閾值法)