【opencv学习笔记】011之基本形态学操作(膨胀与腐蚀)

目录

一、前言

二、形态学操作

1、什么是形态学操作

2、形态学操作的分类

三、OpenCV中的基本形态学操作

0、核生成的API

1、膨胀

1.API

2.代码展示

3.执行结果

扫描二维码关注公众号,回复: 9258698 查看本文章

2、腐蚀


一、前言

继续填坑。

如果想看其他有关于OpenCV学习方法介绍、学习教程、代码实战、常见报错及解决方案等相关内容,可以直接看我的OpenCV分类:

【OpenCV系列】:https://blog.csdn.net/shuiyixin/article/category/7581855

如果你想了解更多有关于计算机视觉、OpenCV、机器学习、深度学习等相关技术的内容,想与更多大佬一起沟通,那就扫描下方二维码加入我们吧!

二、形态学操作

1、什么是形态学操作

形态学操作本身是图像处理要研究的内容,而计算机视觉要实现相关功能,也要实现图像的处理。在图像处理技术中,有一些的操作会对图像的形态发生改变,这些操作一般称之为形态学操作。讲的再专业一些:

图像形态学操作是基于形状的一系列图像处理操作的合集,主要是基于集合论基础上的形态学数学。

2、形态学操作的分类

了解了什么是形态学操作,我们再来了解一下常用的几个形态学操作:

首先是两个基本操作

(1)膨胀:跟卷积操作类似,假设有图像A和结构元素B,结构元素B在A上面移动,其中B定义其中心为锚点,计算B覆盖下A的最大像素值用来替换锚点的像素,其中B作为结构体可以是任意形状。

(2)腐蚀:腐蚀跟膨胀操作的过程类似,唯一不同的是以最小值替换锚点重叠下图像的像素值。

其次基于基本操作的操作

(1)开操作:先腐蚀后膨胀,可以去掉小的对象。

(2)闭操作:先膨胀后腐蚀,可以填充小对象。

(3)形态学梯度:膨胀减去腐蚀。

(4)顶帽:顶帽是原图像与开操作图像之间的差值图像。

(5)黑帽:黑帽是闭操作图像与原图像之间的差值图像。

 

三、OpenCV中的基本形态学操作

可能大家对于定义还是比较模糊,没有直观的感受,接下来,我就以具体的例子,带领大家一起来了解膨胀与腐蚀。

在讲之前,我们先来了解一下核。

0、核生成的API

在形态学中,因为要涉及到区域像素操作,我们就要设计一个核,在核范围内对像素进行操作。所以我们需要创建一个核,在这里,我们用到一个新的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)的填充椭圆。

 

1、膨胀

前面我们讲到,膨胀就是计算B覆盖下A的最大像素值用来替换锚点的像素。我们还记得,像素范围是在[0-255],对于彩图来说,是一个六位的16进制数,如123456,其中12表示前两位,代表红色,34表示中间两位,代表绿色,56表示最后两位,代表蓝色。如果这6位都是最大,即为FFFFFF(255,255,255),图像的水印就是白色,如下图

纯白色水印

如果这六位都是最小,即000000(0,0,0),图像水印就是纯黑色,如下图:

纯白色水印

我们要使用像素最大值,来替换锚点的像素,也就是用区域内的像素最大的值代替区域内锚点的值,所谓锚点,就是区域的中心点。

我们考虑最简单的区域,一个3×3的正方形区域,锚点就是正方形区域的中心点,假设我们有下图中这个一维像素数组,

对于图中黄色区域,由于其中的最大值为255,所以其锚点处(红色数字)由9变为255。

当所有的都执行完该操作之后,生成的图像如下:

膨胀

 我们以一幅图像为例,来直观的看一下执行膨胀前后的操作:

原图与膨胀后的操作

我们发现,经过膨胀操作,黑色变得更瘦了,我们可以理解为白色膨胀了。

 

1.API

讲完了原理,我们来讲一下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:恒定边框时的边框值。

一般来说,我们只需要设置前三个参数,后面的参数默认即可。

2.代码展示

#include<opencv2\opencv.hpp>
#include<iostream>

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;
}

3.执行结果

原图
膨胀操作

2、腐蚀

前面我们讲到,腐蚀就是计算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<opencv2\opencv.hpp>
#include<iostream>

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.执行结果

腐蚀后的图像

 

好啦今天的内容就讲到这里啦,希望大家能够多多练习,才能真正学懂啊!

发布了250 篇原创文章 · 获赞 504 · 访问量 51万+

猜你喜欢

转载自blog.csdn.net/shuiyixin/article/details/104354806