最基本形态学操作:腐蚀与膨胀
实现功能:消除噪声;分割出独立的图像元素,在图像中连接相邻的元素;寻找图像中的明显的极大值区域或极小值区域;求出图像的梯度;
腐蚀膨胀针对高亮部分;膨胀就是利用一形状的核与图像卷积,即计算出核内覆盖的图像区域的像素点中的最大值,并将其赋给锚点,结果就会使图像中高亮的部分延伸扩大,腐蚀正好相反。
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
using namespace std;
using namespace cv;
Mat g_srcImage, g_dstImage;//原始图和效果图
int g_nTrackbarNumer = 0;//0表示腐蚀erode, 1表示膨胀dilate
int g_nStructElementSize = 3; //结构元素(内核矩阵)的尺寸
void Process();//膨胀和腐蚀的处理函数
void on_TrackbarNumChange(int, void *);//回调函数
void on_ElementSizeChange(int, void *);//回调函数
void ShowHelpText();
int main( )
{
//载入原图
g_srcImage = imread("1.jpg");
if( !g_srcImage.data ) { printf("读取srcImage错误~! \n"); return false; }
//显示原始图
namedWindow("【原始图】");
imshow("【原始图】", g_srcImage);
//进行初次腐蚀操作并显示效果图,因为在滑动条未动时,不调用腐蚀膨胀函数
namedWindow("【效果图】");
//获取自定义核
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("【效果图】", g_dstImage);
//创建轨迹条
createTrackbar("腐蚀/膨胀", "【效果图】", &g_nTrackbarNumer, 1, on_TrackbarNumChange);
createTrackbar("内核尺寸", "【效果图】", &g_nStructElementSize, 21, on_ElementSizeChange);
//输出一些帮助信息
cout<<endl<<"\t运行成功,请调整滚动条观察图像效果~\n\n"
<<"\t按下“q”键时,程序退出。\n";
//轮询获取按键信息,若下q键,程序退出
while(char(waitKey(1)) != 'q') {}
return 0;
}
//-----------------------------【Process( )函数】------------------------------------
// 描述:进行自定义的腐蚀和膨胀操作
//-----------------------------------------------------------------------------------------
void Process()
{
//获取自定义核
Mat element = getStructuringElement(MORPH_RECT, Size(2*g_nStructElementSize+1, 2*g_nStructElementSize+1),Point( g_nStructElementSize, g_nStructElementSize ));
/*getStructuringElement该函数会返回指定形状和尺寸的结构元素(内核矩阵);
第一个参数:内核的形状:可选 矩阵:MORPH_RECT;交叉形(十字形):MORPH_CROSS;椭圆形:MORPH_ELLIPSE;十字形唯一依赖于锚点的位置,而其他只是影响运算结果的偏移
第二个参数:内核的尺寸Size(width,height)
第三个参数:锚点的位置,可用默认值Point(-1,-1)表示锚点位于中心*/
//进行腐蚀或膨胀操作
if(g_nTrackbarNumer == 0) {
erode(g_srcImage, g_dstImage, element);
/*腐蚀:第一个参数:输入图像,图像的通道的数量可以是任意的,但图形的深度应为CV_8U、CV_16U、CV_16S、CV_32F、CV_64F其中之一;
第二个参数为输出图像,需要与源图像一样的尺寸和类型;
第三个参数:InputArray类型的kernel,膨胀操作的核。当为NULL时,表示的是使用参考点位于中心的3*3的核
第四个参数:锚点的位置,前面核已定义了锚点,此处再定义不知是重复,还是锚点再次位移?
第五个参数:迭代的次数,有默认值1;
第六个参数:边界同以前笔记说明
第七个参数:constScalar&类型的borderValue,当边界为常数时的边界值,有默认值morphologyDefaultBorderValue(),一般不管*/
}
else {
dilate(g_srcImage, g_dstImage, element);
/*膨胀:第一个参数:输入图像,图像的通道的数量可以是任意的,但图形的深度应为CV_8U、CV_16U、CV_16S、CV_32F、CV_64F其中之一;
第二个参数为输出图像,需要与源图像一样的尺寸和类型;
第三个参数:InputArray类型的kernel,膨胀操作的核。当为NULL时,表示的是使用参考点位于中心的3*3的核
第四个参数:锚点的位置;
第五个参数:迭代的次数,有默认值1;
第六个参数:边界模式同以前笔记说明
第七个参数:constScalar&类型的borderValue,当边界为常数时的边界值,有默认值morphologyDefaultBorderValue()*/
}
//腐蚀与膨胀函数一般只需填前面三个参数,后面四个都有默认值,而且往往结合getStrcturingElement一起使用
//显示效果图
imshow("【效果图】", g_dstImage);
}
//-----------------------------【on_TrackbarNumChange( )函数】------------------------------------
// 描述:腐蚀和膨胀之间切换开关的回调函数
//-----------------------------------------------------------------------------------------------------
void on_TrackbarNumChange(int, void *)
{
//腐蚀和膨胀之间效果已经切换,回调函数体内需调用一次Process函数,使改变后的效果立即生效并显示出来
Process();
}
//-----------------------------【on_ElementSizeChange( )函数】-------------------------------------
// 描述:腐蚀和膨胀操作内核改变时的回调函数
//-----------------------------------------------------------------------------------------------------
void on_ElementSizeChange(int, void *)
{
//内核尺寸已改变,回调函数体内需调用一次Process函数,使改变后的效果立即生效并显示出来
Process();
}