这次范例相对比较简单,是涉及到形态学操作的问题,原理也是比较简单,学习起来比较轻松,大家看完这次的范例分析就可以明白到底图像的腐蚀和膨胀是怎么回事了。
简单来讲,形态学操作就是基于形状的一系列图像处理操作。通过将 结构元素 作用于输入图像来产生输出图像。
最基本的形态学操作有二:腐蚀与膨胀(Erosion 与 Dilation)。 他们的运用广泛:
消除噪声
分割(isolate)独立的图像元素,以及连接(join)相邻的元素。
寻找图像中的明显的极大值区域或极小值区域。
通过以下图像,我们简要来讨论一下膨胀与腐蚀操作,膨胀是取像素值高的点,腐蚀相反,是取像素值低的点。
图1、原图
此操作将图像 A 与任意形状的内核 (B),通常为正方形或圆形,进行卷积。
内核 B 有一个可定义的 锚点, 通常定义为内核中心点。
进行膨胀操作时,将内核 B 划过图像,将内核 B 覆盖区域的最大相素值提取,并代替锚点位置的相素。显然,这一最大化操作将会导致图像中的亮区开始”扩展” (因此有了术语膨胀 dilation )。对上图采用膨胀操作我们得到:
图2、膨胀图片
与上面原图比较,可以明显的看到图像字母变粗了,膨胀了。
腐蚀在形态学操作家族里是膨胀操作的孪生姐妹。它提取的是内核覆盖下的相素最小值。
进行腐蚀操作时,将内核 B 划过图像,将内核 B 覆盖区域的最小相素值提取,并代替锚点位置的相素。
以与膨胀相同的图像作为样本,我们使用腐蚀操作。如下图:
图3、腐蚀图片
与上面原图比较,可以明显的看到图像字母变细了,腐蚀了。
现在,我们编写一些代码,在窗口中再加上trackbar控件对图像进行操作,这样可以更直观的看到图像的变化。
#include "stdafx.h" #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/highgui/highgui.hpp" #include <stdlib.h> #include <stdio.h> using namespace cv; /// 全局变量 Mat src, erosion_dst, dilation_dst; int erosion_elem = 0; int erosion_size = 0; int dilation_elem = 0; int dilation_size = 0; int const max_elem = 2; int const max_kernel_size = 21; /** Function Headers */ void Erosion( int, void* ); void Dilation( int, void* ); /** @function main */ int main( int argc, char** argv ) { /// Load 图像 src = imread( "LinuxLogo.jpg" ); if( !src.data ) { return -1; } /// 创建显示窗口 namedWindow( "Erosion Demo", CV_WINDOW_AUTOSIZE ); namedWindow( "Dilation Demo", CV_WINDOW_AUTOSIZE ); cvMoveWindow( "Dilation Demo", src.cols, 0 ); /// 创建腐蚀 Trackbar createTrackbar( "Element:\n 0: Rect \n 1: Cross \n 2: Ellipse", "Erosion Demo", &erosion_elem, max_elem, Erosion ); createTrackbar( "Kernel size:\n 2n +1", "Erosion Demo", &erosion_size, max_kernel_size, Erosion ); /// 创建膨胀 Trackbar createTrackbar( "Element:\n 0: Rect \n 1: Cross \n 2: Ellipse", "Dilation Demo", &dilation_elem, max_elem, Dilation ); createTrackbar( "Kernel size:\n 2n +1", "Dilation Demo", &dilation_size, max_kernel_size, Dilation ); /// Default start Erosion( 0, 0 ); Dilation( 0, 0 ); waitKey(0); return 0; } /** @function Erosion */ void Erosion( int, void* ) { int erosion_type; if( erosion_elem == 0 ){ erosion_type = MORPH_RECT; } else if( erosion_elem == 1 ){ erosion_type = MORPH_CROSS; } else if( erosion_elem == 2) { erosion_type = MORPH_ELLIPSE; } Mat element = getStructuringElement( erosion_type, Size( 2*erosion_size + 1, 2*erosion_size+1 ), Point( erosion_size, erosion_size ) ); /// 腐蚀操作 erode( src, erosion_dst, element ); imshow( "Erosion Demo", erosion_dst ); } /** @function Dilation */ void Dilation( int, void* ) { int dilation_type; if( dilation_elem == 0 ){ dilation_type = MORPH_RECT; } else if( dilation_elem == 1 ){ dilation_type = MORPH_CROSS; } else if( dilation_elem == 2) { dilation_type = MORPH_ELLIPSE; } Mat element = getStructuringElement( dilation_type, Size( 2*dilation_size + 1, 2*dilation_size+1 ), Point( dilation_size, dilation_size ) ); ///膨胀操作 dilate( src, dilation_dst, element ); imshow( "Dilation Demo", dilation_dst ); }
图5、膨胀图片
图6、腐蚀图片
功能:返回一个指定大小和形态的结构元素
结构:
Mat getStructuringElement(int shape, Size ksize, Point anchor=Point(-1,-1))shape :核的类型
CV_SHAPE_CUSTOM :自定义类型
ksize :核的大小
anchor : 锚点 位置。不指定锚点位置,则默认锚点在内核中心位置。
功能:图像膨胀
结构:
void dilate(InputArray src, OutputArray dst, InputArray element, Point anchor=Point(-1,-1), int iterations=1, int borderType=BORDER_CONSTANT, const Scalar& borderValue=morphologyDefaultBorderValue() )src :源图像
函数支持(in-place)模式。膨胀可以重复进行 (iterations) 次. 对彩色图像,每个彩色通道单独处理。
功能:腐蚀图像
结构:
void erode(InputArray src, OutputArray dst, InputArray element, Point anchor=Point(-1,-1), int iterations=1, int borderType=BORDER_CONSTANT, const Scalar& borderValue=morphologyDefaultBorderValue() )src :源图像
函数支持(in-place)模式。膨胀可以重复进行 (iterations) 次. 对彩色图像,每个彩色通道单独处理。
功能:创建trackbar并将它添加到指定的窗口
结构:
int createTrackbar(const string& trackbarname, const string& winname, int* value, int count, TrackbarCallback onChange=0, void* userdata=0)trackbarname :被创建的trackbar名字
功能:获取trackbar的位置,也即是value的位置
结构:
int getTrackbarPos(const string& trackbarname, const string& winname)trackbarname :trackbar的名字
功能:设置trackbar位置,也即是value的位置
结构:
void setTrackbarPos(const string& trackbarname, const string& winname, int pos)trackbarname :trackbar的名字