在圖像閾值化操作中,更關注的是從二值化圖像中,分離目標區域和背景區域,但是僅僅通過設定固定閾值很難達到理想的分割效果。而自適應閾值,則是根據像素的鄰域塊的像素值分布來確定該像素位置上的二值化閾值。這樣做的好處:
1. 每個像素位置處的二值化閾值不是固定不變的,而是由其周圍鄰域像素的分布來決定的。
2. 亮度較高的圖像區域的二值化閾值通常會較高,而亮度低的圖像區域的二值化閾值則會相適應的變小。
3. 不同亮度、對比度、紋理的局部圖像區域將會擁有相對應的局部二值化閾值。
函數原型
1. void adaptiveThreshold(InputArray src, OutputArray dst, 2. double maxValue, int adaptiveMethod, 3. int thresholdType, int bolckSize, double C)
參數說明
參數1:InputArray類型的src,輸入圖像,填單通道,單8位浮點類型Mat即可。
參數2:函數運算后的結果存放在這。即為輸出圖像(與輸入圖像同樣的尺寸和類型)。
參數3:預設滿足條件的最大值。
參數4:指定自適應閾值算法。可選擇ADAPTIVE_THRESH_MEAN_C 或 ADAPTIVE_THRESH_GAUSSIAN_C兩種。(具體見下面的解釋)。
參數5:指定閾值類型。可選擇THRESH_BINARY或者THRESH_BINARY_INV兩種。(即二進制閾值或反二進制閾值)。
參數6:表示鄰域塊大小,用來計算區域閾值,一般選擇為3、5、7......等。
參數7:參數C表示與算法有關的參數,它是一個從均值或加權均值提取的常數,可以是負數。(具體見下面的解釋)。
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ADAPTIVE_THRESH_MEAN_C,為局部鄰域塊的平均值,該算法是先求出塊中的均值,再減去常數C。
ADAPTIVE_THRESH_GAUSSIAN_C,為局部鄰域塊的高斯加權和。該算法是在區域中(x, y)周圍的像素根據高斯函數按照他們離中心點的距離進行加權計算,再減去常數C。
舉個例子:如果使用平均值方法,平均值mean為190,差值delta(即常數C)為30。那么灰度小於160的像素為0,大於等於160的像素為255。如下圖:
如果是反向二值化,如下圖:
delta(常數C)選擇負值也是可以的。
代碼演示
/* 自適應閾值:adaptiveThreshold()函數 */ #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <iostream> using namespace std; using namespace cv; int main() { //------------【1】讀取源圖像並檢查圖像是否讀取成功------------ Mat srcImage = imread("D:\\OutPutResult\\ImageTest\\build.jpg"); if (!srcImage.data) { cout << "讀取圖片錯誤,請重新輸入正確路徑!\n"; system("pause"); return -1; } imshow("【源圖像】", srcImage); //------------【2】灰度轉換------------ Mat srcGray; cvtColor(srcImage, srcGray, CV_RGB2GRAY); imshow("【灰度圖】", srcGray); //------------【3】初始化相關變量--------------- Mat dstImage; //初始化自適應閾值參數 const int maxVal = 255; int blockSize = 3; //取值3、5、7....等 int constValue = 10; int adaptiveMethod = 0; int thresholdType = 1; /* 自適應閾值算法 0:ADAPTIVE_THRESH_MEAN_C 1:ADAPTIVE_THRESH_GAUSSIAN_C -------------------------------------- 閾值類型 0:THRESH_BINARY 1:THRESH_BINARY_INV */ //---------------【4】圖像自適應閾值操作------------------------- adaptiveThreshold(srcGray, dstImage, maxVal, adaptiveMethod, thresholdType, blockSize, constValue); imshow("【自適應閾值】", dstImage); waitKey(0); return 0; }
顯示結果
可以發現自適應閾值能很好的觀測到邊緣信息。閾值的選取是算法自動完成的,很方便。
濾波處理
另外,做不做濾波處理等對圖像分割影響也比較大。
1. adaptiveThreshold分割
Mat img=imread("D:/ImageTest/sudoku.png",CV_LOAD_IMAGE_COLOR); Mat dst1; Mat dst2; Mat dst3; cv::cvtColor(img,img,COLOR_RGB2GRAY);//進行,灰度處理 medianBlur(img,img,5);//中值濾波 threshold(img,dst1, 127, 255, THRESH_BINARY);//閾值分割 adaptiveThreshold(img,dst2,255,ADAPTIVE_THRESH_MEAN_C,THRESH_BINARY,11,2);//自動閾值分割,鄰域均值 adaptiveThreshold(img,dst3,255,ADAPTIVE_THRESH_GAUSSIAN_C,THRESH_BINARY,11,2);//自動閾值分割,高斯鄰域 //ADAPTIVE_THRESH_MEAN_C : threshold value is the mean of neighbourhood area //ADAPTIVE_THRESH_GAUSSIAN_C : threshold value is the weighted sum of neighbourhood values where weights are a gaussian window. imshow("dst1", dst1); imshow("dst2", dst2); imshow("dst3", dst3); imshow("img", img); waitKey(0);
效果對比,很明顯加入鄰域權重后處理更理想:
2. 加入濾波處理的最大類間方差分割
Mat img=imread("D:/ImageTest/pic2.png",CV_LOAD_IMAGE_COLOR); Mat dst1; Mat dst2; Mat dst3; cv::cvtColor(img,img,COLOR_RGB2GRAY);//進行,灰度處理 // medianBlur(img,img,5); threshold(img,dst1, 127, 255, THRESH_BINARY); threshold(img,dst2,0, 255, THRESH_OTSU);//最大類間方差法分割 Otsu algorithm to choose the optimal threshold value Mat img2=img.clone(); GaussianBlur(img2,img2,Size(5,5),0);//高斯濾波去除小噪點 threshold(img2,dst3, 0, 255, THRESH_OTSU); imshow("BINARY dst1", dst1); imshow("OTSU dst2", dst2); imshow("GaussianBlur OTSU dst3", dst3); imshow("original img", img); waitKey(0);
效果如下,顯然不濾波和濾波差別明顯:
參考文章:https://blog.csdn.net/sinat_36264666/article/details/77586964
https://blog.csdn.net/abcvincent/article/details/78822191