一、概论
数学形态学(Mathematical morphology) 是一门建立在格论和拓扑学基础之上的图像分析学科,是数学形态学图像处理的基本理论。其基本的运算包括:二值腐蚀和膨胀、二值开闭运算、骨架抽取、极限腐蚀、击中击不中变换、形态学梯度、Top-hat变换、颗粒分析、流域变换、灰值腐蚀和膨胀、灰值开闭运算、灰值形态学梯度等。
膨胀与腐蚀是图像的最基本的两种变化,他们能实现的功能包括但不限于:
(1) 、消除噪声
(2) 、分割出图像中独立的元素或者连接图像中的元素
(3) 、寻找图像中明显的极大值区域和极小值区域
(4) 、求出图像的梯度
需要注意的是,腐蚀和膨胀是对高亮部分(白色)来说的,图像进行膨胀操作后,它的高亮区域将变大,图像进行腐蚀操作后,他的高亮区域将变小。
二 、膨胀
void dilate(
InputArray src,
OutputArray dst,
InputArray kernel,
Point anchor=Point(-1,-1),
int iterations=1,
int borderType=BORDER_CONSTANT,
const Scalar& borderValue=morphologyDefaultBorderValue()
);
参数详解:
第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可。图像通道的数量可以是任意的,但图像深度应为CV_8U,CV_16U,CV_16S,CV_32F或 CV_64F其中之一。
第二个参数,OutputArray类型的dst,即目标图像,需要和源图片有一样的尺寸和类型。
第三个参数,InputArray类型的kernel,膨胀操作的核。若为NULL时,表示的是使用参考点位于中心3x3的核。
我们一般使用函数 getStructuringElement配合这个参数的使用。getStructuringElement函数会返回指定形状和尺寸的结构元素(内核矩阵)。
其中,getStructuringElement函数的第一个参数表示内核的形状,我们可以选择如下三种形状之一:
o矩形: MORPH_RECT
o交叉形: MORPH_CROSS
o椭圆形: MORPH_ELLIPSE
而getStructuringElement函数的第二和第三个参数分别是内核的尺寸以及锚点的位置。
我们一般在调用erode以及dilate函数之前,先定义一个Mat类型的变量来获得getStructuringElement函数的返回值。对于锚点的位置,有默认值Point(-1,-1),表示锚点位于中心。且需要注意,十字形的element形状唯一依赖于锚点的位置。而在其他情况下,锚点只是影响了形态学运算结果的偏移。
膨胀就是局部最大值操作,其实就是将图像与核做卷积运算的结果。核可以是任何的形状和大小,它有一个参考点(锚点)。那么膨胀是如何操作的呢?图像与核覆盖的区域求最大值,然后将这个最大值赋值给指定的像素,这样就会使得图像中的高亮区域逐渐增长。
膨胀的数学表达式为:
三、腐蚀
erode(
InputArray src,
OutputArray dst,
InputArray kernel,
Point anchor=Point(-1,-1),
int iterations=1,
int borderType=BORDER_CONSTANT,
const Scalar& borderValue=morphologyDefaultBorderValue()
);
参数详解:
第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可。图像通道的数量可以是任意的,但图像深度应为CV_8U,CV_16U,CV_16S,CV_32F或 CV_64F其中之一。
第二个参数,OutputArray类型的dst,即目标图像,需要和源图片有一样的尺寸和类型。
第三个参数,InputArray类型的kernel,腐蚀操作的内核。若为NULL时,表示的是使用参考点位于中心3x3的核。我们一般使用函数 getStructuringElement配合这个参数的使用。getStructuringElement函数会返回指定形状和尺寸的结构元素(内核矩阵)。(具体看上文中浅出部分dilate函数的第三个参数讲解部分)
第四个参数,Point类型的anchor,锚的位置,其有默认值(-1,-1),表示锚位于单位(element)的中心,我们一般不用管它。
第五个参数,int类型的iterations,迭代使用erode()函数的次数,默认值为1。
第六个参数,int类型的borderType,用于推断图像外部像素的某种边界模式。注意它有默认值BORDER_DEFAULT。
第七个参数,const Scalar&类型的borderValue,当边界为常数时的边界值,有默认值morphologyDefaultBorderValue(),一般我们不用去管他。需要用到它时,可以看官方文档中的createMorphologyFilter()函数得到更详细的解释。
腐蚀和膨胀是相反的操作,膨胀希望高亮区域越来越大,而腐蚀希望高亮区域越来越小,看数学表达式就可以理解这一点:
四、看源码理解
//腐蚀操作函数
void cv::erode( InputArray src, OutputArray dst, InputArray kernel,
Point anchor, int iterations,
int borderType, const Scalar& borderValue )
{
//直接调用,设置标志为MORPH_ERODE
morphOp( MORPH_ERODE, src, dst, kernel, anchor, iterations, borderType, borderValue );
}
//膨胀操作函数
void cv::dilate( InputArray src, OutputArray dst, InputArray kernel,
Point anchor, int iterations,
int borderType, const Scalar& borderValue )
{
//设置标志为MORPH_DILATE
morphOp( MORPH_DILATE, src, dst, kernel, anchor, iterations, borderType, borderValue );
}
这是只是设置好标志后调用高层函数来实现功能。
五、试用
void usage_dilate()
{
Mat image = imread("./smimage/1.jpg");
//show the src image
imshow("SRC", image);
//get the kernel
Mat ele = getStructuringElement(MORPH_RECT, Size(3,3));
Mat res;
dilate(image, res, ele);
//show the res image
imshow("RES", res);
waitKey(0);
}
void usage_erode()
{
Mat src = imread("./smimage/1.jpg");
//get the kernel
Mat ele = getStructuringElement(MORPH_RECT, Size(5, 5));
Mat res;
erode(src, res, ele);
//show the image
imshow("SRC", src);
imshow("RES", res);
waitKey(0);
}