4 形态学滤波(2):开运算、闭运算、形态学梯度、顶帽、黑帽
4.1 开运算
开运算(Opening Operation)其实就是先腐蚀后膨胀的过程
dst = open(src,element) = dilate(erode(src,element));
开运算用来消除小物体,在纤细处分离物体并且在平滑较大的物体的边界不明显改变其体积
4.2 闭运算
先膨胀后腐蚀的过程(Closing Operation)
dst = cleose(src,element) = erode(dilate(src,element))
能够排除小型的黑洞
4.3 形态学梯度
膨胀图与腐蚀图之差,dst = morph-grad(src,element) = dilate(sec,element-) - erode(src,element)
保留物体的边缘轮廓
4.4 顶帽
Top Hat(礼帽),是原图与开运算的结果图之差
dst = tophat(src, element) = src - open(src, element)
用来分离比临近点亮一些的斑点,可以进行背景提取
4.5 黑帽
Black Hat 是闭运算与原图像之差
dst = blackhat(src, element) = close(src,element) -src
用来分离比邻近点暗一些的斑点,效果图有着非常完美的轮廓
4.6 morphologyEx()
morphologyEx函数利用基本的腐蚀核膨胀技术,来执行更加高级的形态学变换
void morphologyEx(InputArray src,OutputArray dst, int op, InputArray kernel, Point anchor = Point(-1,-1),int iterations = 1, int borderType = BORDER_CONSTANT, const Scalar & borderValue=morphologyDefaultBorderValue());
4.7 综合示例
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;
//----------------------【全局变量声明部分】-----------------
//描述:全部变量声明
//--------------------------------------------------------
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 = 2;
//-------------------------【全局函数声明部分】--------------
// 描述:全局函数声明
//--------------------------------------------------------
static void on_OpenClose(int, void *);
static void on_ErodeDilate(int, void *);
static void on_TopBlackHat(int, void *);
int main()
{
//载入原图
g_srcImage = imread("1.jpg");
if (!g_srcImage.data)
{
printf("读取srcImage错误~!\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);
if ((char)c == 'q' || (char)c == 27)
{
break;
}
//按下键盘按键1 使用椭圆elliptic结构元素MORPH_ELLIPSE
if ((char)c == 49)
{
g_nElementShape = MORPH_ELLIPSE;
}
else if ((char)c == 50) //按键2
{
g_nElementShape = MORPH_RECT;
}
else if ((char)c == 51)
{
g_nElementShape = MORPH_CROSS;
}
else if ((char)c == ' ')
{
g_nElementShape = (g_nElementShape + 1) % 3;
}
}
return 0;
}
//-------------------【on_OpenClose()函数】-------------------
// 描述:开运算/闭运算窗口的回调函数
//----------------------------------------------------------
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);
}
//-------------------------【on_ErodeDilate()函数】------------
// 描述:腐蚀膨胀的回调函数
//------------------------------------------------------------
static void on_ErodeDilate(int, void *)
{
//偏移量
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)
{
erode(g_srcImage, g_dstImage, element);
}
else
{
dilate(g_srcImage, g_dstImage, element);
}
imshow("【腐蚀/膨胀】", g_dstImage);
}
//------------------------【on_TopBlackHat()函数】--------------
// 描述:顶帽/黑帽的回调函数
//-------------------------------------------------------------
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);
}