既然是基于膨胀和腐蚀的运算,那么再让我们详细了解一下膨胀和腐蚀到底对图像做了什么?
第一种情况,对于二值图像来说
腐蚀:核与其覆盖的图像部分做“与”操作,如果全为1,则该像素点为1,否则为0;也就是0容易得到,图像更多的地方变黑了,白色部分被腐蚀了
膨胀:核与其覆盖的图像部分做“与”操作,如果全为0,则该像素点为0,否则为1;也就是1容易得到,图像更多的地方变白了,白色部分膨胀了
第二种情况,对于一个灰度图像来说:
腐蚀:某一点的像素值,就是核与图像该部分像素值差的最小值。所以像素值变低比较容易,亮色部分被腐蚀。
膨胀:某一点的像素值,就是核与图像该部分像素值和的最大值。所以像素值变高比较容易,亮色部分膨胀。
1.开运算
先腐蚀后膨胀
作用:放大裂缝和低密度区域,消除小物体,在平滑较大物体的边界时,不改变其面积
2.闭运算
先膨胀后腐蚀
作用:排除小型黑洞,突触了比原图轮廓区域更暗的区域
3.形态学梯度
形态学梯度=膨胀图-腐蚀图
作用:保留图像边缘
4.顶帽(礼帽)
顶帽=原图-开运算
分离邻近点亮一些的斑块,进行背景提取
5.黑帽
黑帽=闭运算-原图
用来分离比邻近点暗一些的斑块
6.更加高级的形态学运算函数——morphologyEx()
下面这个程序:用键盘按键123改变核的形状,用进度条同时改变类型及Size大小,正负代表类型,绝对值代表Size
//目的:写一个腐蚀/膨胀,顶帽/黑帽,开/闭运算的程序,用控制条控制运算方式及核Size,用键盘控制核类型
Mat g_src,g_dst;
int g_nOpenCloseNum=0;
int g_nErodeDilateNum=0;
int g_nTopBlackNum=0;
int g_nMaxNum=10;
static void on_nOpenCloseSlide(int,void*);
static void on_nErodeDilateSlide(int,void*);
static void on_nTopBlackSlide(int,void*);
int g_nShapeNum=MORPH_RECT;
int main()
{
g_src=imread("cui.jpg"); //这里前面错误的写为Mat g_src=imread("cui.jpg")相当于把g_src变成了局部变量
namedWindow("腐蚀/膨胀");
namedWindow("顶帽/黑帽");
namedWindow("开/闭");
createTrackbar("Size-10","开/闭",&g_nOpenCloseNum,g_nMaxNum*2+1,on_nOpenCloseSlide);
createTrackbar("Size-110","腐蚀/膨胀",&g_nErodeDilateNum,g_nMaxNum*2+1,on_nErodeDilateSlide);
createTrackbar("Size-120","顶帽/黑帽",&g_nTopBlackNum,g_nMaxNum*2+1,on_nTopBlackSlide);
while(1)
{
int c;
//cin>>c;
//执行回调函数
cout<<"循环1次"<0)
morphologyEx(g_src,g_dst,MORPH_OPEN,element);
else
morphologyEx(g_src,g_dst,MORPH_CLOSE,element);
imshow("开/闭",g_dst);
}
static void on_nErodeDilateSlide(int,void*)
{
cout<<"已经调用回调函数二:on_nErodeDilateSlide"<0)
erode(g_src,g_dst,element);
else
dilate(g_src,g_dst,element);
imshow("腐蚀/膨胀",g_dst);
}
static void on_nTopBlackSlide(int,void*)
{
cout<<"已经调用回调函数三:on_nTopBlackSlide"<0)
morphologyEx(g_src,g_dst,MORPH_TOPHAT,element);
else
morphologyEx(g_src,g_dst,MORPH_BLACKHAT,element);
imshow("顶帽/黑帽",g_dst);
}
程序问题:1.createTrackbar不执行回调函数为什么也可以运行呢?
经试验,不写回调函数的语句,确实没有调用回调函数,但是为什么之前的例子没关系呢?
确实,不写回调函数可以,但是回调函数承担着给函数赋初值的作用,如果不写回调函数,第一,刚打开图片时是没有画面的,必须点击一下进度条才有画面。
第二,如果在循环开始不赋初值的话,当改变核形状的时候,图片不会自己转变,而是要点一下进度条才有变化。
所以,赋初值,也就是写回调函数,还是很有必要的。
2.waitkey()如何获取获取按键
waitkey灵活运用注意如下几点
当参数delay中为负,则无穷等待
否则等待delay ms.
返回值是按键值 否则返回-1
当参数为空,则一直等待按键当前线程等待
waitkey只对显示图像窗口有效,对控制台无效
3.程序中出现一个错误,那就是只有开闭运算会随着进度条的调整,图像发生变化,其他两种运算不会变化。这里有一个细节,第一下拖动进度条会变化,后面就不动了。还有一个细节,每次显示图片,开闭运算的图片总是第一个显示出来。
猜想原因是:
(1).和三个函数调用的顺序有关,经改变,情况依旧,所以排除该种可能。
(2).另外两个函数的书写有问题,经检查,没问题。
(3).偏差与element没有设置为局部变量,所以函数之间互相影响,这一点是错误,已经更正了。
错误原因找到了 offset的定义出了问题,每一个函数的offset定义不同,但是我因为是复制的,所以都一样了,所以第一个图变了,其他的offset就确定了,导致了错误。
4.3通道RGB图片可以吗?答案是可以。