OpenCV学习心得——基础篇——滤波与卷积——图像形态学与核的卷积
FOR THE SIGMA
FOR THE GTINDER
FOR THE ROBOMASTER
简介:
这一系列的学习心得第一轮将参考《学习OpenCV3》一书
操作系统版本:Ubuntu16.04(在这里博主在Linux下进行运行的)
http://www.ubuntu.org.cn/download/desktop 桌面版ubuntu16.04 下载
电子版书籍下载地址
暂无资源
内容:
OpenCV提供了一种高效且易用的图像形态学变换接口。其中有很多形态学方法,但基本上所有的形态学操作都基于两种原始操作——膨胀与腐蚀。
膨胀与腐蚀
膨胀和腐蚀是最基本的形态学变换,可用于消除噪声、元素分割和连接、寻找图像中明显的极大值区域或极小值区域等。基于这两种操作,可以实现更复杂的形态学操作,用来定位强度峰值或孔洞、另一种形式的图像梯度等。
==膨胀(dilate)==是一种卷积操作,求局部最大值,它将目标像素的值替换为卷积核覆盖区域的局部最大值,扩张了明亮区域,填充凹面。此卷积核是一个非线性核,是一个四边形或圆形的实心核,其锚点在中心。
==腐蚀(erode)==是与之相反的操作,腐蚀操作计算的是核覆盖范围内的局部最小值缩减了明亮区,消除凸起。
总的来说膨胀就是扩展了明亮区域,填充凹面;腐蚀缩减了明亮区域,消除凸起。
void cv::dilate( //膨胀
cv::InputArray src,
cv::OutputArray dst,
cv::inputArray element, //膨胀操作的核,当为NULL时,使用3*3的核
cv::Point anchor = cv::Point(-1,-1), //锚的位置,其默认值(-1,,1)
int iterations = 1, //迭代使用erode函数的次数,默认为1
int borderType = cv::BORDER_CONSTANT //用于推断图像外部像素的某种边界模式
const cv::Scalar& borderValue = cv::morphologyDefaultBorderValue( )
);
void cv::erode( //腐蚀
cv::InputArray src,
cv::OutputArray dst,
cv::inputArray element, //膨胀操作的核,当为NULL时,使用3*3的核
cv::Point anchor = cv::Point(-1,-1), //锚的位置,其默认值(-1,,1)
int iterations = 1, //迭代使用erode函数的次数,默认为1
int borderType = cv::BORDER_CONSTANT //用于推断图像外部像素的某种边界模式
const cv::Scalar& borderValue = cv::morphologyDefaultBorderValue( )
);
通用形态学函数
又被称为高级形态学变换,当处理的对象是二值图像时,像素只能是开(>0)或关(=0)的图像掩膜时,基本的腐蚀和膨胀操作就够用了。需要对灰度图或者彩色图进行处理时,一些其他操作就非常有用了,这些操作可以通过cv::morphologyEx()实现。
void cv::morphologyEx(
cv::InputArray src,
cv::OutputArray dst,
int op, //指定函数进行的操作类型
cv::InputArray element,
cv::Point anchor = cv::Point(-1,-1),
int iterations = 1,
int borderType = cv::BORDER_DEFAULT
op表
操作值 | 形态学操作 | 是否需要临时图像 |
---|---|---|
cv::MOP_OPEN | 开操作 | 否 |
cv::MOP_CLOSE | 闭操作 | 否 |
cv::MOP_GRADIENT | 形态学梯度 | 总是需要 |
cv::MOP_TOPHAT | 顶帽操作 | 就地调用需要src=dist |
cv::MOP_BLACKHAT | 底帽操作 | 就地调用需要src=dist |
开运算和闭运算
开运算先将图像进行腐蚀,然后对腐蚀的结果进行膨胀。开操作常用语对二值图像中的区域进行计算。
dst = open(src,element) = dilate(erode(src,element) )
闭运算想将图像进行膨胀,然后对膨胀的结果进行腐蚀。闭操作用于复杂连通分支算法中减少无用或噪声驱动的片段。
dst=clese(src,element) = erode(dilate(src,element) )
对于连通分支,通常先进行腐蚀或闭操作消除噪声,然后通过开操作连接相互靠近的大型区域。
对于一幅非布尔型图像进行形态学操作时,闭操作最明显的效果是消除值小于邻域内的点的孤立异常,而开操作消除的是大于邻域内点的孤立异常值。
参考:https://blog.csdn.net/hanshanbuleng/article/details/80657148
形态学梯度
梯度操作的结果(扩张亮域)减腐蚀操作的结果(缩减亮域)产生了原图像中的目标边缘。对于灰度图像,其结果就是计算明暗变换的趋势。形态学梯度通常用于显示明亮区域的边界,然后便可以将他们看作目标或者目标的部分。用扩张的图像减去了收缩的图像便得到完整的边界。与计算梯度不同,它并不会关注某个物体的周围。
顶帽与黑帽
顶帽用于显示与其邻近相比更亮的部分;黑帽用于显示与其邻近相比更暗的部分。
参考:https://blog.csdn.net/qq_36387683/article/details/80489631
实例:
#include <opencv2/opencv.hpp>
int main()
{
cv::namedWindow("image", cv::WINDOW_NORMAL);
cv::namedWindow("erosion", cv::WINDOW_NORMAL); //腐蚀
cv::namedWindow("dilation", cv::WINDOW_NORMAL); //膨胀
cv::namedWindow("opening", cv::WINDOW_NORMAL); //开运算
cv::namedWindow("closing", cv::WINDOW_NORMAL); //闭运算
cv::namedWindow("gradient", cv::WINDOW_NORMAL); //形态学梯度
cv::namedWindow("topHat", cv::WINDOW_NORMAL); //顶帽
cv::namedWindow("blackHat", cv::WINDOW_NORMAL); //黑帽
cv::Mat img = cv::imread("pic.jpg");
cv::Mat erosion, dilation, opening, closing, gradient, topHat, blackHat;
cv::erode(img, erosion, cv::Mat());
cv::dilate(img, dilation, cv::Mat());
cv::morphologyEx(img, opening, cv::MORPH_OPEN, cv::Mat());
cv::morphologyEx(img, closing, cv::MORPH_CLOSE, cv::Mat());
cv::morphologyEx(img, gradient, cv::MORPH_GRADIENT, cv::Mat());
cv::morphologyEx(img, topHat, cv::MORPH_TOPHAT, cv::Mat());
cv::morphologyEx(img, blackHat, cv::MORPH_BLACKHAT, cv::Mat());
cv::imshow("image", img);
cv::imshow("erosion", erosion);
cv::imshow("dilation", dilation);
cv::imshow("opening", opening);
cv::imshow("closing", closing);
cv::imshow("gradient", gradient);
cv::imshow("topHat", topHat);
cv::imshow("blackHat", blackHat);
cv::waitKey(0);
cv::destroyAllWindows();
return 0;
}
自定义核
Opencv可以让你创建自己的核,在形态学上,核常常被称为“构造元素”,而使用cv::getStructuringElement()函数便可以自定义一个核。
cv::Mat cv::getStructuringElement(
int shape, //构造元素的基本形状
cv::size ksize, //元素大小
cv::Point anchor = cv::Point(-1,-1) //锚点位置。
);
元素形状shape表
形状值 | 元素 |
---|---|
cv::MORPH_RECT | 矩形 |
cv::MORPH_ELLIPSE | 椭圆形 |
cv::MORPH_CROSS | 交叉 |
==cv::filter2D()==进行卷积
void cv::filter2D(
InputArray src,
OutputArray dst,
int ddepth,
InputArray kernel,
cv::Point anchor=cv::Point(-1, -1),
double delta=0,
int borderType=cv::BORDER_DEFAULT
);
注:如果定义了锚点的位置,那么核的大小可以是偶数,否则必须是奇数。