灰階映像二值化-大津法
大津法又稱最大類間方差法。對映像,記t為前景與背景的分割閾值,前景點數占映像比例為
w0,
平均灰階為u0;背景點數占映像比例為w1,平均灰階為u1。映像的總平均灰階為:u=w0*u0+w1*u1。從最小灰階值到最大灰階值遍曆t,當t使
得值g=w0*(u0-u)2
+w1*(u1-u)2
最大時t即為分割的最佳閾值。閾值t分割出的前景和背景兩部分構成了整幅映像,而前景取值u0,機率為w0,背景取值u1,機率為w1,總均值為u,根據
方差的定義即得該式。因方差是灰階分布均勻性的一種度量,方差值越大,說明構成映像的兩部分差別越大,當部分目標錯分為背景或部分背景錯分為目標都會導致
兩部分差別變小,因此使類間方差最大的分割意味著錯分機率最小。直接應用大津法計算量較大,因此我們在實現時採用了等價的公式g=w0*w1*(u0-
u1)2
。
// 擷取長條圖<br />// 1. pImageData 映像資料<br />// 2. nWidth 映像寬度<br />// 3. nHeight 映像高度<br />// 4. nWidthStep 映像行大小<br />// 5. pHistogram 灰階長條圖,大小256<br />bool GetHistogram(unsigned char *pImageData, int nWidth, int nHeight, int nWidthStep, int *pHistogram)<br />{<br /> int i = 0;<br /> int j = 0;<br /> unsigned char *pLine = NULL;<br /> // 清空長條圖<br /> memset(pHistogram, 0, sizeof(int) * 256);<br /> for (pLine = pImageData, j = 0; j < nHeight; j++, pLine += nWidthStep)<br /> {<br /> for (i = 0; i < nWidth; i++)<br /> {<br /> pHistogram[pLine[i]]++;<br /> }<br /> }<br /> return true;<br />}<br />// 大津法<br />// 1. pImageData 映像資料<br />// 2. nWidth 映像寬度<br />// 3. nHeight 映像高度<br />// 4. nWidthStep 映像行大小<br />// 函數返回閾值<br />int Otsu(unsigned char *pImageData, int nWidth, int nHeight, int nWidthStep)<br />{<br /> int i = 0;<br /> int j = 0;<br /> int nTotal = 0;<br /> int nSum = 0;<br /> int A = 0;<br /> int B = 0;<br /> double u = 0;<br /> double v = 0;<br /> double dVariance = 0;<br /> double dMaximum = 0;<br /> int nThreshold = 0;<br /> int nHistogram[256];<br /> // 擷取長條圖<br /> GetHistogram(pImageData, nWidth, nHeight, nWidthStep, nHistogram);<br /> for (i = 0; i < 256; i++)<br /> {<br /> nTotal += nHistogram[i];<br /> nSum += (nHistogram[i] * i);<br /> }<br /> for (j = 0; j < 256; j++)<br /> {<br /> A = 0;<br /> B = 0;<br /> for (i = 0; i < j; i++)<br /> {<br /> A += nHistogram[i];<br /> B += (nHistogram[i] * i);<br /> }<br /> if (A > 0)<br /> {<br /> u = B / A;<br /> }<br /> else<br /> {<br /> u = 0;<br /> }<br /> if (nTotal - A > 0)<br /> {<br /> v = (nSum - B) / (nTotal - A);<br /> }<br /> else<br /> {<br /> v = 0;<br /> }<br /> dVariance = A * (nTotal - A) * (u - v) * (u - v);<br /> if (dVariance > dMaximum)<br /> {<br /> dMaximum = dVariance;<br /> nThreshold = j;<br /> }<br /> }<br /> return nThreshold;<br />}