目录
一、前言
二、形态学操作
1、什么是形态学操作
2、形态学操作的分类
三、OpenCV中的基本形态学操作
0、核生成的API
1、膨胀
1.API
2.代码展示
3.执行结果
2、腐蚀
继续填坑。
如果想看其他有关于OpenCV学习方法介绍、学习教程、代码实战、常见报错及解决方案等相关内容,可以直接看我的OpenCV分类:
【OpenCV系列】:https://blog.csdn.net/shuiyixin/article/category/7581855
如果你想了解更多有关于计算机视觉、OpenCV、机器学习、深度学习等相关技术的内容,想与更多大佬一起沟通,那就扫描下方二维码加入我们吧!
形态学操作本身是图像处理要研究的内容,而计算机视觉要实现相关功能,也要实现图像的处理。在图像处理技术中,有一些的操作会对图像的形态发生改变,这些操作一般称之为形态学操作。讲的再专业一些:
图像形态学操作是基于形状的一系列图像处理操作的合集,主要是基于集合论基础上的形态学数学。
了解了什么是形态学操作,我们再来了解一下常用的几个形态学操作:
首先是两个基本操作
(1)膨胀:跟卷积操作类似,假设有图像A和结构元素B,结构元素B在A上面移动,其中B定义其中心为锚点,计算B覆盖下A的最大像素值用来替换锚点的像素,其中B作为结构体可以是任意形状。
(2)腐蚀:腐蚀跟膨胀操作的过程类似,唯一不同的是以最小值替换锚点重叠下图像的像素值。
其次基于基本操作的操作
(1)开操作:先腐蚀后膨胀,可以去掉小的对象。
(2)闭操作:先膨胀后腐蚀,可以填充小对象。
(3)形态学梯度:膨胀减去腐蚀。
(4)顶帽:顶帽是原图像与开操作图像之间的差值图像。
(5)黑帽:黑帽是闭操作图像与原图像之间的差值图像。
可能大家对于定义还是比较模糊,没有直观的感受,接下来,我就以具体的例子,带领大家一起来了解膨胀与腐蚀。
在讲之前,我们先来了解一下核。
在形态学中,因为要涉及到区域像素操作,我们就要设计一个核,在核范围内对像素进行操作。所以我们需要创建一个核,在这里,我们用到一个新的API:getStructuringElement()。
我们来看一下API:
Mat getStructuringElement(
int shape,
Size ksize,
Point anchor = Point(-1,-1)
);
其函数参数如下:
(1)int类型的shape,元素形状,可以是cv::MorphShapes之一。
(2)Size类型的ksize,结构化元素的大小。
(3)Point类型的anchor,默认值(-1,-1),表示锚定位于中心。请注意,只有十字形元素的形状取决于锚定位置。在其他情况下,锚只是调节形态学操作结果的移动量。
这里主要说一下第一个参数,该参数主要有如下几种选择:
(1)MORPH_RECT:矩形结构区域。
(2)MORPH_CROSS,十字形结构区域。
(3)MORPH_ELLIPSE,椭圆结构区域,内接于矩形Rect(0,0,esize.width,0.esize.height)的填充椭圆。
前面我们讲到,膨胀就是计算B覆盖下A的最大像素值用来替换锚点的像素。我们还记得,像素范围是在[0-255],对于彩图来说,是一个六位的16进制数,如123456,其中12表示前两位,代表红色,34表示中间两位,代表绿色,56表示最后两位,代表蓝色。如果这6位都是最大,即为FFFFFF(255,255,255),图像的水印就是白色,如下图
如果这六位都是最小,即000000(0,0,0),图像水印就是纯黑色,如下图:
我们要使用像素最大值,来替换锚点的像素,也就是用区域内的像素最大的值代替区域内锚点的值,所谓锚点,就是区域的中心点。
我们考虑最简单的区域,一个3×3的正方形区域,锚点就是正方形区域的中心点,假设我们有下图中这个一维像素数组,
对于图中黄色区域,由于其中的最大值为255,所以其锚点处(红色数字)由9变为255。
当所有的都执行完该操作之后,生成的图像如下:
我们以一幅图像为例,来直观的看一下执行膨胀前后的操作:
我们发现,经过膨胀操作,黑色变得更瘦了,我们可以理解为白色膨胀了。
讲完了原理,我们来讲一下API
void dilate(
InputArray src,
OutputArray dst,
InputArray kernel,
Point anchor = Point(-1,-1),
int iterations = 1,
int borderType = BORDER_CONSTANT,
const Scalar& borderValue = morphologyDefaultBorderValue()
);
函数参数含义如下:
(1)InputArray类型的src,输入图像。通道数可以任意,但深度应为CV_8U、CV_16U、CV_16S、CV_32F或CV_64F之一。。
(2)OutputArray类型的dst,即目标图像,与输入图像有相同的尺寸和类型。
(3)InputArray类型的kernel,用于膨胀的结构元素;如果elemenat=Mat(),则使用3 x 3矩形结构元素。可以使用getStructuringElement创建内核。
(4)Point类型的anchor:锚定在元素中的位置;默认值(-1,-1)表示锚定在元素中心。。
(5)int类型的iterations:应用膨胀的次数。。
(6)int类型的borderType:像素外推方法,参见cv::BorderTypes。
(7)Scalar类型的borderValue:恒定边框时的边框值。
一般来说,我们只需要设置前三个参数,后面的参数默认即可。
#include
#include
using namespace std;
using namespace cv;
int main()
{
Mat src, dst;
src = imread("E:/image/girl.png");
if (!src.data)
{
cout << "could not load image !";
return -1;
}
imshow("src", src);
Mat kernel = getStructuringElement(MORPH_RECT, Size(3,3), Point(-1,-1));
dilate(src, dst, kernel);
imshow("dilate-src", dst);
waitKey(0);
return 0;
}
前面我们讲到,腐蚀就是计算B覆盖下A的最小像素值用来替换锚点的像素。我们要使用像素最小值,来替换锚点的像素,也就是用区域内的像素最小的值代替区域内锚点的值,所谓锚点,就是区域的中心点。
我们考虑最简单的区域,一个3×3的正方形区域,锚点就是正方形区域的中心点,假设我们有下图中这个一维像素数组,
对于图中黄色区域,由于其中的最大值为1,所以其锚点处(红色数字)由9变为1。
当所有的都执行完该操作之后,生成的图像如下:
我们以一幅图像为例,来直观的看一下执行腐蚀前后的操作:、
通过对比,我们发现,就是黑色的区域变胖了,我们考虑一下腐蚀,比如浓硫酸的腐蚀,越腐蚀,黑色的部分就越多,所以腐蚀就是深色越来越浓,越来越多。
1.API
void erode(
InputArray src,
OutputArray dst,
InputArray kernel,
Point anchor = Point(-1,-1),
int iterations = 1,
int borderType = BORDER_CONSTANT,
const Scalar& borderValue = morphologyDefaultBorderValue()
);
函数参数含义如下:
(1)InputArray类型的src,输入图像。该函数对通道是独立处理的,且可以处理任意通道数的图片,但需要注意,待处理的图片深度应该为CV_8U, CV_16U, CV_16S, CV_32F 以及 CV_64F之一。
(2)OutputArray类型的dst,即目标图像,与输入图像有相同的尺寸和类型。
(3)int类型的d,滤波过程中使用的每个像素邻域的直径。如果是非正的,则从sigmaSpace计算。
(4)double类型的sigmaColor ,颜色空间中过滤器sigma。参数值越大,意味着像素邻域(参见sigmaSpace)中的更多颜色将混合在一起,从而产生更大的半等色区域。
(5)double类型的sigmaSpace,在坐标空间中过滤器sigma。参数值越大,意味着更远的像素将相互影响,只要它们的颜色足够接近(参见sigmaColor)。当d大于0时,它指定邻域大小,而不考虑sigmaSpace。否则,d与sigmaSpace成比例。
(6)int类型的borderType,用于在图像外部外推像素的边框模式,具体请参见cv::BorderTypes。
2.代码展示
#include
#include
using namespace std;
using namespace cv;
int main()
{
Mat src, dst;
src = imread("E:/image/girl.png");
if (!src.data)
{
cout << "could not load image !";
return -1;
}
imshow("src", src);
Mat kernel = getStructuringElement(MORPH_RECT, Size(3,3), Point(-1,-1));
erode(src, dst, kernel);
imshow("erode-src", dst);
waitKey(0);
return 0;
}
3.执行结果
好啦今天的内容就讲到这里啦,希望大家能够多多练习,才能真正学懂啊!