OTSU_影象二值化分割閾值的演算法
簡介:
大津法(OTSU)是一種確定影象二值化分割閾值的演算法,由日本學者大津於1979年提出。從大津法的原理上來講,該方法又稱作最大類間方差法,因為按照大津法求得的閾值進行影象二值化分割後,前景與背景影象的類間方差最大(何為類間方差?原理中有介紹)。
OTSU演算法
OTSU演算法也稱最大類間差法,有時也稱之為大津演算法,由大津於1979年提出,被認為是影象分割中閾值選取的最佳演算法,計算簡單,不受影象亮度和對比度的影響,因此在數字影象處理上得到了廣泛的應用。它是按影象的灰度特性,將影象分成背景和前景兩部分。因方差是灰度分佈均勻性的一種度量,背景和前景之間的類間方差越大,說明構成影象的兩部分的差別越大,當部分前景錯分為背景或部分背景錯分為前景都會導致兩部分差別變小。因此,使類間方差最大的分割意味著錯分概率最小。
原理:
對於影象I(x,y),前景(即目標)和背景的分割閾值記作T,屬於前景的畫素點數佔整幅影象的比例記為ω0,其平均灰度μ0;背景畫素點數佔整幅影象的比例為ω1,其平均灰度為μ1。影象的總平均灰度記為μ,類間方差記為g。
假設影象的背景較暗,並且影象的大小為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) 這就是類間方差
採用遍歷的方法得到使類間方差g最大的閾值T,即為所求。
matlab函式:
matlab中函式graythresh既是使用大津法求得分割閾值T。用法如下:
T = graythresh(img); %得到影象二值化分割的閾值T
BW = im2bw(img,T); %對img這個影象做影象二值化閾值分割
大津法的形象理解:
對於直方圖有兩個峰值的影象,大津法求得的T近似等於兩個峰值之間的低谷。
imhist(img);
T = graythresh(img);
如下圖為影象的直方圖,使大津法求得的T=0.5294,轉換在[0,255]之間為134.9970,只好是兩個峰值之間低谷的位置。
OpenCV的二值化操作中,有一種“大津閾值處理”的方法,使用函式cvThreshold(image,image2,0,255,CV_THRESH_OTSU) 實現,該函式就會使用大律法OTSU得到的全域性自適應閾值來進行二值化圖片,而引數中的threshold不再起作用。以下是一段在OpenCV中實現的C語言程式,即一個使用OTSU演算法提取影象閾值的函式,輸入引數為一個影象指標,返回分割該影象的最佳閾值。
其中的變數說明:當分割的閾值為t時
w0為背景畫素點佔整幅影象的比例
u0為w0平均灰度
w1為前景畫素點佔整幅影象的比例
u1為w1平均灰度
u為整幅影象的平均灰度
公式:g = w0*pow((u-u0),2) + w1*pow((u-u1),2)
int MyAutoFocusDll::otsuThreshold(IplImage *frame) { const int GrayScale = 256; int width = frame->width; int height = frame->height; int pixelCount[GrayScale]; float pixelPro[GrayScale]; int i, j, pixelSum = width * height, threshold = 0; uchar* data = (uchar*)frame->imageData; //指向畫素資料的指標 for (i = 0; i < GrayScale; i++) { pixelCount[i] = 0; pixelPro[i] = 0; } //統計灰度級中每個畫素在整幅影象中的個數 for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { pixelCount[(int)data[i * width + j]]++; //將畫素值作為計數陣列的下標 } } //計算每個畫素在整幅影象中的比例 float maxPro = 0.0; int kk = 0; for (i = 0; i < GrayScale; i++) { pixelPro[i] = (float)pixelCount[i] / pixelSum; if (pixelPro[i] > maxPro) { maxPro = pixelPro[i]; kk = i; } } //遍歷灰度級[0,255] float w0, w1, u0tmp, u1tmp, u0, u1, u, deltaTmp, deltaMax = 0; for (i = 0; i < GrayScale; i++) // i作為閾值 { w0 = w1 = u0tmp = u1tmp = u0 = u1 = u = deltaTmp = 0; for (j = 0; j < GrayScale; j++) { if (j <= i) //背景部分 { w0 += pixelPro[j]; u0tmp += j * pixelPro[j]; } else //前景部分 { w1 += pixelPro[j]; u1tmp += j * pixelPro[j]; } } u0 = u0tmp / w0; u1 = u1tmp / w1; u = u0tmp + u1tmp; deltaTmp = w0 * pow((u0 - u), 2) + w1 * pow((u1 - u), 2); if (deltaTmp > deltaMax) { deltaMax = deltaTmp; threshold = i; } } return threshold; }
轉自: https://www.cnblogs.com/ranjiewen/p/6385564.html