学习OpenCV范例(十一)——图像的腐蚀与膨胀

这次范例相对比较简单,是涉及到形态学操作的问题,原理也是比较简单,学习起来比较轻松,大家看完这次的范例分析就可以明白到底图像的腐蚀和膨胀是怎么回事了。

1、原理

简单来讲,形态学操作就是基于形状的一系列图像处理操作。通过将 结构元素 作用于输入图像来产生输出图像。
最基本的形态学操作有二:腐蚀与膨胀(Erosion 与 Dilation)。 他们的运用广泛:
消除噪声
分割(isolate)独立的图像元素,以及连接(join)相邻的元素。
寻找图像中的明显的极大值区域或极小值区域。
通过以下图像,我们简要来讨论一下膨胀与腐蚀操作,膨胀是取像素值高的点,腐蚀相反,是取像素值低的点。

学习OpenCV范例(十一)——图像的腐蚀与膨胀_第1张图片

                      图1、原图

①、膨胀

此操作将图像 A 与任意形状的内核 (B),通常为正方形或圆形,进行卷积。
内核 B 有一个可定义的 锚点, 通常定义为内核中心点。
进行膨胀操作时,将内核 B 划过图像,将内核 B 覆盖区域的最大相素值提取,并代替锚点位置的相素。显然,这一最大化操作将会导致图像中的亮区开始”扩展” (因此有了术语膨胀 dilation )。对上图采用膨胀操作我们得到:
学习OpenCV范例(十一)——图像的腐蚀与膨胀_第2张图片
                图2、膨胀图片

与上面原图比较,可以明显的看到图像字母变粗了,膨胀了。

②、腐蚀

腐蚀在形态学操作家族里是膨胀操作的孪生姐妹。它提取的是内核覆盖下的相素最小值。
进行腐蚀操作时,将内核 B 划过图像,将内核 B 覆盖区域的最小相素值提取,并代替锚点位置的相素。
以与膨胀相同的图像作为样本,我们使用腐蚀操作。如下图:

学习OpenCV范例(十一)——图像的腐蚀与膨胀_第3张图片

                图3、腐蚀图片

与上面原图比较,可以明显的看到图像字母变细了,腐蚀了。

现在,我们编写一些代码,在窗口中再加上trackbar控件对图像进行操作,这样可以更直观的看到图像的变化。

2、代码实现

#include "stdafx.h"

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include 
#include 

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 );
}

3、运行结果

学习OpenCV范例(十一)——图像的腐蚀与膨胀_第4张图片
          图4、原图

学习OpenCV范例(十一)——图像的腐蚀与膨胀_第5张图片

         图5、膨胀图片

学习OpenCV范例(十一)——图像的腐蚀与膨胀_第6张图片

         图6、腐蚀图片

4、用到的类和函数

getStructuringElement:

功能:返回一个指定大小和形态的结构元素

结构:

Mat getStructuringElement(int shape, Size ksize, Point anchor=Point(-1,-1))
shape :核的类型
        MORPH_RECT:矩形,核的定义为:
        E_{ij}=1
      MORPH_ELLIPSE:椭圆
      MORPH_CROSS:交叉型,核的定义为:

      E_{ij} =  \fork{1}{if i=\texttt{anchor.y} or j=\texttt{anchor.x}}{0}{otherwise}
      CV_SHAPE_CUSTOM :自定义类型
ksize :核的大小
anchor : 锚点 位置。不指定锚点位置,则默认锚点在内核中心位置。

dilate:

功能:图像膨胀

结构:

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 :源图像
dst :目标图像,和源图像有同样的size和type
element :结构元素,可通过 getStructuringElement,如果element=Mat(),那么默认核为3*3的矩形结构
anchor:  锚点  位置。不指定锚点位置,则默认锚点在内核中心位置。
iterations :迭代次数
borderType :边缘点插值类型
实现原理:

\texttt{dst} (x,y) =  \max _{(x',y'):  \, \texttt{element} (x',y') \ne0 } \texttt{src} (x+x',y+y')

函数支持(in-place)模式。膨胀可以重复进行 (iterations) 次. 对彩色图像,每个彩色通道单独处理。

erode:

功能:腐蚀图像

结构:

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 :源图像
dst :目标图像,和源图像有同样的size和type
element :结构元素,可通过 getStructuringElement,如果element=Mat(),那么默认核为3*3的矩形结构
anchor:  锚点  位置。不指定锚点位置,则默认锚点在内核中心位置。
iterations :迭代次数
borderType :边缘点插值类型
实现原理:

\texttt{dst} (x,y) =  \min _{(x',y'):  \, \texttt{element} (x',y') \ne0 } \texttt{src} (x+x',y+y')

函数支持(in-place)模式。膨胀可以重复进行 (iterations) 次. 对彩色图像,每个彩色通道单独处理。

createTrackbar:

功能:创建trackbar并将它添加到指定的窗口

结构:

int createTrackbar(const string& trackbarname, const string& winname, int* value, int count, TrackbarCallback onChange=0, void* userdata=0)
trackbarname :被创建的trackbar名字
winname :窗口名字,这个窗口将为被创建trackbar的父对象
value :整数指针,它的值将反映滑块的位置。这个变量指定创建时的滑块位置
count :滑块位置的最大值。最小值一直是0
onChange :每次滑块位置被改变的时候,被调用函数的指针。这个函数应该被声明为void Foo(int,void*);第一个参数是trackbar的位置,第二个参数是userdata,如果没有回调函数,这个值可以设为NULL。
userdata :回调函数返回的数据,在没有使用全局变量的时候,可以通过它来处理trackbar事件
补充:

getTrackbarPos:

功能:获取trackbar的位置,也即是value的位置

结构:

 int getTrackbarPos(const string& trackbarname, const string& winname)
trackbarname :trackbar的名字
winname :trackbar父窗口的名字

setTrackbarPos:

功能:设置trackbar位置,也即是value的位置

结构:

void setTrackbarPos(const string& trackbarname, const string& winname, int pos)
trackbarname :trackbar的名字
winname :trackbar父窗口的名字
pos :新的位置

你可能感兴趣的:(学习OpenCV范例)