在OpenCV中,膨胀和腐蚀是基本的形态学操作,膨胀是使用像素邻域内的局部极大运算来膨胀一张图片,腐蚀是使用像素邻域内的局部极小运算来腐蚀一张图片,二者是一对相反的操作,但是都是对图像中的白色部分(高亮部分)而言的,膨胀用dilate()函数,腐蚀用erode()函数,函数原型分别如下:
void dilate( InputArray src, OutputArray dst, InputArray kernel,
Point anchor = Point(-1,-1), int iterations = 1,
int borderType = BORDER_CONSTANT,
const Scalar& borderValue = morphologyDefaultBorderValue() );
void erode( InputArray src, OutputArray dst, InputArray kernel,
Point anchor = Point(-1,-1), int iterations = 1,
int borderType = BORDER_CONSTANT,
const Scalar& borderValue = morphologyDefaultBorderValue() );
一、实例代码:
#include
//#include
#include
#include
#include
#define WINDOWNAME "【效果图】"
using namespace std;
using namespace cv;
//------------------------【全局变量声明】
Mat g_srcImage, g_dstImage; //原始图和效果图
int g_nTrackbarNumber = 0; //0表示腐蚀erode,1表示膨胀dilate,初始值设为0表示用腐蚀
int g_nStructElementSize = 3; //结构元素(内核矩阵)的尺寸
//-------------------------【全局函数声明】
void Process(); //膨胀和腐蚀的处理函数
void on_TrackbarNumChange(int, void*); //回调函数
void on_ElementSizeChange(int, void*); //回调函数
int main()
{
//改变console字体颜色
//system("color 2F");
//载入原图
g_srcImage = imread("F:\\TuPian\\littlecat.jpg");
if (g_srcImage.data == NULL)
{
cout << "读取srcImage失败!" << endl;
}
//显示原始图
const char* pName1 = "原始图";
namedWindow(pName1);
imshow(pName1, g_srcImage);
// 进行初次腐蚀操作并显示效果图
const char* Pname = "图2";
namedWindow(Pname);
Mat element = getStructuringElement(MORPH_RECT, Size(2*g_nStructElementSize+1,2*g_nStructElementSize+1), Point(g_nStructElementSize,g_nStructElementSize));
erode(g_srcImage, g_dstImage, element);
imshow(Pname, g_dstImage);
namedWindow(WINDOWNAME);
//显示的图像是根据图像的名称来显示的
//只是创建了带有窗口名的一个窗口,里面并没有任何图像内容
//创建轨迹条
//在创建的窗体中创建一个滑动条控件
createTrackbar("腐蚀/膨胀", WINDOWNAME, &g_nTrackbarNumber, 1, on_TrackbarNumChange); //第三个参数是滑块的初始位置,第4个参数是最大值
createTrackbar("内核尺寸", WINDOWNAME, &g_nStructElementSize, 21, on_ElementSizeChange);
//on_TrackbarNumChange(g_nTrackbarNumber, 0); //【回调函数初始化】
//on_ElementSizeChange(g_nStructElementSize, 0); //【回调函数初始化】
//需要进行回调函数初始化,不进行初始化就没有初始图像显示
//按任意键退出
waitKey(0);
return 0;
//std::cout << "Hello World!\n";
}
//-----------------------------【Process()函数】
//描述:进行自定义的腐蚀和膨胀操作
void Process()
{
//获取自定义内核
Mat element = getStructuringElement(MORPH_RECT, Size(2 * g_nStructElementSize + 1, 2 * g_nStructElementSize + 1), Point(g_nStructElementSize, g_nStructElementSize));
//进行膨胀或腐蚀操作
if (g_nTrackbarNumber == 0)
{
erode(g_srcImage, g_dstImage, element);
}
else
{
dilate(g_srcImage, g_dstImage, element);
}
//显示效果图
imshow(WINDOWNAME, g_dstImage);
}
//-----------------------------【on_TrackbarNumChange()函数】
//描述:腐蚀和膨胀之间切换开关的回调函数
void on_TrackbarNumChange(int, void*)
{
//腐蚀和膨胀之间效果已经切换,回调函数体内需调用一次Process函数,使改变后的效果立即生效并显示出来
Process();
}
//-----------------------------【on_ElementSizeChange()函数】
//描述:腐蚀和膨胀操作内核改变时的回调函数
void on_ElementSizeChange(int, void*)
{
//内核尺寸已经改变,回调函数体内需调用一次Process函数,使改变后的效果立即生效并显示出来
Process();
}
二、结果:
调整第3幅图上的滑块,结果如下图所示:
第3幅图之所以最开始没有显示出图像,是因为没有进行函数的回调,代码中的这两行注释掉了,
//on_TrackbarNumChange(g_nTrackbarNumber, 0); //【回调函数初始化】
//on_ElementSizeChange(g_nStructElementSize, 0); //【回调函数初始化】
如果不注释掉这两行,则第3幅图最开始就会显示出来。
参考: 《OpenCV3编程入门》毛星云、冷雪飞等编著,电子工业出版社,2018年11月第19次印刷,p187-198。