相关重要API:
Mat getStructuringElement(int shape, Size esize, Point anchor = Point(-1, -1));
getStructuringElement函数会返回指定形状和尺寸的结构元素,返回类型为Mat
第一个参数表示内核的形状,有三种形状可以选择:
矩形:MORPH_RECT;
交叉形:MORPH_CROSS;
椭圆形:MORPH_ELLIPSE;
第二和第三个参数分别是内核的尺寸以及锚点的位置。
一般在调用erode以及dilate函数之前,先定义一个Mat类型的变量来获得getStructuringElement函数的返回值。对于锚点的位置,有默认值Point(-1,-1),表示锚点位于中心点。element形状唯一依赖锚点位置,其他情况下,锚点只是影响了形态学运算结果的偏移。
----------------------------------------------------------
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());//默认值
第一个参数,输入图像
第二个参数,输出图像
第三个参数,使用的形态学方法,有以下几种:
MORPH_OPEN – 开运算(Opening operation)
开运算是对图像先腐蚀再膨胀,可以排除小团的物体;
MORPH_CLOSE – 闭运算(Closing operation)
闭运算是对图像先膨胀再腐蚀,可以排除小型黑洞;
MORPH_GRADIENT -形态学梯度(Morphological gradient)
返回图片为膨胀图与腐蚀图之差,可以保留物体的边缘轮廓;
MORPH_TOPHAT - “顶帽”(“Top hat”)
返回图像为原图像与开运算结果图之差;
MORPH_BLACKHAT - “黑帽”(“Black hat“)
返回图片为闭运算结果图与原图像之差。
第四个参数,InputArray类型的kernel,形态学运算的内核。若为NULL时,表示的是使用参考点位于中心3x3的核。
第五个参数,Point类型的anchor,锚的位置,其有默认值(-1,-1),表示锚位于中心。
第六个参数,int类型的iterations,迭代使用函数的次数,默认值为1。
第七个参数,int类型的borderType,用于推断图像外部像素的某种边界模式。它有默认值BORDER_ CONSTANT。
第八个参数,const Scalar&类型的borderValue,当边界为常数时的边界值,有默认值morphologyDefaultBorderValue()。
------------------------------------------------------
#include "stdafx.h"
#include
#include
#include
#include
#include
using namespace std;
#define zoom 4 // 缩放因子, 将大图像缩小 n 倍显示
using namespace cv;
using namespace std;
// 填充holes
void fillHole(const Mat srcBw, Mat &dstBw);
int main()
{
// 【1】读入图像
Mat srcImage;
srcImage = imread("D:\\DSC_0506.JPG");
if (!srcImage.data) {
//处理错误
cout << "读取图片错误!" << endl;
system("pause");
return 0;
}
//【2】将图片转为灰度图
cvtColor(srcImage, srcImage, COLOR_BGR2GRAY);
Mat temp;
temp = srcImage;
resize(temp, temp, Size(temp.cols / zoom, temp.rows / zoom), (0, 0), (0, 0), 3);
imshow("灰度图", temp);
// 【3】canny算子边缘检测
Mat edge;
blur(srcImage, edge, Size(3, 3));//3x3内核降噪
Canny(srcImage, edge, 150, 100, 3);
temp = edge;
resize(edge, temp, Size(temp.cols / zoom, temp.rows / zoom), (0, 0), (0, 0), 3);
imshow("canny算子边缘检测", temp);
//【4】膨胀操作, 填充边缘缝隙
Mat element = getStructuringElement(MORPH_RECT, Size(3, 3));
for (int i = 0; i < 3; i++) {
morphologyEx(edge, edge, MORPH_DILATE,element);
}
temp = edge;
resize(edge, temp, Size(temp.cols / zoom, temp.rows / zoom), (0, 0), (0, 0), 3);
imshow("膨胀操作效果图", temp);
// 【5】Holes填充
for (int i = 0; i < 10; i++) // 填充10次
{
fillHole(edge, edge);
}
temp = edge;
resize(edge, temp, Size(temp.cols / zoom, temp.rows / zoom), (0, 0), (0, 0), 3);
imshow("【Holes填充图】", temp);
waitKey(0); // 等待按键结束
return 0;
}
// 填充Holes
void fillHole(const Mat srcBw, Mat &dstBw)
{
Size m_Size = srcBw.size();
Mat Temp = Mat::zeros(m_Size.height + 2, m_Size.width + 2, srcBw.type());//延展图像
srcBw.copyTo(Temp(Range(1, m_Size.height + 1), Range(1, m_Size.width + 1)));
floodFill(Temp, Point(0, 0), Scalar(255));
Mat cutImg;//裁剪延展的图像
Temp(Range(1, m_Size.height + 1), Range(1, m_Size.width + 1)).copyTo(cutImg);
dstBw = srcBw | (~cutImg);
}
原图:
canny边缘检测效果图:
边缘膨胀效果图:
空洞填充效果图:
相关参考:https://blog.csdn.net/kksc1099054857/article/details/76569718
https://blog.csdn.net/jiangjiao4726/article/details/75571014