圖像的腐蝕與膨脹
一、原理:
⑴ 圖像形態學處理的概念⑵ 二值圖像的邏輯運算
⑶ 膨脹和腐蝕
定義結構元素B為:
1 | 1 |
1 | 0 |
(i-1,j+1) | (i,j+1) |
(i-1,j) | 所求此點(i,j) |
① 膨脹
⑴ 用結構元素B,掃描圖像A的每一個像素
⑵ 用結構元素與其覆蓋的二值圖像做“或”操作
⑶ 如果有一個元素為0,結果圖像的該像素為0。否則為255
② 腐蝕
⑴ 用結構元素B,掃描圖像A的每一個像素
⑵ 用結構元素與其覆蓋的二值圖像做“與”操作
⑶ 如果都為0,結果圖像的該像素為0。否則為255
腐蝕處理的結果是使原來的二值圖像減小一圈。
二、我再加一個輪廓提取,非常簡單的方法:用的是9X9的模板;
(i-1,j+1) | (i,j+1) | (i+1,j+1) |
(i-1,j) | 所求此點(i,j) | (i+1,j) |
(i-1,j-1) | (i,j-1) | (i+1,j_1) |
#include<opencv2/opencv.hpp> #include<iostream> using namespace cv; using namespace std; Mat srcImage, grayImage, binarygray, erosion, dilation, outline; static void g_erosion(int, void*); static void g_dilation(int, void*); static void g_outline(int, void*); static void ShowHelpText(); int main() { system("color 3f"); ShowHelpText(); srcImage = imread("D://vvoo//cell.jpg"); cvtColor(srcImage, grayImage, CV_RGB2GRAY); int threshold; cout << "input threshold: " << endl; cin >> threshold; //二值化 binarygray = Mat::zeros(grayImage.rows, grayImage.cols, grayImage.type()); { for (int i = 0; i <grayImage.rows; i++) { for (int j = 0; j < grayImage.cols; j++) { if (grayImage.data[i*grayImage.step + j] > threshold) { binarygray.data[i*binarygray.step + j] = 255; } else { binarygray.data[i*binarygray.step + j] = 0; } } } } //腐蝕 g_erosion(0, 0); //膨脹 g_dilation(0, 0); //輪廓提取 g_outline(0, 0); imshow("原圖", srcImage); imshow("binarygray", binarygray); waitKey(0); return 0; } static void g_erosion(int, void*) { erosion = Mat::zeros(binarygray.rows, binarygray.cols, binarygray.type()); { for (int i = 1; i < binarygray.rows; i++) { for (int j = 1; j < binarygray.cols; j++) { if (binarygray.data[(i - 1)*binarygray.step + j] + binarygray.data[(i - 1)*binarygray.step + j + 1] + binarygray.data[i*binarygray.step + j + 1] == 0) { erosion.data[i*erosion.step + j] = 0; } else { erosion.data[i*erosion.step + j] = 255; } } } } imshow("erosion_1", erosion); } static void g_dilation(int, void*) { dilation = Mat::zeros(binarygray.rows, binarygray.cols, binarygray.type()); for (int i = 1; i < binarygray.rows; i++) { for (int j = 1; j < binarygray.cols; j++) { if (binarygray.data[(i - 1)*binarygray.step + j] == 0 || binarygray.data[(i - 1)*binarygray.step + j - 1] == 0 || binarygray.data[i*binarygray.step + j + 1] == 0) { dilation.data[i*dilation.step + j] = 0; } else { dilation.data[i*dilation.step + j] = 255; } } } imshow("dilation_1", dilation); } static void g_outline(int, void*) { outline = Mat::zeros(binarygray.rows, binarygray.cols, binarygray.type()); for (int i = 1; i < binarygray.rows; i++) { for (int j = 1; j < binarygray.cols; j++) { if (binarygray.data[i*binarygray.step + j + 1] + binarygray.data[(i - 1)*binarygray.step + j] + binarygray.data[i*binarygray.step + j - 1] + binarygray.data[(i - 1)*binarygray.step + j - 1] + binarygray.data[(i + 1)*binarygray.step + j - 1] + binarygray.data[(i + 1)*binarygray.step + j] + binarygray.data[(i - 1)*binarygray.step + j + 1] + binarygray.data[(i + 1)*binarygray.step + j + 1] == 2040) { outline.data[i*erosion.step + j] = 255; } if (binarygray.data[i*binarygray.step + j + 1] + binarygray.data[(i - 1)*binarygray.step + j] + binarygray.data[i*binarygray.step + j - 1] + binarygray.data[(i - 1)*binarygray.step + j - 1] + binarygray.data[(i + 1)*binarygray.step + j - 1] + binarygray.data[(i + 1)*binarygray.step + j] + binarygray.data[(i - 1)*binarygray.step + j + 1] + binarygray.data[(i + 1)*binarygray.step + j + 1] == 0) { outline.data[i*erosion.step + j] = 255; } } } imshow("outline", outline); } static void ShowHelpText() { cout << "\n\n本程序涉及到:"<<"腐蝕(erosion)、膨脹(dilation)、輪廓提取(outline)。\n\n" << endl; }四、運行結果
五、調用Opencv的erode()函數和dilate()函數實現腐蝕和膨脹功能
1)erode函數,使用像素鄰域內的局部極小運算符來腐蝕一張圖片,從src輸入,由dst輸出。支持就地(in-place)操作。
看一下函數原型:
void erode( InputArray src, OutputArray dst, InputArray kernel, Point anchor=Point(-1,-1), int iterations=1, int borderType=BORDER_CONSTANT, const Scalar& borderValue=http://blog.csdn.net/qq_29540745/article/details/morphologyDefaultBorderValue() );
參數原型
- 第一個參數,InputArray類型的src,輸入圖像,即源圖像,填Mat類的對象即可。圖像通道的數量可以是任意的,但圖像深度應為CV_8U,CV_16U,CV_16S,CV_32F或 CV_64F其中之一。
- 第二個參數,OutputArray類型的dst,即目標圖像,需要和源圖片有一樣的尺寸和類型。
- 第三個參數,InputArray類型的kernel,腐蝕操作的內核。若為NULL時,表示的是使用參考點位於中心3x3的核。我們一般使用函數 getStructuringElement配合這個參數的使用。getStructuringElement函數會返回指定形狀和尺寸的結構元素(內核矩陣)。(具體看上文中淺出部分dilate函數的第三個參數講解部分)
- 第四個參數,Point類型的anchor,錨的位置,其有默認值(-1,-1),表示錨位於單位(element)的中心,我們一般不用管它。
- 第五個參數,int類型的iterations,叠代使用erode()函數的次數,默認值為1。
- 第六個參數,int類型的borderType,用於推斷圖像外部像素的某種邊界模式。註意它有默認值BORDER_DEFAULT。
- 第七個參數,const Scalar&類型的borderValue,當邊界為常數時的邊界值,有默認值morphologyDefaultBorderValue(),一般我們不用去管他。需要用到它時,可以看官方文檔中的createMorphologyFilter()函數得到更詳細的解釋。
同樣的,使用erode函數,一般我們只需要填前面的三個參數,後面的四個參數都有默認值。而且往往結合getStructuringElement一起使用。
2)dilate函數原型
函數原型:
C++: void dilate( InputArray src, OutputArray dst, InputArray kernel, Point anchor=Point(-1,-1), int iterations=1, int borderType=BORDER_CONSTANT, const Scalar& borderValue=http://blog.csdn.net/qq_29540745/article/details/morphologyDefaultBorderValue() );
參數詳解:
- 第一個參數,InputArray類型的src,輸入圖像,即源圖像,填Mat類的對象即可。圖像通道的數量可以是任意的,但圖像深度應為CV_8U,CV_16U,CV_16S,CV_32F或 CV_64F其中之一。
- 第二個參數,OutputArray類型的dst,即目標圖像,需要和源圖片有一樣的尺寸和類型。
- 第三個參數,InputArray類型的kernel,膨脹操作的核。若為NULL時,表示的是使用參考點位於中心3x3的核。
我們一般使用函數 getStructuringElement配合這個參數的使用。getStructuringElement函數會返回指定形狀和尺寸的結構元素(內核矩陣。其中,getStructuringElement函數的第一個參數表示內核的形狀,我們可以選擇如下三種形狀之一:
矩形: MORPH_RECT
- 交叉形: MORPH_CROSS
- 橢圓形: MORPH_ELLIPSE
而getStructuringElement函數的第二和第三個參數分別是內核的尺寸以及錨點的位置。
3)代碼實現
#include<opencv2/opencv.hpp> #include<iostream> using namespace cv; using namespace std; #define WINDOWN_NAME_1 "原圖" #define WINDOWN_NAME_2 "腐蝕圖" #define WINDOWN_NAME_3 "膨脹圖" int main() { Mat srcImage = imread("D://vvoo//cell.jpg"); //獲取自定義核 Mat element = getStructuringElement(MORPH_RECT, Size(15, 15)); Mat out_erosion, out_dilate; //進行膨脹操作 erode(srcImage, out_erosion, element); dilate(srcImage, out_dilate, element); imshow(WINDOWN_NAME_1, srcImage); imshow(WINDOWN_NAME_2, out_erosion); imshow(WINDOWN_NAME_3, out_dilate); waitKey(0); return 0; }
4)運行結果
和自己寫的比較下比較一下,差別比較大,主要是因為結構元素大小的關系,我的是2*2,Opencv是15*15的。
我也是初學者,歡迎糾正!
六、參考資料
1.system("color 3f");//輸出窗口和字體顏色可變化,3代表窗口顏色(綠色),f代表窗口裏字體顏色(白色)
全部顏色為:
2.圖像腐蝕、膨脹、細化基本原理
3. 形態學圖像處理(一): 膨脹與腐蝕
Tags: 程序 元素
文章來源: