1. 低對比度圖像臟污區域檢測
先上圖:


第一張圖如果不是標注結果,我都沒有發現臟污區域在哪里,第二張圖還清晰一些,基本可以看出來圖像靠近左邊緣的位置有偏暗的區域,這就是我們所說的臟污區域了,也是我們要檢測的區域。
標注結果圖:


2. 實現方法介紹
這里介紹兩種實現方法,
第一種是用C++實現參考博文的方法,即利用梯度方法來檢測,具體步驟如下:
- 對圖像進行高斯模糊去噪,梯度計算對噪聲很敏感;
- 調用Sobel函數計算圖像在x,y方向梯度;
- 調用convertScaleAbs函數將x,y梯度圖像像素值限制在0-255;
- 調用addWeight函數將x,y梯度圖像融合;
- 調用threshold函數對融合圖像進行二值化;
- 使用先腐蝕、后膨脹的形態學處理方法對二值圖像進行非臟污區域過濾;
- 調用findContours方法查找臟污區域輪廓。
第二種方法是本人根據提高圖像對比度思路實現的,具體步驟如下:
8. 對圖像進行高斯模糊去噪;
9. 使用局部直方圖均衡化方法來提高圖像對比度;
10. 使用OTSU二值化閾值方法來粗略分割臟污區域;
11. 對二值圖像使用腐蝕的形態學操作過濾掉部分非臟污區域;
12. 調用findContours方法查找臟污區域輪廓。
3. C++源碼實現
1 #include <iostream>
2 #include <opencv2\imgcodecs.hpp>
3 #include <opencv2\core.hpp>
4 #include <opencv2\imgproc.hpp>
5 #include <opencv2\highgui.hpp>
6 #include <vector>
7
8 int main() 9 { 10 using namespace cv; 11
12 std::string strImgFile = "C:\\Temp\\common\\Workspace\\Opencv\\images\\led1.jpg"; 13 Mat mSrc = imread(strImgFile); 14
15 CV_Assert(mSrc.empty() == false); 16
17 Mat mSrc2 = mSrc.clone(); 18
19 CV_Assert(mSrc2.empty() == false); 20
21 Mat mGray; 22 cvtColor(mSrc, mGray, COLOR_BGR2GRAY); 23
24 GaussianBlur(mGray, mGray, Size(5, 5), 1.0); 25 Mat mGray2 = mGray.clone(); 26
27 CV_Assert(mGray.empty() == false); 28 imshow("gray", mGray.clone()); 29
30 //方法1:利用梯度變化檢測缺陷
31 Mat mSobelX, mSobelY; 32 Sobel(mGray, mSobelX, CV_16S, 1, 0, 7); 33 Sobel(mGray, mSobelY, CV_16S, 0, 1, 7); 34 convertScaleAbs(mSobelX, mSobelX); 35 convertScaleAbs(mSobelY, mSobelY); 36
37 Mat mEdge; 38 addWeighted(mSobelX, 1, mSobelY, 1, 0, mEdge); 39 imshow("edge", mEdge); 40
41 Mat mThresh; 42 threshold(mEdge, mThresh, 0, 255, THRESH_BINARY | THRESH_OTSU); 43 imshow("thresh", mThresh); 44
45 Mat kernel1 = getStructuringElement(MORPH_RECT, Size(11, 11)); 46 CV_Assert(kernel1.empty() == false); 47
48 Mat mMorph; 49 morphologyEx(mThresh, mMorph, MORPH_ERODE, kernel1); 50 imshow("erode", mMorph); 51
52 Mat kernel2 = getStructuringElement(MORPH_RECT, Size(5, 5)); 53 morphologyEx(mMorph, mMorph, MORPH_DILATE, kernel2); 54 imshow("dilate", mMorph); 55
56 std::vector<std::vector<Point>> contours; 57 findContours(mMorph, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE); 58
59 for (int i = 0; i < contours.size(); i++) 60 { 61 float area = contourArea(contours[i]); 62 if (area > 200) 63 { 64 drawContours(mSrc, contours, i, Scalar(0, 0, 255)); 65 } 66 } 67
68 imshow("result1", mSrc.clone()); 69
70 //方法2: 利用局部直方圖均衡化方法檢測缺陷
71 Ptr<CLAHE> ptrCLAHE = createCLAHE(20, Size(30, 30)); 72 ptrCLAHE->apply(mGray2, mGray2); 73 imshow("equalizeHist", mGray2); 74
75 Mat mThresh2; 76 threshold(mGray2, mThresh2, 0, 255, THRESH_BINARY_INV | THRESH_OTSU); 77 CV_Assert(mThresh2.empty() == false); 78 imshow("thresh", mThresh2); 79
80 Mat kernel2_1 = getStructuringElement(MORPH_RECT, Size(9, 9)); 81 Mat mMorph2; 82 morphologyEx(mThresh2, mMorph2, MORPH_ERODE, kernel2_1); 83
84 CV_Assert(mMorph2.empty() == false); 85
86 imshow("morph2", mMorph2); 87
88 std::vector<std::vector<Point>> contours2; 89 findContours(mMorph2, contours2, RETR_EXTERNAL, CHAIN_APPROX_NONE); 90
91 for (int i = 0; i < contours2.size(); i++) 92 { 93 float area = contourArea(contours2[i]); 94 if (area > 200) 95 { 96 drawContours(mSrc2, contours2, i, Scalar(0, 0, 255)); 97 } 98 } 99
100 imshow("result2", mSrc2); 101
102 waitKey(0); 103 destroyAllWindows(); 104
105 system("pause"); 106 return 0; 107 }
4.結果
梯度方法檢測結果:


局部直方圖均衡化方法檢測結果:


總結
相對於梯度方法,局部直方圖均衡化方法需要特別注意局部窗口大小參數以及閾限值參數的選擇,本人也是嘗試了多次才達到比較好的效果。再一次體會到傳統圖像處理的痛處,沒有通用的參數適用於所有的應用實例,不同的場景要配置不同的參數才能達到想要的結果。
