opencv自适应二值化的应用
opencv自適應二值化
- 前言
- 一、二值化是什么?
- 二、自適應二值化
- 1.為什么要用自適應二值化
- 2.自適應二值化代碼實現(c++)
前言
最近在工作中,要實現自動繪制ROI的功能,但是在代碼實現的過程中,遇到了不小的問題,現已解決。
一、二值化是什么?
圖像的二值化,就是將圖像上的像素點的灰度值設置為0或255,也就是將整個圖像呈現出明顯的只有黑和白的視覺效果。
二值化是圖像分割的一種最簡單的方法。二值化可以把灰度圖像轉換成二值圖像。把大于某個臨界灰度值的像素灰度設為灰度極大值,把小于這個值的像素灰度設為灰度極小值,從而實現二值化。
根據閾值選取的不同,二值化的算法分為固定閾值和自適應閾值。
二、自適應二值化
1.為什么要用自適應二值化
在處理從一個視頻流中獲取的圖片時,往往因為光線的變化,而導致固定的閾值不適用,這樣就會導致圖片處理的結果大打折扣,現做如下比較:
原圖_1:
在圖中我們可以看到,只有這個水杯我們希望是黑色的,背景應該處理成白色。那么進行如下不同閾值的嘗試。
閾值_100:
閾值_110:
閾值_120:
cvtColor(srcClone, srcClone, CV_BGR2GRAY);threshold(srcClone, srcClone, 120, 255, CV_THRESH_BINARY);cv::imwrite("D:/閾值_120.jpg", srcClone);
還是同樣的環境(拍攝角度改變了,但還是這個水杯),改變亮度,再來看這個水杯:
原圖_2:
閾值_50:
cvtColor(srcClone, srcClone, CV_BGR2GRAY);threshold(srcClone, srcClone, 50, 255, CV_THRESH_BINARY);cv::imwrite("D:/閾值_50.jpg", srcClone);閾值_100:
cvtColor(srcClone, srcClone, CV_BGR2GRAY);threshold(srcClone, srcClone, 100, 255, CV_THRESH_BINARY);cv::imwrite("D:/閾值_100.jpg", srcClone);很明顯可以看到,對于亮度改變的原圖_2,原先的閾值_100已經不能完全適用,如果將閾值提升到110甚至再往上就會出現大面積黑色的結果,這就是要使用自適應二值化的原因,可以明顯降低亮度變化帶來的影響(當然不僅僅用于處理亮度變化)。
接下來看看自適應二值化的結果:
原圖_1的自適應二值化:
原圖_2的自適應二值化:
從以上結果我們可以看出,對于不同亮度的圖片,使用自適應二值化后的結果是相差不大的,但是將兩種不同的二值化結果相比較可得出,當背景沒有過多的影子以及整張圖的亮度沒有明顯變化(比如從左到右變暗)時,自適應二值化后的結果不一定比得過參數調好的固定閾值二值化,這是因為背景光源信息過于簡單(大智若愚),但在處理視頻流信息的時候,背景光源總會發生不可控的變化,我們肯定不能每次都通過人工來調整閾值,這是不符合自動化工藝的,因此就要使用一個比較好的自適應二值化。
再給出一個例子:
自適應二值化結果:
在這里就不浪費篇幅與固定閾值二值化做比較,讀者可自行比較(本人已經試過,效果沒那么好)。
2.自適應二值化代碼實現(c++)
void thresholdIntegral(cv::Mat &inputMat, cv::Mat &outputMat) {// accept only char type matricesCV_Assert(!inputMat.empty());CV_Assert(inputMat.depth() == CV_8U);CV_Assert(inputMat.channels() == 1);CV_Assert(!outputMat.empty());CV_Assert(outputMat.depth() == CV_8U);CV_Assert(outputMat.channels() == 1);// rows -> height -> yint nRows = inputMat.rows;// cols -> width -> xint nCols = inputMat.cols;// create the integral imagecv::Mat sumMat;cv::integral(inputMat, sumMat);CV_Assert(sumMat.depth() == CV_32S);CV_Assert(sizeof(int) == 4);int S = MAX(nRows, nCols)/8;double T = 0.15;// perform thresholdingint s2 = S/2;int x1, y1, x2, y2, count, sum;// CV_Assert(sizeof(int) == 4);int *p_y1, *p_y2;uchar *p_inputMat, *p_outputMat;for( int i = 0; i < nRows; ++i){y1 = i-s2;y2 = i+s2;if (y1 < 0){y1 = 0;}if (y2 >= nRows) {y2 = nRows-1;}p_y1 = sumMat.ptr<int>(y1);p_y2 = sumMat.ptr<int>(y2);p_inputMat = inputMat.ptr<uchar>(i);p_outputMat = outputMat.ptr<uchar>(i);for ( int j = 0; j < nCols; ++j){// set the SxS regionx1 = j-s2;x2 = j+s2;if (x1 < 0) {x1 = 0;}if (x2 >= nCols) {x2 = nCols-1;}count = (x2-x1)*(y2-y1);// I(x,y)=s(x2,y2)-s(x1,y2)-s(x2,y1)+s(x1,x1)sum = p_y2[x2] - p_y1[x2] - p_y2[x1] + p_y1[x1];if ((int)(p_inputMat[j] * count) < (int)(sum*(1.0-T)))p_outputMat[j] = 255;elsep_outputMat[j] = 0;}} } --- 參考自:[添加鏈接描述](https://www.cnblogs.com/polly333/p/7269153.html) 這套算法以W*W為模板的矩形區域的二維平滑值來代替一維加權值,從而拋開了一維平滑的方向性問題,是Wellner 自適應濾波閾值的升級版。 若有人對算法原理感興趣或對源碼中有不理解的部分可移步下一篇博客,其中會根據自己的理解進行詳細介紹。 本文如有問題請積極指出,萬分感謝。總結
以上是生活随笔為你收集整理的opencv自适应二值化的应用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Grid Search 网格搜索 介绍
- 下一篇: endnote引用格式自定义