歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> OpenCV入門教程之六 數學形態學基本操作及其應用

OpenCV入門教程之六 數學形態學基本操作及其應用

日期:2017/3/1 9:45:26   编辑:Linux編程

數學形態學實際上可以理解為一種濾波行為,所以很多地方稱它為形態學濾波。有了個這概念,我們就能更好的理解它。我們濾波中用的濾波器(kernel)在這裡被稱為結構元素,結構元素往往是由一個特殊的形狀構成,如:線條、矩形、圓、菱形等。我們把結構元素的中心(Anchor Point)與圖像上像素點對齊,然後結構元素覆蓋的領域像素就是我們要分析的像素,我們定義一種操作就形成了一種形態學運算。

我們在這裡不解釋形態學操作的算法原理及它們的意義,有興趣的可以參見相關數字圖像處理方面的教材,或關注本博客,博主打算在OpenCV系列寫完後,開始寫圖像處理方面算法系列的文章。

2 3 void erode(InputArray src, OutputArray dst, InputArray kernel, Point anchor=Point(-1,-1), int iterations=1, int borderType=BORDER_CONSTANT, const Scalar& borderValue=morphologyDefaultBorderValue());

src:輸入圖像,很多場合下我們使用的是二值圖像,當然灰度圖像也可以。

dst:輸出圖像,格式和輸入圖像一致。

kernel:定義的結構元素。

anchor:結構元素的中心,如果是默認參數(-1,-1),程序會自動將其設置為結構元素的中心。

iterations:迭代次數,我們可以選擇對圖像進行多次形態學運算。

後面兩個參數是邊界類型,由於要處理領域問題,所以圖像需要擴充邊界。一般情況下使用默認即可。

膨脹運算:dilate

膨脹跟腐蝕的參數完全一致,就不過多的說明了。這兩個形態學操作是最基本的兩個操作。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 int main() { Mat image=imread("../cat.png"); // 彩色轉灰度 cvtColor(image,image,CV_BGR2GRAY); // 阈值化 threshold(image,image,255*(0.5),255,THRESH_BINARY); // 形態學操作 // 如果把結構元素設置為Mat(),則將用默認的3*3的矩形結構元素 Mat eroded; erode(image,eroded,Mat()); Mat dilated; dilate(image,dilated,Mat()); return 0; }

下面要介紹的兩個形態學操作,在實際應用中要比上面兩個更加廣泛,但實際上它們是上面兩種操作的一個組合式的操作。

開運算與閉運算

這兩個運算都是使用函數morphologyEx來實現的,這個函數的接口如下:

1 2 void morphologyEx(InputArray src, OutputArray dst, int op, InputArray kernel, Point anchor=Point(-1,-1), int iterations=1, int borderType=BORDER_CONSTANT, const Scalar& borderValue=morphologyDefaultBorderValue());

函數的大部分參數都與上面介紹的erode函數參數是一樣的,這裡面的op是我們要進行的形態學的類型:

MORPH_OPEN:對圖像進行開運算。

MORPH_CLOSE:對圖像進行閉運算。

下面我們還是以小貓圖像為例顯示一下對二值圖像進行開運算和閉��算後得到的結果。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 int main() { Mat image=imread("../cat.png"); // 彩色轉灰度 cvtColor(image,image,CV_BGR2GRAY); // 阈值化 threshold(image,image,255*(0.5),255,THRESH_BINARY); // 定義結構元素 Mat se(5,5,CV_8U,Scalar(1)); Mat closed; morphologyEx(image,closed,MORPH_CLOSE,se); Mat opened; morphologyEx(image,opened,MORPH_OPEN,se); return 0; }

從圖片中我們可以得出結論:

閉運算可以填充圖像中的孔洞,連接一些缺口;開運算可以去除圖像中一些較小的結構。前提是這些孔洞或碎片要與進行運算的結構元素尺度相當。

二、用形態學操作來檢測邊緣和角點

其實用形態學來檢測邊緣的原理非常簡單,我們打開源碼看它是怎麼操作的:

1 2 3 4 5 case CV_MOP_GRADIENT: erode( src, temp, kernel, anchor, iterations, borderType, borderValue ); dilate( src, dst, kernel, anchor, iterations, borderType, borderValue ); dst -= temp; break;

可以看出來,它是對圖像先做了一個腐蝕,再做了一次膨脹,然後將兩次的結果相減即可。

1 2 3 4 5 6 7 8 9 10 11 12 13 int main() { Mat image=imread("../cat.png"); // 彩色轉灰度 cvtColor(image,image,CV_BGR2GRAY); Mat catEdge; morphologyEx(image,catEdge,MORPH_GRADIENT,Mat()); // 阈值化 threshold(catEdge,catEdge,40,255,THRESH_BINARY); namedWindow("catEdge");imshow("catEdge",catEdge); waitKey(); return 0; }

下面我們來實現用形態學操作來檢測角點。

首先我們需要定義幾個特殊的結構元素,我們這裡都用Mat來定義,並像素式的賦值,你可以選擇OpenCV裡的getStructElement來更快的實現。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 // 定義結構元素 Mat cross(5,5,CV_8U,Scalar(0)); Mat diamond(5,5,CV_8U,Scalar(1)); Mat square(5,5,CV_8U,Scalar(1)); Mat x(5,5,CV_8U,Scalar(0)); for(int i=0;i<5;i++) { cross.at<uchar>(2,i)=1; cross.at<uchar>(i,2)=1; } diamond.at<uchar>(0,0)=0; diamond.at<uchar>(0,1)=0; diamond.at<uchar>(1,0)=0; diamond.at<uchar>(4,4)=0; diamond.at<uchar>(3,4)=0; diamond.at<uchar>(4,3)=0; diamond.at<uchar>(4,0)=0; diamond.at<uchar>(4,1)=0; diamond.at<uchar>(3,0)=0; diamond.at<uchar>(0,4)=0; diamond.at<uchar>(0,3)=0; diamond.at<uchar>(1,4)=0; for(int i=0;i<5;i++){ x.at<uchar>(i,i)=1; x.at<uchar>(4-i,i)=1; }

第一個為一個十字型的結構元素,第二個為菱形,第三個是矩形,第四個是一個“X”

型。

然後我們按下面的順序對一幅圖像進行操作,並對最後的結果進行阈值化。

1 2 3 4 5 6 7 Mat result; dilate(image,result,cross); erode(result,result,diamond); Mat result2; dilate(image,result2,x); erode(result2,result2,square); absdiff(result2,result,result);

經過上面步驟,我們得到了一張二值圖像,顯示了圖像的一些角點的位置。

為了更形象的說明,我們將上面的這些點在原彩色圖像上標出來:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 // 標記角點 void drawOnImage(const Mat& binary,Mat& image) { for(int i=0;i<binary.rows;i++) { // 獲取行指針 const uchar* data=binary.ptr<uchar>(i); for(int j=0;j<binary.cols;j++) { if(data[j]) //角點圖像上的白點 circle(image,Point(j,i),8,Scalar(0,255,0));// 畫圈 } } }

Copyright © Linux教程網 All Rights Reserved