形态学滤波(2):开运算、闭运算、形态学梯度、顶帽、黑帽
一、開(kāi)運(yùn)算
開(kāi)運(yùn)算,就是先腐蝕后膨脹的過(guò)程
數(shù)學(xué)表達(dá)式:
dst = open(src,element) = dilate(erode(src, element))
開(kāi)運(yùn)算可以用來(lái)消除小物體,在纖細(xì)點(diǎn)處分離物體,并且在平滑較大物體的邊界的同時(shí)不明顯改變其面積。
二、閉運(yùn)算
閉運(yùn)算,就是先膨脹后腐蝕的過(guò)程
數(shù)學(xué)表達(dá)式:
dst = open(src,element) = erode(dilate(src, element))
閉運(yùn)算可以用來(lái)排除小型黑洞(黑色區(qū)域)
三、形態(tài)學(xué)梯度
形態(tài)學(xué)梯度,就是膨脹圖與腐蝕圖之差
數(shù)學(xué)表達(dá)式:
dst = morph-grad(src,element) = dilate(src, element) -erode(src, element)
對(duì)二值圖進(jìn)行這一操作可以將團(tuán)塊的邊緣突出出來(lái),我們可以用形態(tài)學(xué)梯度來(lái)保留物體的邊緣輪廓
四、頂帽
頂帽(禮帽)運(yùn)算,就是原圖像與“開(kāi)運(yùn)算”的結(jié)果圖之差
數(shù)學(xué)表達(dá)式:
dst = tophat(src,element) = src -open(src,element)
因?yàn)殚_(kāi)運(yùn)算帶來(lái)的結(jié)果是放大了裂縫或者局部低亮度的區(qū)域。因此從原圖中減去開(kāi)運(yùn)算后的圖,得到的效果
圖突出了比原圖輪廓周?chē)膮^(qū)域更明亮的區(qū)域,且這一操作與選擇的核的的大小相關(guān)。
頂帽運(yùn)算往往用來(lái)分離比臨近點(diǎn)亮一些的斑塊,在一幅圖像具有大幅的背景,而微小物品比較有規(guī)律的情況下,
可以使用頂帽運(yùn)算進(jìn)行背景提取
五、黑帽
黑帽運(yùn)算,就是“閉運(yùn)算”的結(jié)果圖與原圖像之差
數(shù)學(xué)表達(dá)式:
dst = blackhat(src,element) = close(src,element) -src
黑帽運(yùn)算后的效果圖突出了比原圖輪廓周?chē)膮^(qū)域更暗的區(qū)域,且這一操作和選擇的核的大小相關(guān)
黑帽運(yùn)算用來(lái)分離比臨近點(diǎn)暗一些的斑塊,效果圖有著非常完美的輪廓
六、核心函數(shù):morphologyEx()
1 void morphologyEx( InputArray src, OutputArray dst, 2 int op, InputArray kernel, 3 Point anchor = Point(-1,-1), int iterations = 1, 4 int borderType = BORDER_CONSTANT, 5 const Scalar& borderValue = morphologyDefaultBorderValue() );
1 #include<opencv2/opencv.hpp>
2 #include<iostream>
3
4 using namespace std;
5 using namespace cv;
6
7 Mat g_srcImage, g_dstImage;
8 int g_nElementShap = MORPH_RECT; //元素結(jié)構(gòu)的形狀
9
10 //變量接收的TrackBar位置參數(shù)
11 int g_nMaxIterationNum = 10;
12 int g_nOpenCloseNum = 0;
13 int g_nErodeDilateNum = 0;
14 int g_nTopBlackHatNum = 0;
15
16 static void on_OpenClose(int, void *); //回調(diào)函數(shù)
17 static void on_ErodeDilate(int, void *);
18 static void on_TopBlackHat(int, void *);
19
20
21 int main()
22 {
23 //載入原圖
24 g_srcImage = imread("C:\Users\Administrator\Pictures\Camera Roll\05.jpg");
25 if (!g_srcImage.data) {
26 cout << "圖片載入失敗!" << endl;
27 return false;
28 }
29
30 //顯示原始圖
31 namedWindow("【原始圖】");
32 imshow("【原始圖】", g_srcImage);
33
34 //創(chuàng)建三個(gè)窗口
35 namedWindow("【開(kāi)運(yùn)算/閉運(yùn)算】", 1);
36 namedWindow("【腐蝕/膨脹】", 1);
37 namedWindow("【頂帽/黑帽】", 1);
38
39 //分別為三個(gè)窗口創(chuàng)建滾動(dòng)條
40 createTrackbar("迭代值", "【開(kāi)運(yùn)算/閉運(yùn)算】", &g_nOpenCloseNum, g_nMaxIterationNum * 2 + 1, on_OpenClose);
41 createTrackbar("迭代值", "【腐蝕/膨脹】", &g_nErodeDilateNum, g_nMaxIterationNum * 2 + 1, on_ErodeDilate);
42 createTrackbar("迭代值", "【頂帽/黑帽】", &g_nTopBlackHatNum, g_nMaxIterationNum * 2 + 1, on_TopBlackHat);
43
44 //輪詢(xún)獲取按鍵信息
45 while (1)
46 {
47 int c;
48
49 //執(zhí)行回調(diào)函數(shù)
50 on_OpenClose(g_nOpenCloseNum, 0);
51 on_ErodeDilate(g_nErodeDilateNum, 0);
52 on_TopBlackHat(g_nTopBlackHatNum, 0);
53
54 //獲取按鍵
55 c = waitKey(0);
56
57 //按下鍵盤(pán)Q或者ESC,程序退出
58 if (c == 'q' || c == 27)
59 break;
60 //按下鍵盤(pán)按鍵1,使用橢圓(Elliptic)結(jié)構(gòu)元素MORPH_ELLIPSE
61 if (c == 'a')
62 g_nElementShap = MORPH_ELLIPSE;
63 //按下鍵盤(pán)按鍵2,使用矩形(Rectangle)結(jié)構(gòu)元素MORPH_RECT
64 if (c == 'b')
65 g_nElementShap = MORPH_RECT;
66 //按下鍵盤(pán)按鍵3,使用十字形(Cross-shaped)結(jié)構(gòu)元素MORPH_CROSS
67 if (c == 'c')
68 g_nElementShap = MORPH_CROSS;
69 //按下鍵盤(pán)按鍵space,在矩形、橢圓、十字形結(jié)構(gòu)元素中循環(huán)
70 if (c == ' ')
71 g_nElementShap = (g_nElementShap + 1) % 3;
72 }
73 return 0;
74 }
75 static void on_OpenClose(int, void *) {
76 //偏移量的定義
77 int offset = g_nOpenCloseNum - g_nMaxIterationNum; //偏移量
78 int Absolute_offset = offset > 0 ? offset : -offset; //偏移量的絕對(duì)值
79 //自定義核
80 Mat element = getStructuringElement(g_nElementShap, Size(Absolute_offset * 2 + 1, Absolute_offset * 2 + 1), Point(Absolute_offset, Absolute_offset));
81
82 //進(jìn)行操作
83 if (offset < 0)
84 morphologyEx(g_srcImage, g_dstImage, MORPH_OPEN, element);
85 else
86 morphologyEx(g_srcImage, g_dstImage, MORPH_CLOSE, element);
87
88 //顯示圖像
89 imshow("【開(kāi)運(yùn)算/閉運(yùn)算】", g_dstImage);
90 }
91
92 static void on_ErodeDilate(int, void *) {
93 int offset = g_nOpenCloseNum - g_nMaxIterationNum; //偏移量
94 int Absolute_offset = offset > 0 ? offset : -offset; //偏移量的絕對(duì)值
95 //自定義核
96 Mat element = getStructuringElement(g_nElementShap, Size(Absolute_offset * 2 + 1, Absolute_offset * 2 + 1), Point(Absolute_offset, Absolute_offset));
97
98 //進(jìn)行操作
99 if (offset < 0)
100 erode(g_srcImage, g_dstImage, element);
101 else
102 dilate(g_srcImage, g_dstImage, element);
103
104 //顯示圖像
105 imshow("【腐蝕/膨脹】", g_dstImage);
106 }
107
108 static void on_TopBlackHat(int, void *) {
109 int offset = g_nOpenCloseNum - g_nMaxIterationNum; //偏移量
110 int Absolute_offset = offset > 0 ? offset : -offset; //偏移量的絕對(duì)值
111 //自定義核
112 Mat element = getStructuringElement(g_nElementShap, Size(Absolute_offset * 2 + 1, Absolute_offset * 2 + 1), Point(Absolute_offset, Absolute_offset));
113
114 //進(jìn)行操作
115 if (offset < 0)
116 morphologyEx(g_srcImage, g_dstImage, MORPH_TOPHAT, element);
117 else
118 morphologyEx(g_srcImage, g_dstImage, MORPH_BLACKHAT, element);
119
120 //顯示圖像
121 imshow("【頂帽/黑帽】", g_dstImage);
122 }
123
總結(jié)
以上是生活随笔為你收集整理的形态学滤波(2):开运算、闭运算、形态学梯度、顶帽、黑帽的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 体温计腋下要量多久
- 下一篇: 怎么创建具有真实纹理的CG场景岩石?