天天看點

otsu結合OpenCV實作灰階圖像自動門檻值處理

        簡單的說,這種算法假設一副圖像由前景色和背景色組成,通過統計學的方法來選取一個門檻值,使得這個門檻值可以将前景色和背景色盡可能的分開。

或者更準确的說是在某種判據下最優。與數理統計領域的 fisher 線性判别算法其實是等價的。

otsu算法中這個判據就是最大類間方差 (intra-class variance or the variance within the class)。下面就來詳細說說什麼是 intra-class variance。

我們知道一副灰階圖像,可以計算它的顔色平均值,或者更進一步。可以計算出灰階直方圖。

這裡給出一個示例圖檔:

otsu結合OpenCV實作灰階圖像自動門檻值處理

這個圖檔拍攝的是一個條形碼。在這個圖中,前景色就是黑色的條形碼,背景色是其餘部分的灰色。那麼我們可以計算出這個圖像的灰階直方圖。

otsu結合OpenCV實作灰階圖像自動門檻值處理

圖中那個大的峰是背景色的部分,小的峰是前景色。灰階值的均值是 122. 我們稱這個均值為 M。

現在任意選取一個灰階值 t,則可以将這個直方圖分成前後兩部分。我們稱這兩部分分别為 A 和 B。對應的就是前景色和背景色。這兩部分各自的平均值成為 MA 和 MB。 

A 部分裡的像素數占總像素數的比例記作 PA,B部分裡的像素數占總像素數的比例記作 PB。 

Nobuyuki Otsu 給出的類間方差定義為:

otsu結合OpenCV實作灰階圖像自動門檻值處理

那麼這個最佳的門檻值t 就是使得 ICV 最大的那個值。 

對于上面的測試圖像,我們可以周遊 t 的各種取值,計算 ICV。之後可以畫出這樣的ICV 曲線(綠色線條):

otsu結合OpenCV實作灰階圖像自動門檻值處理

可以看出,ICV 取最值的點确實将前景色和背景色分開了。

以上理論部分參考了這篇部落格http://blog.csdn.net/liyuanbhu/article/details/49387483

下面是C++結合OpenCV2.x實作的代碼:

int otsu(Mat image)
{
	int width = image.cols;
	int height = image.rows;
	int x = 0, y = 0;
	int pixelCount[256];
	float pixelPro[256];
	int i, j, pixelSum = width * height, threshold = 0;

	uchar* data = (uchar*)image.data;

	//初始化  
	for (i = 0; i < 256; i++)
	{
		pixelCount[i] = 0;
		pixelPro[i] = 0;
	}

	//統計灰階級中每個像素在整幅圖像中的個數  
	for (i = y; i < height; i++)
	{
		for (j = x; j<width;i++)
		{
			pixelCount[data[i * image.step+ j]]++;
		}
	}


	//計算每個像素在整幅圖像中的比例  
	for (i = 0; i < 256; i++)
	{
		pixelPro[i] = (float)(pixelCount[i]) / (float)(pixelSum);
	}

	//經典ostu算法,得到前景和背景的分割  
	//周遊灰階級[0,255],計算出方差最大的灰階值,為最佳門檻值  
	float w0, w1, u0tmp, u1tmp, u0, u1, u, deltaTmp, deltaMax = 0;
	for (i = 0; i < 256; i++)
	{
		w0 = w1 = u0tmp = u1tmp = u0 = u1 = u = deltaTmp = 0;

		for (j = 0; j < 256; j++)
		{
			if (j <= i) //背景部分  
			{
				//以i為門檻值分類,第一類總的機率  
				w0 += pixelPro[j];
				u0tmp += j * pixelPro[j];
			}
			else       //前景部分  
			{
				//以i為門檻值分類,第二類總的機率  
				w1 += pixelPro[j];
				u1tmp += j * pixelPro[j];
			}
		}

		u0 = u0tmp / w0;        //第一類的平均灰階  
		u1 = u1tmp / w1;        //第二類的平均灰階  
		u = u0tmp + u1tmp;      //整幅圖像的平均灰階  
		//計算類間方差  
		deltaTmp = w0 * (u0 - u)*(u0 - u) + w1 * (u1 - u)*(u1 - u);
		//找出最大類間方差以及對應的門檻值  
		if (deltaTmp > deltaMax)
		{
			deltaMax = deltaTmp;
			threshold = i;
		}
	}
	//傳回最佳門檻值;  
	return threshold;
}
           

利用這個方法計算出的門檻值做了二值化後得到圖像如下:

otsu結合OpenCV實作灰階圖像自動門檻值處理

可以看到效果很好。

Otsu 方法也不是萬能的。當目标與背景的大小比例懸殊時,類間方差準則函數可能呈現雙峰或多峰,此時效果不好。這時就要考慮其他的辦法了。

其實,我們可以仔細觀察 ICV 的計算公式。 

otsu結合OpenCV實作灰階圖像自動門檻值處理

這裡面 PA 和 PB 相當于是個前景色和背景色部分做個權重。目前景色或背景色有一個區域很小時。比如 PA 非常的小。那麼這時計算出來的 t 就會和 B 區域很接近,這時的分割效果就會比較差。我們可以對ICV的公式進行一點小小的改造。

otsu結合OpenCV實作灰階圖像自動門檻值處理

這裡的 α 可以取一個 0-1之間的值。比如上面的例子圖檔,如果我們取 α=0.8 計算出的效果會更好一些。當然這個 α 值就要全憑經驗來定了

繼續閱讀