閾值T:按照個人理解就是通常咱們用攝像頭拍攝照片或者視頻咱們一般把拍攝的照片或者視html
頻轉化爲RGB565圖像,而後經過RGB的轉化算出像素經過設置一個閾值像素,大於算法
這個值咱們把它設置爲白色,小於這個值得咱們把它設置爲黑色。這個就是圖像二值ide
化。post
圖像二值化的原理spa
圖像的二值化處理就是將圖像上的點的灰度置爲0或255,也就是將整個圖像視頻
呈現出明顯的黑白效果。即將256個亮度等級的灰度圖像經過適當的閾值選取而獲htm
得仍然能夠反映圖像總體和局部特徵的二值化圖像。在數字圖像處理中,二值圖像blog
佔有很是重要的地位,特別是在實用的圖像處理中,以二值圖像處理實現而構成的get
系統是不少的,要進行二值圖像的處理與分析,首先要把灰度圖像二值化,獲得二it
值化圖像,這樣子有利於在對圖像作進一步處理時,圖像的集合性質只與像素值爲
0或255的點的位置有關,再也不涉及像素的多級值,使處理變得簡單,並且數據的
處理和壓縮量小。爲了獲得理想的二值圖像,通常採用封閉、連通的邊界定義不交
疊的區域。全部灰度大於或等於閾值的像素被斷定爲屬於特定物體,其灰度值爲255
表示,則這些像素點被排除在物體區域之外,灰度值爲0,表示背景或者例外的物體
區域。若是某特定物體在內部有均勻一致的灰度值,而且其處在一個具備其餘等級灰
度值的均勻背景下,使用閾值法就能夠獲得比較的分割效果。若是物體同背景的差異
表現不在灰度值上(好比紋理不一樣),以將這個差異特徵轉換爲灰度的差異,而後利用
閾值選取技術來分割該圖像。動態調節閾值實現圖像的二值化可動態觀察其分割圖像
的具體結果。
圖像二值化的方法
(1)全局二值化
一幅圖像包括目標物體、背景還有噪聲,要想從多值的數字圖像中直接提取出目標物體,
最經常使用的方法就是設定一個全局的閾值T,用T將圖像的數據分紅兩部
分:大於T的像素羣和小於T的像素羣。將大於T的像素羣的像素值設定爲白色(或者
黑色),小於T的像素羣的像素值設定爲黑色(或者白色)。
(2)局部二值化
全局二值化,在表現圖像細節方面存在很大缺陷。爲了彌補這個缺陷,出現了局部
二值化方法。
局部二值化的方法就是按照必定的規則將整幅圖像劃分爲N個窗口,對這N個窗口中
的每個窗口再按照一個統一的閾值T將該窗口內的像素劃分爲兩部分,進行二值
化處理。
(3)局部自適應二值化
局部二值化也有一個缺陷。這個缺陷存在於那個統一閾值的選定。這個閾值是沒有
通過合理的運算得來,通常是取該窗口的平局值。這就致使在每個窗口內仍然出
現的是全局二值化的缺陷。爲了解決這個問題,就出現了局部自適應二值化方法。
局部自適應二值化,該方法就是在局部二值化的基礎之上,將閾值的設定更加合理
化。該方法的閾值是經過對該窗口像素的平均值E,像素之間的差平方P,像素之間
的均方根值Q等各類局部特徵,設定一個參數方程進行閾值的計算,例如:T=a*E
+b*P+c*Q,其中a,b,c是自由參數。這樣得出來的二值化圖像就更能表現出二值化
圖像中的細節。
此篇介紹兩種全局閾值方法,下篇介紹自適應方法。
1:經典算法OTSU
OTSU的中心思想是閾值T應使目標與背景兩類的類間方差最大。
//用類間方差最大思想計算閾值
int Threshold(int *hist) //compute the threshold
{
float u0, u1;
float w0, w1;
int count0;
int t, maxT;
float devi, maxDevi = 0; //方差及最大方差
int i;
int sum = 0;
for (i = 0; i < 256; i++)
{
sum = sum + hist[i];
}
for (t = 0; t < 255; t++)
{
u0 = 0; count0 = 0;
//閾值爲t時,c0組的均值及產生的機率
for (i = 0; i <= t; i++)
{
u0 += i * hist[i]; count0 += hist[i];
}
u0 = u0 / count0; w0 = (float)count0/sum;
//閾值爲t時,c1組的均值及產生的機率
u1 = 0;
for (i = t + 1; i < 256; i++)
{
u1 += i * hist[i];
}
u1 = u1 / (sum - count0); w1 = 1 - w0;
//兩類間方差
devi = w0 * w1 * (u1 - u0) * (u1 - u0);
//記錄最大的方差及最佳位置
if (devi > maxDevi)
{
maxDevi = devi;
maxT = t;
}
}
return maxT;
}
//二值化處理
void OTSU(IplImage *src, IplImage *dst)
{
int i = 0, j = 0;
int wide = src->widthStep;
int high = src->height;
int hist[256] = {0};
int t;
unsigned char *p, *q;
for (j = 0; j < high; j ++)
{
p = (unsigned char *)(src->imageData + j * wide);
for (i = 0; i < wide; i++)
{
hist[p[i]]++; //統計直方圖
}
}
t = Threshold(hist);
for (j = 0; j < high; j ++)
{
q = (unsigned char *)(dst->imageData + j * wide);
p = (unsigned char *)(src->imageData + j * wide);
for (i = 0; i < wide; i++)
{
q[i] = p[i] >= t ? 255 : 0;
}
}
}
2:另一個Kittler算法,是一種快速的全局閾值法。它的效果不比OTSU差多少,但速度快好多倍,若是能夠應用在圖像質量不錯的環境。
它的中心思想是,計算整幅圖像的梯度灰度的平均值,以此平均值作爲閾值。
//kittler算法
for (i=1;i<high-1;i++)
{
plineadd=src->imageData+i*wide;
pNextLine=src->imageData+(i+1)*wide;
pPreLine=src->imageData+(i-1)*wide;
for(j=1;j<wide-1;j++)
{
//求水平或垂直方向的最大梯度
Grads=MAX(abs((uchar)pPreLine[j]-(uchar)pNextLine[j]),abs((uchar)plineadd[j-1]-(uchar)plineadd[j+1])); //max(xGrads,yGrads)
sumGrads += Grads;
//梯度與當前點灰度的積
sumGrayGrads += Grads*((uchar)plineadd[j]);
}
}
threshold=sumGrayGrads/sumGrads;
// printf("%d\n",threshold);
for(i=0;i<high;i++)
{
plineadd=src->imageData+i*wide;
pTempLine=kittler->imageData+i*wide;
for(j=0;j<wide;j++)
{
pTempLine[j]=(uchar)plineadd[j]>threshold?255:0;
}
}