目录
腐蚀与膨胀
更多的形态学操作
腐蚀与膨胀
更多形态学操作
形态学操作就是基于形状的一系列图像处理操作。
最基本的形态学操作就是腐蚀( erode )和膨胀( dilate )。其主要功能如下:
消除噪声;
分割出独立的图像元素,在图像中连接相邻的元素;
寻找图像中明显的极大值区域或极小值区域;
求出图像的梯度。
1. 膨胀函数: dilate() 。函数原型如下:
void dilate(InputArray src, OutputArray dst, InputArray kernel, Point anchor = Point(-1, -1), int iterations = 1, int borderType = BORDER_DEFAULT, const Scalar& borderValue = morphologyDefaultBorderValue());
(1)第一个参数,InputArray 类型的 src,源图像。图像通道的数量可以是任意的,但图像深度应为 CV_8U、CV_16U、CV_16S、CV_32F、CV_64F 之一。
(2)第二个参数,OutputArray 类型的 dst,输出图像。图像的尺寸和类型应和源图像保持一致。
(3)第三个参数,InputArray 类型的 kernel,膨胀操作的核。当为 NULL 时,表示使用参考点位于中心的 3*3 的核。一般使用 getStructingElement(int shape, Size ksize, Point anchor = Point(-1, -1)) 函数来设定内核矩阵的形状和尺寸。shape 参数表示内核矩阵的形状(矩形:MORPH_RECT;交叉形:MORPH_CROSS;椭圆形:MORPH_ELLIPSE)。使用如下所示:
int kernelSize = 3;
Mat element =
getStructingElement(MORPH_RECT, Size(2 * kernelSize + 1, 2 * kernelSize + 1);
(4)第四个参数,Point 类型的 anchor。默认值为Point(-1, -1),位于内核的中心点。
(5)第五个参数,int 类型的 iterations,迭代使用 dilate() 函数的次数,默认为 1。
(6)第六个参数,int 类型的 borderType,用于推断图像外部像素的某种边界模式。默认值为 MORPH_DEFAULT。
(7)第七个参数,const Scalar& 类型的 borderValue,当边界为常数时的边界值,有默认值 morphologyDefaultBorderValue() ,一般不管。
2. 腐蚀函数:erode()。原型如下:
void erode(InputArray src, OutputArray dst, InputArray kernel, Point anchor = Point(-1, -1), int iterations = 1, int borderType = BORDER_DEFAULT, const Scalar& morphologyDefaultBorderValue());
(1)第一个参数:源图像。参考 dilate() 函数。
(2)第二个参数,输出图像。参考 dilate() 函数。
(3)第三个参数,腐蚀内核。参考 dilate() 函数。
(4)第四个参数,内核矩阵的锚点。参考 dilate() 函数。
(5)第五个参数,erode() 函数执行的迭代次数。参考 dilate() 函数。
(6)第六个参数,图像外部像素的边界模式。参考 dilaye() 函数。
(7)第七个参数,边界为常数时的边界值。参考 dilate() 函数。
腐蚀与膨胀简单示例:
#include
#include
using namespace cv;
using namespace std;
void on_Erosion(int, void*);
void on_Dilation(int, void*);
int g_erosionType = 0;
int g_dilationType = 0;
int g_erosionSize = 1;
int g_dilationSize = 1;
int g_maxErosionType = 2;
int g_maxDilationType = 2;
int g_maxErosionSize = 31;
int g_maxDilationSize = 31;
const char* erosionTypeStr = "内核类型";
const char* erosionSizeStr = "内核大小";
const char* dilationTypeStr = "内核类型";
const char* dilationSizeStr = "内核大小";
Mat srcErosionImage, dstErosionImage, srcDilationImage, dstDilationImage;
int main()
{
srcErosionImage = imread("cat.jpg");
srcDilationImage = imread("cat.jpg");
imshow("原图", srcDilationImage);
if (srcErosionImage.empty())
{
cout << "源图片读取错误" << endl;
}
if (srcDilationImage.empty())
{
cout << "源图片读取错误" << endl;
}
namedWindow("腐蚀效果图", WINDOW_AUTOSIZE);
namedWindow("膨胀效果图", WINDOW_AUTOSIZE);
createTrackbar(erosionTypeStr, "腐蚀效果图", &g_erosionType, g_maxErosionType, on_Erosion);
createTrackbar(erosionSizeStr, "腐蚀效果图", &g_erosionSize, g_maxErosionSize, on_Erosion);
createTrackbar(dilationTypeStr, "膨胀效果图", &g_dilationType, g_maxDilationType, on_Dilation);
createTrackbar(dilationSizeStr, "膨胀效果图", &g_dilationSize, g_maxDilationSize, on_Dilation);
on_Erosion(0, 0);
on_Dilation(0, 0);
waitKey(0);
return 0;
}
void on_Erosion(int, void*)
{
/*
内核类型
0: 矩形
1: 交叉形
2: 椭圆形
*/
if (g_erosionType == 0)
{
g_erosionType = MORPH_RECT;
}
else if (g_erosionType == 1)
{
g_erosionType = MORPH_CROSS;
}
else if (g_erosionType == 2)
{
g_erosionType = MORPH_ELLIPSE;
}
Mat element = getStructuringElement(g_erosionType, Size(2 * g_erosionSize + 1, 2 * g_erosionSize + 1));
erode(srcErosionImage, dstErosionImage, element);
imshow("腐蚀效果图", dstErosionImage);
}
void on_Dilation(int, void*)
{
/*
内核类型
0: 矩形
1: 交叉形
2: 椭圆形
*/
if (g_dilationType == 0)
{
g_dilationType = MORPH_RECT;
}
else if (g_dilationType == 1)
{
g_dilationType = MORPH_CROSS;
}
else if (g_dilationType == 2)
{
g_dilationType = MORPH_ELLIPSE;
}
Mat element = getStructuringElement(g_dilationType, Size(2 * g_dilationSize + 1, 2 * g_dilationSize + 1));
dilate(srcDilationImage, dstDilationImage, element);
imshow("膨胀效果图", dstDilationImage);
}
运行结果如下图:
通过腐蚀与膨胀这两个基本操作的结合,我们可以得到更多的形态学操作。主要有以下几种:
开运算(Opening )
闭运算(Closing)
形态学梯度(Morphological Gradient)
顶帽(Top Hat)
黑帽(Black Hat)
1. 开运算,其实就是先腐蚀后膨胀的过程。其数学表达式如下:
dst = open(src, element) = dilate(erode(src, element));
开运算可以用来消除小物体,在纤细点处分离物体,并且在平滑较大物体的边界的同时不明显改变其面积。
2.闭运算,其实就是先膨胀后腐蚀的过程。其数学表达式如下:
dst = close(src, element) = erode(dilate(src, element));
闭运算能够排除小型黑洞(黑色区域)。
3.形态学梯度,其实就是膨胀图与腐蚀图之差。其数学表达式如下:
dst = morph-grad(src, element) = dilate(src, element)− erode(src, element);
对二值图像进行这一操作可以将团块(blob)的边缘突出出来。可以使用形态学梯度来保留物体的边缘轮廓。
4.顶帽,其实就是原图像与开运算效果图之差。数学表达式如下:
dst = tophat(src, element) = src - open(src, element);
开运带来的结果是放大了裂缝或者局部低亮度的区域,因此,从原图像中减去开运算的图,得到的效果图突出了比原图轮廓周围的区域更明亮的区域,且这一操作与选择的核的大小相关。
顶帽运算往往用来分离比邻近点亮一些的斑块。在一幅图像具有大幅的背景,而微小物品比较有规律的情况下,可以使用顶帽运算进行背景提取。
5.黑帽,其实就是闭运算的效果图与原图像之差,其数学表达式如下:
dst = blackhat(src, element) = close(src, element) - src;
黑帽运算后的效果图突出了比原图轮廓周围区域更暗的区域,且这一操作和选择的核的大小相关。
所以,黑帽运算用来分离比邻近点暗一些的斑块,效果图有着非常完美的轮廓。