一、膨胀和腐蚀
二、开运算、闭运算、形态学梯度、顶帽、黑帽
示例代码:
#include<opencv2\core\core.hpp>
#include<opencv2\highgui\highgui.hpp>
#include<opencv2\imgproc\imgproc.hpp>
#include<iostream>
using namespace cv;
using namespace std;
Mat g_srcImage, g_dstImage;
int g_nElementShape = MORPH_RECT;
int g_nMaxIterationNum = 10;
int g_nOpenCloseNum = 0;
int g_nErodeDilateNum = 0;
int g_nTopBlackHatNum = 0;
static void on_OpenClose(int, void *)
{
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)
morphologyEx(g_srcImage, g_dstImage, MORPH_OPEN, element);
else
morphologyEx(g_srcImage, g_dstImage, MORPH_CLOSE, element);
imshow("<开/闭运算>", g_dstImage);
}
static void on_ErodeDilate(int, void *)
{
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)
erode(g_srcImage, g_dstImage,element);
else
dilate(g_srcImage, g_dstImage,element);
imshow("<腐蚀/膨胀>", g_dstImage);
}
static void on_TopBlackHat(int, void*)
{
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)
morphologyEx(g_srcImage, g_dstImage, MORPH_TOPHAT, element);
else
morphologyEx(g_srcImage, g_dstImage, MORPH_BLACKHAT, element);
imshow("<顶帽/黑帽>", g_dstImage);
}
int main()
{
g_srcImage = imread("lena.jpg");
if (!g_srcImage.data)
{
cout << "读取图片错误\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_nOpenCloseNum, 2 * g_nMaxIterationNum + 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,椭圆
if ((char)c == 49)
g_nElementShape = MORPH_ELLIPSE;
//按2,矩形
if ((char)c == 50)
g_nElementShape = MORPH_RECT;
//按3,十字形
else if ((char)c == 51)
g_nElementShape = MORPH_CROSS;
//space键,在矩形、椭圆、十字之间循环
else if ((char)c == ' ')
g_nElementShape = (g_nElementShape + 1) % 3;
}
return 0;
}
效果:
理解:
后面的那些都是基于腐蚀和膨胀的。
开运算——先腐蚀再膨胀,消除细小物体,在纤细点处分离物体。
闭运算——先膨胀后腐蚀,排除小型黑洞。
形态学梯度——膨胀-腐蚀,将团块的边缘突出出来,保留物体边缘轮廓。
顶帽——原图-开运算,分离比临近点亮的一些斑块,在一幅图像具有大幅背景并且微小物品有规律,可以用这个进行背景提取。
黑帽——原图-闭运算,分离比临近点暗的一些斑块,效果图有很完美的轮廓。