OpenCV学习(二十) :分水岭算法:watershed()
OpenCV學習(二十) :分水嶺算法:watershed()
參考博客:
OpenCV—分水嶺算法
圖像處理——分水嶺算法
OpenCV學習(7) 分水嶺算法(1)
Opencv分水嶺算法——watershed自動圖像分割用法 -牧野-
分水嶺算法是一種圖像區域分割法,在分割的過程中,它會把跟臨近像素間的相似性作為重要的參考依據,從而將在空間位置上相近并且灰度值相近(求梯度)的像素點互相連接起來構成一個封閉的輪廓。分水嶺算法常用的操作步驟:彩色圖像灰度化,然后再求梯度圖,最后在梯度圖的基礎上進行分水嶺算法,求得分段圖像的邊緣線。
1、watershed()函數
void watershed( InputArray image, // 必須是一個8bit 3通道彩色圖像矩陣序列 InputOutputArray markers // markers必須包含了種子點信息:算法會根據markers傳入的輪廓作為種子(也就是所謂的注水點), //對圖像上其他的像素點根據分水嶺算法規則進行判斷,并對每個像素點的區域歸屬進行劃定, //直到處理完圖像上所有像素點。而區域與區域之間的分界處的值被置為“-1”,以做區分。==markers== 在將圖像傳遞給函數之前,您必須粗略地勾勒出索引為正(>0)的圖像標記中的所需區域。 因此,每個區域都表示為一個或多個具有像素值1,2,3的連接組件,以此類推。 可以使用findcontours()和drawcontours()從二進制掩碼中檢索這些標記。這些標記是未來圖像區域的“種子”。 標記中的所有其他像素,如果它們與輪廓區域的關系未知,應該由算法定義,則應該設置為0。 在函數輸出中,標記中的每個像素被設置為“seed”組件的值,或者在區域之間的邊界處設置為-1。 );2、示例一:手動添加 markers
watershed圖像自動分割的實現步驟:
1)圖像灰度化、濾波、Canny邊緣檢測
2)查找輪廓,并且把輪廓信息按照不同的編號繪制到watershed的第二個入參merkers上,相當于標記注水點。
3)watershed分水嶺運算
4)繪制分割出來的區域,視覺控還可以使用隨機顏色填充,或者跟原始圖像融合以下,以得到更好的顯示效果。
鼠標回調函數:
static void on_Mouse( int event, int x, int y, int flags, void* ) {// 1)處理鼠標不在窗口中的情況if( x < 0 || x >= g_srcImage.cols || y < 0 || y >= g_srcImage.rows )return;// 2)處理鼠標左鍵相關消息if( event == CV_EVENT_LBUTTONUP || !(flags & CV_EVENT_FLAG_LBUTTON) )prevPt = Point(-1,-1);else if( event == CV_EVENT_LBUTTONDOWN )prevPt = Point(x,y);// 3)鼠標左鍵按下并移動,繪制出白色線條else if( event == CV_EVENT_MOUSEMOVE && (flags & CV_EVENT_FLAG_LBUTTON) ){Point pt(x, y); // 當前坐標值if( prevPt.x < 0 )prevPt = pt;line( g_maskImage, prevPt, pt, Scalar::all(200), 5, 8, 0 ); // 掩模圖line( g_srcImage, prevPt, pt, Scalar::all(200), 5, 8, 0 ); //prevPt = pt;imshow(WINDOW_NAME1, g_srcImage);} }結果:
3、示例二:自動添加 markers
int main() {//1、載入原圖并顯示,初始化掩膜和灰度圖Mat image = imread("F:/C++/2. OPENCV 3.1.0/TEST/1.jpg", 1);imshow("Source Image",image);// 2、灰度化,濾波,Canny邊緣檢測Mat imageGray;cvtColor(image,imageGray,CV_RGB2GRAY);//灰度轉換GaussianBlur(imageGray,imageGray,Size(5,5),2); //高斯濾波imshow("Gray Image",imageGray);Canny(imageGray,imageGray,80,150);imshow("Canny Image",imageGray);// 3、查找輪廓vector<vector<Point>> contours;vector<Vec4i> hierarchy;findContours(imageGray,contours,hierarchy,RETR_TREE,CHAIN_APPROX_SIMPLE,Point());Mat imageContours=Mat::zeros(image.size(),CV_8UC1); //輪廓Mat marks(image.size(),CV_32S); //Opencv分水嶺第二個矩陣參數marks=Scalar::all(0);int index = 0;int compCount = 0;for( ; index >= 0; index = hierarchy[index][0], compCount++ ){// 4、對marks進行標記,對不同區域的輪廓進行編號,相當于設置注水點,有多少輪廓,就有多少注水點drawContours(marks, contours, index, Scalar::all(compCount+1), 1, 8, hierarchy); // 每個輪廓的標記點不一樣drawContours(imageContours,contours,index,Scalar(255),1,8,hierarchy);}//我們來看一下傳入的矩陣marks里是什么東西Mat marksShow;convertScaleAbs(marks,marksShow); // 轉換前的 marker 圖imshow("marksBefore",marksShow);imshow("imageContours 輪廓",imageContours);// 5、分水嶺算法watershed(image,marks);// 6、我們再來看一下分水嶺算法之后的矩陣marks里是什么東西Mat afterWatershed;convertScaleAbs(marks,afterWatershed); // 轉換后的 marker 圖imshow("After Watershed",afterWatershed);// 7、對每一個區域進行顏色填充Mat PerspectiveImage=Mat::zeros(image.size(),CV_8UC3);for(int i=0;i<marks.rows;i++){for(int j=0;j<marks.cols;j++){int index=marks.at<int>(i,j);if(marks.at<int>(i,j)==-1){PerspectiveImage.at<Vec3b>(i,j)=Vec3b(255,255,255);}else{PerspectiveImage.at<Vec3b>(i,j) =RandomColor(index);}}}imshow("After ColorFill",PerspectiveImage);//分割并填充顏色的結果跟原始圖像融合Mat wshed;addWeighted(image,0.4,PerspectiveImage,0.6,0,wshed);imshow("AddWeighted Image",wshed);waitKey(0);return 0; } Vec3b RandomColor(int value) //生成隨機顏色函數 {value=value%255; //生成0~255的隨機數RNG rng;int aa=rng.uniform(0,value);int bb=rng.uniform(0,value);int cc=rng.uniform(0,value);return Vec3b(aa,bb,cc); }
3、基于距離的分水嶺算法
使用分水嶺算法進行圖像分割:(一)獲取灰度圖像,二值化圖像,進行形態學操作,消除噪點
??(二)在距離變換前加上一步操作:通過對上面形態學去噪點后的圖像,進行膨脹操作,可以得到大部分都是背景的區域(原黑色不是我們需要的部分是背景)
??(三)使用距離變換distanceTransform獲取確定的前景色
相關知識補充(重點)
??(四)在獲取了背景區域和前景區域(其實前景區域是我們的種子,我們將從這里進行灌水,向四周漲水,但是這個需要在markers中表示)后,這兩個區域中有未重合部分(注1)怎么辦?首先確定這些區域(尋找種子)
?? 開始獲取未知區域unknown(柵欄會創建在這一區域),為下一步獲取種子做準備
?? (五)獲取了這些區域,我們可以獲取種子,這是通過connectedComponents實現,獲取masker標簽,確定的前景區域會在其中顯示為以1開始的數據,這就是我們的種子,會從這里開始漫水
??重點:
??(六)根據未知區域unknown在markers中設置柵欄,并將背景區域加入種子區域,一起漫水
??(七)根據種子開始漫水,讓水漫起來找到最后的漫出點(柵欄邊界),越過這個點后各個山谷中水開始合并。注意watershed會將找到的柵欄在markers中設置為-1
總結
以上是生活随笔為你收集整理的OpenCV学习(二十) :分水岭算法:watershed()的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 网址的bibtex格式
- 下一篇: 使用Hadoop自带的例子pi计算圆周率