opencv——形态学基本操作(腐蚀与膨胀)

形态学操作

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

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

形态学操作的分类

两个基本操作:

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

基于基本操作的操作:

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

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

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

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

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

kernel生成API

在形态学中,因为要涉及到区域像素操作,我们就要设计一个核,在核范围内对像素进行操作。所以我们需要创建一个核,在这里,我们用到一个新的API:
getStructuringElement()

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的最大像素值用来替换锚点的像素

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

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

对于图中黄色区域,由于其中的最大值为255,所以其锚点处(红色数字)由9变为255。
在这里插入图片描述
当所有的都执行完该操作之后,生成的图像如下:
在这里插入图片描述
注意:图像的膨胀是基于原图的

如果膨胀一个点,替换值之后再做下一个点,那么整张图都是255


在这里插入图片描述
这个点是基于原图的9来进行膨胀的,而不是膨胀过后左上角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<opencv2\opencv.hpp>
#include<iostream>

using namespace std;
using namespace cv;

int main()
{
    
    
	Mat src, dst;
	src = imread("ur own path of pic ");
	if (!src.data)
	{
    
    
		cout << "could not load image !";
		return -1;
	}

	imshow("src", src);

	Mat kernel = getStructuringElement(MORPH_RECT, Size(7, 7), 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。

代码

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

using namespace std;
using namespace cv;

int main()
{
    
    
	Mat src, dst;
	src = imread("path");
	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;
}

效果

在这里插入图片描述
很明显的看到,细的线被腐蚀了

猜你喜欢

转载自blog.csdn.net/qq_28258885/article/details/112691425