高级形态学变换,基于腐蚀与膨胀,利用morphologyEx函数实现
1.腐蚀后膨胀的过程,数学表达式:dst=open(src,element)=dilate(erode(src,element))
2.作用:消除小物体,在纤细点处分离物体,并且在平滑较大物体的边界的同时不明显改变其面积
1.膨胀后腐蚀的过程,数学表达式:dst=close(src,element)=erode(dilate(src,element))
2.作用:排除小型黑洞
1.膨胀图与腐蚀图之差,数学表达式:dst=morph-grad(src,element)=dilate(src,element)-erode(src,element)
2.作用:将团块的边缘突出,保留物体边缘轮廓
1.原图像与开运算结果之差,数学表达式:dst=tophat(src,element)=src-open(src,element)
2.作用:开运算放大了裂缝或局部低亮度区域,所以顶帽突出了比原图轮廓周围区域更明亮的区域,用来分离比临近点亮一些的区域,在一幅大背景物品微小有规律的图像中,可以进行背景提取
1.闭运算结果与原图之差,数学表达式:dst=blackhhat(src,element)=close(src,element)-src
2.作用:黑帽突出了比原图轮廓周围区域更暗的区域,用来分离比临近点暗一些的区域,效果图有非常完美的轮廓
1.函数原型:
void morphologyEx(InputArray src,OutputArray dst,int op,InputArraykernel,Pointanchor=Point(-1,-1),intiterations=1,intborderType=BORDER_CONSTANT,constScalar& borderValue=morphologyDefaultBorderValue() );
2.参数说明:
(1)输入图像
(2)目标图像
(3)形态学运算类型
(4)形态学运算内核,getStructuringElement函数配合使用
(5)锚的位置,默认(-1,-1)表示中心
(6)迭代使用函数次数,默认1
(7)用于推断图像外部像素的某种边界模式,默认BORDER_CONSTANT
(8)当边界为常数时的边界值,默认值morphologyDefaultValue()
/*
效果:
4个显示窗口,原始图,开/闭运算,腐蚀/膨胀,顶帽/黑帽
滚动条控制形态学效果,迭代值为10的时候为中间点
通过按键1、2、3及空格调节成不同的元素结构(矩形、椭圆、十字形)
*/
#include
#include
#include
#include
using namespace cv;
using namespace std;
//全局变量
Mat g_srcImage, g_dstImage;
int g_nElementShape = MORPH_RECT;//元素结构形状
//变量接收的TrackBar位置参数
int g_nMaxIterationNum = 10;
int g_nOpenCloseNum = 0;
int g_nErodeDilateNum = 0;
int g_nTopBlackHatNum = 0;
//全局函数
static void on_OpenClose(int, void*);
static void on_ErodeDilate(int, void*);
static void on_TopBlackHat(int, void*);
static void ShowHelpText();
int main()
{
//改变console颜色
system("color 3B");
//显示提示信息
ShowHelpText();
//载入原图
g_srcImage = imread("love.jpg");
if (!g_srcImage.data)
{
printf("载入原图像失败~!\n");
return false;
}
//显示原图
namedWindow("【原始图】");
imshow("【原始图】", g_srcImage);
//创建三个窗口
namedWindow("【开运算/闭运算】",1);
namedWindow("【腐蚀/膨胀】",1);
namedWindow("【顶帽/黑帽】",1);
//参数赋值
g_nOpenCloseNum = 9;
g_nErodeDilateNum = 9;
g_nTopBlackHatNum = 2;
//创建滚动条
createTrackbar("迭代值", "【开运算/闭运算】", &g_nOpenCloseNum, g_nMaxIterationNum * 2 + 1, on_OpenClose);
createTrackbar("迭代值", "【腐蚀/膨胀】", &g_nErodeDilateNum, g_nMaxIterationNum * 2 + 1, on_ErodeDilate);
createTrackbar("迭代值", "【顶帽/黑帽】", &g_nTopBlackHatNum, g_nMaxIterationNum * 2 + 1, on_TopBlackHat);
//轮询获取按键信息
while (1)
{
int c;
//执行回调函数
on_OpenClose(g_nOpenCloseNum, 0);
on_ErodeDilate(g_nErodeDilateNum, 0);
on_TopBlackHat(g_nTopBlackHatNum, 0);
//获取按键
c = waitKey(0);
//按下键盘按键Q或ESC,程序退出
if ((char)c == 'q' || (char)c == 27)
break;
//按下键盘按键1,使用椭圆结构元素MORPH_ELLIPSE
if ((char)c == 49)//键盘1的ASII码为49
g_nElementShape = MORPH_ELLIPSE;
//按下键盘按键2,使用矩形结构元素MORPH_RECT
else if ((char)c == 50)//键盘2的ASII码为50
g_nElementShape = MORPH_RECT;
//按下键盘按键3,使用十字形结构元素MORPH_CROSS
else if ((char)c == 51)//键盘3的ASII码为51
g_nElementShape = MORPH_CROSS;
//按下键盘按键space,在矩形、椭圆、十字形结构元素中循环
else if ((char)c == ' ')
g_nElementShape = (g_nElementShape + 1) % 3;
}
return 0;
}
//【开运算/闭运算】窗口回调函数
static void on_OpenClose(int, void*)
{
//偏移量定义(滑动条以g_nMaxIterationNum点为原点,计算偏移量(<0)绝对值为开运算度,偏移量(>0)绝对值为闭运算度
int offset = g_nOpenCloseNum - g_nMaxIterationNum;//偏移量
int Absolute_offset = offset > 0 ? offset : -offset;//偏移量绝对值
//自定义核
Mat element = getStructuringElement(g_nElementShape, Size(Absolute_offset * 2 + 1, Absolute_offset * 2 + 1), Point(Absolute_offset, Absolute_offset));
//进行操作
if (offset < 0) //g_nOpenCloseNum=0~9
morphologyEx(g_srcImage, g_dstImage, MORPH_OPEN, element);
else //g_OpenCloseNum=10~21
morphologyEx(g_srcImage, g_dstImage, MORPH_CLOSE, element);
//显示图像
imshow("【开运算/闭运算】", g_dstImage);
}
//【腐蚀/膨胀】窗口回调函数
static void on_ErodeDilate(int, void*)
{
//偏移量定义(滑动条以g_nMaxIterationNum点为原点,计算偏移量(<0)绝对值为腐蚀度,偏移量(>0)绝对值为膨胀度
int offset = g_nErodeDilateNum - g_nMaxIterationNum;//偏移量
int Absolute_offset = offset > 0 ? offset : -offset;//偏移量绝对值
//自定义核
Mat element = getStructuringElement(g_nElementShape, Size(Absolute_offset * 2 + 1, Absolute_offset * 2 + 1), Point(Absolute_offset, Absolute_offset));
//进行操作
if (offset < 0) //g_nErodeDilateNum=0~9
erode(g_srcImage, g_dstImage, element);
else //g_nErodeDilateNum=10~21
dilate(g_srcImage, g_dstImage, element);
//显示图像
imshow("【腐蚀/膨胀】", g_dstImage);
}
//【顶帽运算/黑帽运算】窗口回调函数
static void on_TopBlackHat(int, void*)
{
//偏移量定义(滑动条以g_nMaxIterationNum点为原点,计算偏移量(<0)绝对值为顶帽度,偏移量(>0)绝对值为黑帽度
int offset = g_nTopBlackHatNum - g_nMaxIterationNum;//偏移量
int Absolute_offset = offset > 0 ? offset : -offset;//偏移量绝对值
//自定义核
Mat element = getStructuringElement(g_nElementShape, Size(Absolute_offset * 2 + 1, Absolute_offset * 2 + 1), Point(Absolute_offset, Absolute_offset));
//进行操作
if (offset < 0) //g_nTopBlackHatNum=0~9
morphologyEx(g_srcImage, g_dstImage, MORPH_TOPHAT, element);
else //g_nTopBlackHatNum=10~21
morphologyEx(g_srcImage, g_dstImage, MORPH_BLACKHAT, element);
//显示图像
imshow("【顶帽/黑帽】", g_dstImage);
}
static void ShowHelpText()
{
printf("--------------------------------------------------------------------\n");
printf("请调整滑动条观察图像效果\n");
printf("按键操作说明:\n");
printf("\t\t键盘按键[ESC]或[Q]-退出程序\n");
printf("\t\t键盘按键[1]-使用椭圆结构元素\n");
printf("\t\t键盘按键[2]-使用矩形结构元素\n");
printf("\t\t键盘按键[3]-使用十字形结构元素\n");
printf("\t\t键盘按键[space]-在巨型、椭圆、十字形结构元素中循环\n");
printf("--------------------------------------------------------------------\n");
}