一、开运算
开运算,就是先腐蚀后膨胀的过程
数学表达式:
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