2020年8月1日 星期六

OpenCV Threshold(二值化)

為了從影像找出我們想要的特徵,一般會使用二值化(Threshold)先將前景(foreground)與背景(background)初步分離出來,以減少不必要的訊息量(雜訊),底下就來介紹一下OpenCV常用的threshold函式,我自己初分成三種類型。

第一種:基本款的二值化(依據閥值進行分類的二值化)

double cv::threshold(InputArray src,OutputArray dst,double thresh,double maxval,int type)
InputArray src:輸入的影像來源
OutputArray dst:輸出的影像來源
double thresh:判定閥值
double maxval:最大值(當像素值大於或小於判定閥值時,用此參數取代)
int type:設定二值化模式,常見有THRESH_BINARY、THRESH_BINARY_INV、THRESH_TRUNC、THRESH_TOZERO、THRESH_TOZERO_INV五種。
THRESH_BINARY:將大於閥值的灰度值設為最大值,反之設為0
THRESH_BINARY_INV:將大於閥值的灰度值設為0,反之設為最大值
THRESH_TRUNC:將大於閥值的灰度值設為閥值,反之則不變
THRESH_TOZERO:將大於閥值的灰度值不變,反之則設為0
THRESH_TOZERO_INV:將大於閥值的灰度值設為0,反之則不變

第二種:進階版的二值化(依據亮度分佈,自動定義閥值進行分類的二值化)

跟第一種幾乎一樣,差別在於設定的二值化模式不同,可選擇為THRESH_OTSU跟THRESH_TRIANGLE兩種,THRESH_OTSU比較適用在有兩個分峰值情況下使用,而THRESH_TRIANGLE則用在單一峰值比較合適。


第三種:強大版的二值化(依據區域不同,適應不同閥值進行分類的二值化)

void adaptiveThreshold(InputArray src, OutputArray dst,double maxValue,int adaptiveMethod, int thresholdType, int blockSize, double C)
InputArray src:輸入的影像來源
OutputArray dst:輸出的影像來源
double maxval:最大值(當像素值大於或小於判定閥值時,用此參數取代)
int adaptiveMethod:設定自適應模式,有ADAPTIVE_THRESH_MEAN_C(平均法)、ADAPTIVE_THRESH_GAUSSIAN_C(高斯法)兩種。
nt thresholdType:設定二值化模式,即前面提到的二值化五種模式
int blockSize:區塊大小
double C:常數

總結:

上述三種方式,我覺得第一種使用單純但無法用於環境光源變化大的地方、第二種雖然可以自動定義閥值,但使用時若影像亮度分佈沒有明顯的兩個或一個峰值,則效果可能有限,第三種則適應能力較強,處理後的效果還有點像邊緣偵測,也許可用在其他地方上。


現在就來實作一下吧,為了比較好理解基本款二值化操作,我設計了一張圖片,當中分成了五個區域,由左至右亮度值分別為(50、100、150、200、250),讓我們更容易看出不同的差異性。

程式碼如下:
#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main(){

	Mat SrcImg = imread("GradientImg.bmp", CV_LOAD_IMAGE_COLOR);
	Mat GrayImg, BinaryImg, BinaryInvImg, BinaryTruncImg, BinaryToZeroImg, BinaryToZeroInvImg;
	Mat OtsuImg, TriangleImg, AdaptiveThImg;

	cvtColor(SrcImg, GrayImg, CV_BGR2GRAY);
	threshold(GrayImg, BinaryImg, 150, 255, THRESH_BINARY);//將大於閥值的灰度值設為最大值,反之設為0
	threshold(GrayImg, BinaryInvImg, 150, 255, THRESH_BINARY_INV);//將大於閥值的灰度值設為0,反之設為最大值
	threshold(GrayImg, BinaryTruncImg, 190, 255, THRESH_TRUNC);//將大於閥值的灰度值設為閥值,反之則不變
	threshold(GrayImg, BinaryToZeroImg, 150, 255, THRESH_TOZERO);//將大於閥值的灰度值不變,反之則設為0
	threshold(GrayImg, BinaryToZeroInvImg, 150, 255, THRESH_TOZERO_INV);//將大於閥值的灰度值設為0,反之則不變
	threshold(GrayImg, OtsuImg, 0, 255, THRESH_OTSU);//自動設定最佳閥值,適用於有兩個峰值的情況
	threshold(GrayImg, TriangleImg, 250, 255, THRESH_TRIANGLE);//自動設定最佳閥值,適用只有一個峰值的情況
	adaptiveThreshold(GrayImg, AdaptiveThImg, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 5, 1);

	imshow("GradientImg", SrcImg);
	imshow("BinaryImg", BinaryImg);
	imshow("BinaryInvImg", BinaryInvImg);
	imshow("BinaryTruncImg", BinaryTruncImg);
	imshow("BinaryToZeroImg", BinaryToZeroImg);
	imshow("BinaryToZeroInvImg", BinaryToZeroInvImg);
	imshow("OtsuImg", OtsuImg);
	imshow("TriangleImg", TriangleImg);
	imshow("AdaptiveThImg", AdaptiveThImg);

	waitKey(0);
	return 0;
}


GradientImg

BinaryImg

BinaryInvImg

BinaryTruncImg

BinaryToZeroImg

BinaryToZeroInvImg

OtsuImg


TriangleImg

AdaptiveImg










沒有留言:

張貼留言