【opencv入门之八】形态学图像处理(二):开运算、闭运算、形态学梯度、顶帽、黑帽
参考网站:
http://blog.csdn.net/poem_qianmo/article/details/24599073
1、开运算(Opening Operation)
先腐蚀,后膨胀的过程。
开运算可以用来消除小物体、在纤细点处分离物体、平滑较大物体的边界的同时并不明显改变其面积。
2、闭运算(Closing Operation)
先膨胀,后腐蚀的过程。
闭运算能够排除小型黑洞(黑色区域)
3、形态学梯度(MorphologicalGradient)
其为膨胀图与腐蚀图之差。
可以用形态学梯度来保留物体的边缘轮廓。
4、顶帽(Top Hat)
又称“礼帽”运算,其为原图像与 “开运算” 的结果图之差。
开运算的结果,放大了裂缝或者局部低亮度的区域。
所以顶帽的结果,突出了比原图轮廓周围的区域更明亮的区域,且这一操作和选择的核的大小相关。
顶帽运算用来分离比领近点亮一些的斑块。
当一幅图像具有大幅的背景的时候,而微小物品比较有规律的情况下,可以使用顶帽运算进行背景提取 。
5、黑帽(Black Hat)
“闭运算”的结果与原图像之差。
黑帽运算后的效果突出了比原图轮廓周围的区域更暗的区域,这一操作和选择的核的大小相关。
黑帽运算用来分离比领近点暗一些的斑块。
6、morphologyEx函数
void morphologyEx( InputArray src, OutputArray dst, int op, //表示形态学运算的类型 InputArraykernel, //形态学运算的内核,使用getStructuringElement()函数
Pointanchor=Point(-1,-1),
intiterations=1,
intborderType=BORDER_CONSTANT,
constScalar& borderValue=morphologyDefaultBorderValue() );
第三个参数可以选择如下:
-
- MORPH_OPEN:开运算(opening operation)
- MORPH_CLOSE:闭运算(Closing operation)
- MORPH_GRADIENT:形态学梯度(Morphological gradient)
- MORPH_TOPHAT:顶帽(“Top hat”)
- MORPH_BLACKHAT:黑帽(“Black hat”)
7、综合实践
1 //******************************【程序说明】***************************** 2 // 程序名称:形态学图像处理(二):开运算、闭运算、形态学梯度、顶帽、黑帽 3 // opencv版本:2.4.13 4 // 日期:2017/9/21 5 //********************************************************************** 6 7 8 //******************************【头文件包含部分】***************************** 9 // 描述:包含程序所依赖的头文件 10 //***************************************************************************** 11 #include <opencv2/core/core.hpp> 12 #include <opencv2/highgui/highgui.hpp> 13 #include <opencv2/imgproc/imgproc.hpp> 14 //#include <iostream> 15 16 17 //******************************【命名空间声明部分】***************************** 18 // 描述:包含程序所使用的命名空间 19 //***************************************************************************** 20 using namespace std; 21 using namespace cv; 22 23 24 //******************************【全局变量声明部分】***************************** 25 // 描述:全局变量声明 26 //***************************************************************************** 27 Mat g_srcImage, g_dstImage; //原始图、效果图 28 int g_nElementShape = MORPH_RECT; //元素结构的运算 29 30 //变量接收的TrackBar位置参数 31 int g_nMaxIterationNum = 10; 32 int g_nOpenCloseNum = 0; 33 int g_nErodeDilateNum = 0; 34 int g_nTopBlackHatNum = 0; 35 36 37 //******************************【全局函数声明部分】***************************** 38 // 描述:全局函数声明 39 //***************************************************************************** 40 static void on_OpenClose( int, void* ); //回调函数 41 static void on_ErodeDilate ( int, void* ); //回调函数 42 static void on_TopBlackHat( int, void* ); //回调函数 43 static void ShowHelpText(); //帮助文字显示 44 45 46 //******************************【main()部分】***************************** 47 // 描述:控制台应用程序的入口函数,我们的程序从这里开始 48 //***************************************************************************** 49 int main() 50 { 51 //【0】初始化 52 system("color 2F"); 53 ShowHelpText(); 54 55 //【1】读取原图 56 g_srcImage = imread( "1.jpg", 1 ); //工程目录下需要有一张名为1.jpg的素材图 57 if(!g_srcImage.data) { printf("Oh,no,读取srcImage错误!!!!\n"); return false; } 58 59 //【2】显示原图 60 namedWindow("【<0>原图窗口】", 1 ); 61 imshow("【<0>原图窗口】", g_srcImage ); 62 63 //【3】创建三个窗口 64 namedWindow("【<1>开运算/闭运算】", 1); 65 namedWindow("【<2>腐蚀/膨胀】", 1); 66 namedWindow("【<3>顶帽/黑帽】", 1); 67 68 //【4】参数赋值 69 g_nOpenCloseNum = 9; 70 g_nErodeDilateNum = 9; 71 g_nTopBlackHatNum = 2; 72 73 //【5】分别为三个窗口创建轨迹条 74 createTrackbar( "迭代值", "【<1>开运算/闭运算】", &g_nOpenCloseNum, g_nMaxIterationNum*2+1, on_OpenClose ); 75 createTrackbar( "迭代值", "【<2>腐蚀/膨胀】", &g_nErodeDilateNum, g_nMaxIterationNum*2+1, on_ErodeDilate ); 76 createTrackbar( "迭代值", "【<3>顶帽/黑帽】", &g_nTopBlackHatNum, g_nMaxIterationNum*2+1, on_TopBlackHat ); 77 78 //【5】轮询获取按键信息 79 while(1) 80 { 81 int c; 82 83 //【1】执行回调函数 84 on_OpenClose( g_nOpenCloseNum, 0 ); 85 on_ErodeDilate( g_nErodeDilateNum, 0 ); 86 on_TopBlackHat( g_nTopBlackHatNum, 0 ); 87 88 //【2】获取按键 89 c = waitKey(0); 90 91 //【3】按下键盘Q或者ESC,程序退出 92 if( (char)c==\'q\' || (char)c==27 ) 93 break; 94 95 //【4】按下键盘1、2、3或者空格,结构元素矩形、椭圆、十字循环改变 96 if( (char)c == 49 )//键盘按键1,使用椭圆结构元素 97 g_nElementShape = MORPH_ELLIPSE; 98 else if( (char)c == 50 )//键盘按键2,使用矩形结构元素 99 g_nElementShape = MORPH_RECT; 100 else if( (char)c == 51 )//键盘按键3,使用十字结构元素 101 g_nElementShape = MORPH_CROSS; 102 else if( (char)c == \' \' ) 103 g_nElementShape = (g_nElementShape + 1) % 3; 104 105 } 106 107 return 0; 108 } 109 110 111 //******************************【on_OpenClose()部分】***************************** 112 // 描述:【开运算/闭运算】窗口的回调函数 113 //***************************************************************************** 114 static void on_OpenClose( int, void* ) 115 { 116 //【0】偏移量的定义 117 int offset = g_nOpenCloseNum - g_nMaxIterationNum; //偏移量 118 int Absolute_offset = offset > 0 ? offset : -offset; //偏移量绝对值 119 120 //【1】自定义核 121 Mat element = getStructuringElement( g_nElementShape, 122 Size(Absolute_offset*2+1, Absolute_offset*2+1), 123 Point(Absolute_offset,Absolute_offset)); 124 125 //【2】进行操作 126 if(offset < 0) 127 morphologyEx( g_srcImage, g_dstImage, CV_MOP_OPEN, element ); 128 else 129 morphologyEx( g_srcImage, g_dstImage, CV_MOP_CLOSE, element ); 130 131 //【3】显示效果图 132 imshow("【<1>开运算/闭运算】", g_dstImage); 133 } 134 135 136 137 //******************************【on_ErodeDilate()部分】***************************** 138 // 描述:【腐蚀/膨胀】窗口的回调函数 139 //***************************************************************************** 140 static void on_ErodeDilate( int, void* ) 141 { 142 //【0】偏移量的定义 143 int offset = g_nErodeDilateNum - g_nMaxIterationNum; //偏移量 144 int Absolute_offset = offset > 0 ? offset : -offset; //偏移量绝对值 145 146 //【1】自定义核 147 Mat element = getStructuringElement( g_nElementShape, 148 Size(Absolute_offset*2+1, Absolute_offset*2+1), 149 Point(Absolute_offset,Absolute_offset)); 150 151 //【2】进行操作 152 if(offset < 0) 153 erode( g_srcImage, g_dstImage, element ); 154 else 155 dilate( g_srcImage, g_dstImage, element ); 156 157 //【3】显示效果图 158 imshow("【<2>腐蚀/膨胀】", g_dstImage); 159 } 160 161 162 163 //******************************【on_TopBlackHat()部分】***************************** 164 // 描述:【顶帽运算/黑帽运算】窗口的回调函数 165 //***************************************************************************** 166 static void on_TopBlackHat( int, void* ) 167 { 168 //【0】偏移量的定义 169 int offset = g_nTopBlackHatNum - g_nMaxIterationNum; //偏移量 170 int Absolute_offset = offset > 0 ? offset : -offset; //偏移量绝对值 171 172 //【1】自定义核 173 Mat element = getStructuringElement( g_nElementShape, 174 Size(Absolute_offset*2+1, Absolute_offset*2+1), 175 Point(Absolute_offset,Absolute_offset)); 176 177 //【2】进行操作 178 if(offset < 0) 179 morphologyEx( g_srcImage, g_dstImage, MORPH_TOPHAT, element ); 180 else 181 morphologyEx( g_srcImage, g_dstImage, MORPH_BLACKHAT, element ); 182 183 //【3】显示效果图 184 imshow("【<3>顶帽/黑帽】", g_dstImage); 185 } 186 187 188 //******************************【ShowHelpText()部分】***************************** 189 // 描述:输出一些帮助信息 190 //***************************************************************************** 191 static void ShowHelpText() 192 { 193 //输出一些帮助信息 194 printf("\n\n\n\t请调整滚动条观察图像效果!!\n\n"); 195 printf("\n\n\t按键操作说明:\n\n" 196 "\t\t键盘按键【ESC】或者【Q】- 退出程序\n" 197 "\t\t键盘按键【1】- 使用椭圆(Elliptic)结构元素\n" 198 "\t\t键盘按键【2】- 使用矩形(Rectangle )结构元素\n" 199 "\t\t键盘按键【3】- 使用十字型(Cross-shaped)结构元素\n" 200 "\t\t键盘按键【空格SPACE】- 在矩形、椭圆、十字形结构元素中循环\n" 201 "\n\n\t\t\t\t\t\t\t\t by浅墨" 202 ); 203 }