OpenCV數(shù)字圖像處理基于C++之圖像形態(tài)學(xué)處理詳解
1、圖像腐蝕
? 原理:腐蝕用來收縮或細化二值圖像中的前景,借此實現(xiàn)去噪聲、元素分割等功能。和所有形態(tài)學(xué)濾波器一樣,腐蝕和膨脹這兩個濾波器的作用范圍是由結(jié)構(gòu)元素定義的像素集。在某個像素上應(yīng)用結(jié)構(gòu)元素時,結(jié)構(gòu)元素的錨點與該像素對齊,所有與結(jié)構(gòu)元素相交的像素就包含在當(dāng)前集合中。腐蝕就是把當(dāng)前像素替換成所定義像素集合中的最小像素值;膨脹是腐蝕的反運算,它把當(dāng)前像素替換成所定義像素集合中的最大像素值。由于輸入的二值圖像只包含黑色(值為0)和白色(值為255)像素,因此每個像素都會被替換成白色或黑色像素。
? 要形象地理解這兩種運算的作用,可考慮背景(黑色)和前景(白色)的物體。腐蝕時,如果結(jié)構(gòu)元素放到某個像素位置時碰到了背景(即交集中有一個像素是黑色的),那么這個像素就變?yōu)楸尘?膨脹時,如果結(jié)構(gòu)元素放到某個背景像素位置時碰到了前景物體,那么這個像素就被標(biāo)為白色。正因如此,圖像腐蝕后物體尺寸會縮小(形狀被腐蝕),而圖像膨脹后物體會擴大。在腐蝕圖像中,有些面積較小的物體(可看作背景中的“噪聲”像素)會徹底消失。與之類似,膨脹后的物體會變大.而物體中一些“空隙”會被填滿。OpenCV默認使用3×3正方形結(jié)構(gòu)元素。在調(diào)用函數(shù)時,就能得到默認的結(jié)構(gòu)元素。你也可以通過提供一個矩陣來指定結(jié)構(gòu)元素的大小(以及形狀),矩陣中的非零元素將構(gòu)成結(jié)構(gòu)元素。
作用:去除圖像中的某些部分以及會縮小細化目標(biāo)
1.1 CV腐蝕函數(shù)
CV_EXPORTS_W 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 輸入圖像;通道的數(shù)量可以是任意的,但是深度值應(yīng)該是以下之一: CV_8U, CV_16U, CV_16S, CV_32F or CV_64F. dst 和源圖像同樣大小和類型的輸出圖像。 kernel 用于腐蝕的結(jié)構(gòu)元素;如果element=Mat(),是一個3 x 3的矩形結(jié)構(gòu)元素. Kernel 可以通過使用getStructuringElement來創(chuàng)建。 anchor 素中的錨點的位置,默認是值(-1,-1),也就是說錨點在元素的中心位置。 iterations 腐蝕的迭代次數(shù)。 borderType像素外推方法。參見#BorderTypes, BORDER_WRAP不支持。 borderValue 固定邊緣的情況下的邊緣值。 參考 dilate,morphologyEx,getStructuringElement
Mat cv::getStructuringElement( int shape, Size ksize, Point anchor = Point(-1,-1) ) 參數(shù)1:結(jié)構(gòu)元的形狀(0:矩形結(jié)構(gòu)元;1:十字架結(jié)構(gòu)元;2:橢圓結(jié)構(gòu)元); 參數(shù)2:結(jié)構(gòu)元大?。╯ize(m, n)); 參數(shù)3:結(jié)構(gòu)元中心點所在位置(point(x, y))默認為中心點
Mat element = getStructuringElement(0, Size(3, 3)); //構(gòu)造矩形結(jié)構(gòu)元素 Mat image_erosion; erode(image_bw, image_erosion, element, Point(-1, -1), 3); //執(zhí)行腐蝕操作 imshow("image_erosion", image_erosion);
原圖
二值圖
CV腐蝕
1.2 自定義腐蝕函數(shù)
void erode_my(Mat &src,Mat &dst,int size) { for (int i = 0; i < src.rows; ++i) { for (int j = 0; j < src.cols; ++j) { uchar minV = 255; //uchar maxV = 0; //遍歷周圍最小像素值 for (int yi = i - size / 2; yi <= i + size / 2; yi++) { for (int xi = j - size / 2; xi <= j + size / 2; xi++) { if (xi < 0 || xi >= src.cols || yi < 0 || yi >= src.rows) { continue; } minV = (std::min<uchar>)(minV, src.at<uchar>(yi, xi)); //maxV = (std::max<uchar>)(maxV, src.at<uchar>(yi, xi)); } } dst.at<uchar>(i, j) = minV; } } }
自定義腐蝕
1.3 對比
erode_my(image_bw, image_erosion_my,9); 當(dāng)腐蝕結(jié)構(gòu)擴大到9×9時效果基本與cv自帶函數(shù)一致。
2、圖像膨脹
原理:腐蝕用來收縮或細化二值圖像中的前景,借此實現(xiàn)去噪聲、元素分割等功能。腐蝕過程:用結(jié)構(gòu)元來逐個像素掃描被腐蝕圖像,并根據(jù)結(jié)構(gòu)元和被腐蝕圖像的關(guān)系確定腐蝕結(jié)果。
注意,腐蝕操作等形態(tài)學(xué)操作,是逐個像素地來確定值的,每次判定的點都與結(jié)構(gòu)元中心點所對應(yīng),如果結(jié)構(gòu)元完全處于前景圖像中,就將結(jié)構(gòu)元中心點所對應(yīng)的腐蝕結(jié)果圖像中的像素點處理為前景色(如1)。如果結(jié)構(gòu)元不完全處于前景圖像中,就將結(jié)構(gòu)元中心點所對應(yīng)的腐蝕結(jié)果圖像中的像素點處理為背景色(如0)。(結(jié)構(gòu)元也被稱為核)
作用:增大圖像中的目標(biāo),或者填充、連接某些目標(biāo)。
2.1 CV膨脹函數(shù)
CV_EXPORTS_W void dilate( InputArray src, OutputArray dst, InputArray kernel, Point anchor = Point(-1,-1), int iterations = 1, int borderType = BORDER_CONSTANT, const Scalar& borderValue = morphologyDefaultBorderValue() ); src 輸入圖像;通道的數(shù)量可以是任意的,但是深度值應(yīng)該是以下之一:CV_8U, CV_16U, CV_16S, CV_32F or CV_64F. dst 和源圖像同樣大小和類型的輸出圖像。 kernel 膨脹核元素,如果elemenat=Mat(), 是一個3 x 3的矩形核元素,核可以使用getStructuringElement來創(chuàng)建。 anchor 元素中的錨點的位置,默認是值(-1,-1),也就是說錨點在元素的中心位置。 iterations 膨脹的迭代次數(shù)。 borderType 像素外推方法。參見#BorderTypes, BORDER_WRAP不支持。 borderValue 固定邊緣的情況下的邊緣值。 參考:erode,morphologyEx,getStructuringElement
//膨脹 Mat element = getStructuringElement(0, Size(3, 3)); //構(gòu)造矩形結(jié)構(gòu)元素 Mat image_dilate; dilate(image_bw, image_dilate, element, Point(-1, -1), 9); //執(zhí)行膨脹操作 imshow("image_dilate", image_dilate);
二值圖
CV膨脹
2.2 自定義膨脹函數(shù)
void dilate_my(Mat& src, Mat& dst, int size) { for (int i = 0; i < src.rows; ++i) { for (int j = 0; j < src.cols; ++j) { //uchar minV = 255; uchar maxV = 0; //遍歷周圍最大像素值 for (int yi = i - size / 2; yi <= i + size / 2; yi++) { for (int xi = j - size / 2; xi <= j + size / 2; xi++) { if (xi < 0 || xi >= src.cols || yi < 0 || yi >= src.rows) { continue; } //minV = (std::min<uchar>)(minV, src.at<uchar>(yi, xi)); maxV = (std::max<uchar>)(maxV, src.at<uchar>(yi, xi)); } } dst.at<uchar>(i, j) = maxV; } } }
自定義膨脹
2.3 對比
dilate_my(image_bw, image_dilate_my, 9); 當(dāng)膨脹結(jié)構(gòu)擴大到9×9時效果基本與cv自帶函數(shù)一致。
腐蝕圖像相當(dāng)于對其反色圖像膨脹后再取反色;
膨脹圖像相當(dāng)于對其反色圖像腐蝕后再取反色。
3、開運算
原理:先腐蝕,再膨脹。
作用:平滑物體輪廓、斷開狹窄的狹頸、消除細長的突出和物體??梢匀サ魣D像上一些小的對象。(假設(shè)圖像前景色是白色,背景色是黑色)
原圖
3.1 方法一
//先腐蝕后膨脹 Mat open_image; Mat element = getStructuringElement(0, Size(3, 3)); //構(gòu)造矩形結(jié)構(gòu)元素 erode(image_bw, image_erosion, element, Point(-1, -1), 3); //執(zhí)行腐蝕操作 dilate(image_erosion, open_image, element, Point(-1, -1), 3); //執(zhí)行膨脹操作 imshow("open", open_image);
3.2 方法二
morphologyEx(image_bw, open_image, MORPH_OPEN, element); imshow("open2", open_image);
4、閉運算
原理:先膨脹,再腐蝕。
作用:閉運算可以填充小洞,填充小的噪點。
4.1 方法一
Mat close_image; Mat element = getStructuringElement(0, Size(3, 3)); //構(gòu)造矩形結(jié)構(gòu)元素 dilate(image_bw, image_dilate, element, Point(-1, -1), 3); //執(zhí)行膨脹操作 erode(image_dilate, close_image, element, Point(-1, -1), 3); //執(zhí)行腐蝕操作 imshow("close", close_image);
4.2 方法二
morphologyEx(image_bw, close_image, MORPH_CLOSE, element); imshow("close2", close_image);
4.3 morphologyEx函數(shù)介紹
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() ); (1)參數(shù)1:InputArray src 輸入圖像,圖像數(shù)據(jù)類型必須為CV_8U, CV_16U, CV_16S, CV_32F or CV_64F中的一種。 (2)參數(shù)2:OutputArray dst 輸出圖像,數(shù)據(jù)類型與大小和輸入圖像一樣。 (3)參數(shù)3:int op 形態(tài)學(xué)處理的類型: MORPH_ERODE = 0:腐蝕處理 MORPH_DILATE = 1:膨脹處理 MORPH_OPEN = 2:開運算處理 MORPH_CLOSE = 3:閉運算處理 MORPH_GRADIENT = 4:形態(tài)學(xué)梯度 MORPH_TOPHAT = 5:頂帽變換 MORPH_BLACKHAT = 6:黑帽變換 MORPH_HITMISS = 7 :擊中-擊不中變換 (4)參數(shù)4:InputArray kernel結(jié)構(gòu)元矩陣 (5)參數(shù)5:Point anchor = Point(-1,-1) 結(jié)構(gòu)元中心點, 默認值Point(-1,-1), 表示正中心 (6)參數(shù)6:int iterations = 1 腐蝕膨脹處理的次數(shù),默認值為1; 如果是開運算閉運算,次數(shù)表示先腐蝕或者膨脹幾次,再膨脹腐蝕幾次,而不是開運算閉運算幾次: 如開運算且次數(shù)為2:erode -> erode -> dilate -> dilate (7)參數(shù)7:int borderType = BORDER_CONSTANT 圖像邊框插值類型,默認類型為固定值填充 BORDER_CONSTANT = 0:固定值 i 填充:iiiiii | abcdefgh | iiiiiii BORDER_REPLICATE = 1:兩端復(fù)制:aaaaaa | abcdefgh | hhhhhhh BORDER_REFLECT = 2:鏡像復(fù)制:fedcba | abcdefgh | hgfedcb BORDER_WRAP = 3:去除一端的值然后復(fù)制: cdefgh | abcdefgh | abcdefg BORDER_REFLECT_101 = 4:去除一端的值然后鏡像復(fù)制: gfedcb|abcdefgh|gfedcba BORDER_TRANSPARENT = 5:推導(dǎo)賦值 uvwxyz | abcdefgh | ijklmno BORDER_REFLECT101 = BORDER_REFLECT_101: same as BORDER_REFLECT_101 BORDER_DEFAULT = BORDER_REFLECT_101: same as BORDER_REFLECT_101 BORDER_ISOLATED = 16:< do not look outside of ROI (8)參數(shù)8:const Scalar& borderValue = morphologyDefaultBorderValue() 文檔中說明:param borderValue Border value in case of a constant border. The default value has a special meaning.
5、頂帽運算
原理:頂帽(或禮帽)運算是原始圖像減去圖像開運算的結(jié)果。
頂帽運算:原始圖像 — 圖像開運算
作用:得到圖像的噪聲。如下圖所示:
5.1 方法一
//構(gòu)造結(jié)構(gòu)元 Mat kernel = getStructuringElement(0, Size(5, 5)); Mat image_lm; //頂帽變換(禮帽變換) morphologyEx(image_bw, image_lm, 5, kernel); cv::imshow("image_lm", image_lm);
5.2 方法二
Mat image_lm2; //**頂帽運算:原始圖像 — 圖像開運算** //dst=img1-img2;//這兩個減法效果相同 若dst<0,則dst=0 subtract(image_bw,open_image2, image_lm2);//注意:要求被處理圖片尺寸一致 cv::imshow("image_lm2",image_lm2);
Mat image_lm2; absdiff(image_bw, open_image2, image_lm2);//若dst<0,則dst=|dst|>=0 用于檢測兩幅相似圖像的不同點,效果比上面的兩種減法好 cv::imshow("image_lm2", image_lm2);
6、黑帽運算
原理:黑帽運算是圖像閉運算操作減去原始圖像的結(jié)果。
黑帽運算:閉運算 — 原始圖像
作用:得到圖像內(nèi)部的小孔,或者前景色中的小黑點。如下圖所示:
6.1 方法一
//構(gòu)造結(jié)構(gòu)元 Mat kernel = getStructuringElement(0, Size(5, 5)); //底帽變換(黑帽變換) Mat image_hm; morphologyEx(image_bw, image_hm, 6, kernel); cv::imshow("image_hm", image_hm);
6.2 方法二
Mat image_hm2; subtract(image_bw, close_image2, image_hm2);//注意:要求被處理圖片尺寸一致 cv::imshow("image_hm2", image_hm2);
Mat image_hm2; absdiff(image_bw, close_image2, image_hm2);//若dst<0,則dst=|dst|>=0 用于檢測兩幅相似圖像的不同點,效果比上面的兩種減法好 cv::imshow("image_hm2", image_hm2);
7、形態(tài)學(xué)梯度
原理:膨脹圖與腐蝕圖之差;
作用:對二值圖進行這一操作可以得到圖像中白色區(qū)域的邊界,因此可以用形態(tài)學(xué)梯度來保留物體的邊界輪廓。
7.1 方法一
//構(gòu)造結(jié)構(gòu)元 Mat kernel = getStructuringElement(0, Size(5, 5)); Mat image_lm; //形態(tài)學(xué)梯度 morphologyEx(image_bw, image_td, 4, kernel); cv::imshow("image_td", image_td);
7.2 方法二
Mat image_tw2; subtract(image_dilate, image_erosion, image_tw2);//注意:要求被處理圖片尺寸一致 cv::imshow("image_tw2", image_tw2);
Mat image_tw2; absdiff(image_dilate, image_erosion, image_tw2);//若dst<0,則dst=|dst|>=0 用于檢測兩幅相似圖像的不同點,效果比上面的兩種減法好 cv::imshow("image_tw2", image_tw2);
部分參考來自:數(shù)字圖像處理(c++ opencv)–持續(xù)更新 - 知乎 (zhihu.com)
總結(jié)
到此這篇關(guān)于OpenCV數(shù)字圖像處理基于C++之圖像形態(tài)學(xué)處理的文章就介紹到這了,更多相關(guān)OpenCV數(shù)字圖像處理基于C++內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!