形态学滤波(2):开运算、闭运算、形态学梯度、顶帽、黑帽

一、开运算

开运算,就是先腐蚀后膨胀的过程

数学表达式:

  dst = open(src,element) = dilate(erode(src, element))

开运算可以用来消除小物体,在纤细点处分离物体,并且在平滑较大物体的边界的同时不明显改变其面积。

二、闭运算

闭运算,就是先膨胀后腐蚀的过程

数学表达式:

  dst = open(src,element) = erode(dilate(src, element))

闭运算可以用来排除小型黑洞(黑色区域)

三、形态学梯度

 形态学梯度,就是膨胀图与腐蚀图之差

数学表达式:

  dst = morph-grad(src,element) = dilate(src, element) – erode(src, element)

对二值图进行这一操作可以将团块的边缘突出出来,我们可以用形态学梯度来保留物体的边缘轮廓

四、顶帽

顶帽(礼帽)运算,就是原图像与“开运算”的结果图之差

数学表达式:

  dst = tophat(src,element) = src – open(src,element)

因为开运算带来的结果是放大了裂缝或者局部低亮度的区域。因此从原图中减去开运算后的图,得到的效果

图突出了比原图轮廓周围的区域更明亮的区域,且这一操作与选择的核的的大小相关。

顶帽运算往往用来分离比临近点亮一些的斑块,在一幅图像具有大幅的背景,而微小物品比较有规律的情况下,

可以使用顶帽运算进行背景提取

五、黑帽

黑帽运算,就是“闭运算”的结果图与原图像之差

数学表达式:

  dst = blackhat(src,element) = close(src,element) – src 

黑帽运算后的效果图突出了比原图轮廓周围的区域更暗的区域,且这一操作和选择的核的大小相关

黑帽运算用来分离比临近点暗一些的斑块,效果图有着非常完美的轮廓

六、核心函数: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;   //元素结构的形状
  9 
 10 //变量接收的TrackBar位置参数
 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 *);   //回调函数
 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     //创建三个窗口
 35     namedWindow("【开运算/闭运算】", 1);
 36     namedWindow("【腐蚀/膨胀】", 1);
 37     namedWindow("【顶帽/黑帽】", 1);
 38 
 39     //分别为三个窗口创建滚动条
 40     createTrackbar("迭代值", "【开运算/闭运算】", &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     //轮询获取按键信息
 45     while (1)
 46     {
 47         int c;
 48 
 49         //执行回调函数
 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         //按下键盘Q或者ESC,程序退出
 58         if (c == 'q' || c == 27)
 59             break;
 60         //按下键盘按键1,使用椭圆(Elliptic)结构元素MORPH_ELLIPSE
 61         if (c == 'a')
 62             g_nElementShap = MORPH_ELLIPSE;
 63         //按下键盘按键2,使用矩形(Rectangle)结构元素MORPH_RECT
 64         if (c == 'b')
 65             g_nElementShap = MORPH_RECT;
 66         //按下键盘按键3,使用十字形(Cross-shaped)结构元素MORPH_CROSS
 67         if (c == 'c')
 68             g_nElementShap = MORPH_CROSS;
 69         //按下键盘按键space,在矩形、椭圆、十字形结构元素中循环
 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;  //偏移量的绝对值
 79         //自定义核
 80         Mat element = getStructuringElement(g_nElementShap, Size(Absolute_offset * 2 + 1, Absolute_offset * 2 + 1), Point(Absolute_offset, Absolute_offset));
 81 
 82         //进行操作
 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("【开运算/闭运算】", 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;  //偏移量的绝对值
 95         //自定义核
 96         Mat element = getStructuringElement(g_nElementShap, Size(Absolute_offset * 2 + 1, Absolute_offset * 2 + 1), Point(Absolute_offset, Absolute_offset));
 97 
 98         //进行操作
 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;  //偏移量的绝对值
111         //自定义核
112         Mat element = getStructuringElement(g_nElementShap, Size(Absolute_offset * 2 + 1, Absolute_offset * 2 + 1), Point(Absolute_offset, Absolute_offset));
113 
114         //进行操作
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     

Published by

风君子

独自遨游何稽首 揭天掀地慰生平

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注