图像形态学中两种最基本的操作就是对图形的腐蚀和膨胀,可以说,形态学中的中高级操作都是建立在这两种操作之上。通过这两种基本的运算可以去除图像中的噪声,分割出独立的区域或者将两个区域连接在一起。
关于图像腐蚀和膨胀的概念,不严谨的简单理解是:经过腐蚀和膨胀操作后最终的效果是对图像中物体的边界进行一层一层的腐蚀和膨胀操作,这个边界包括内边界和外边界。
严谨的理解是这样的:图像的腐蚀和膨胀实际上是用某种形状的窗去遍历图像中的每一个元素,并用这个形状中的最大值或最小值做为锚点的值(锚点的概念可参考我的另一篇博文 https://blog.csdn.net/wenhao_ir/article/details/124173092)。若取的是最大值,则是膨胀操作,若取的是最小值,则是腐蚀操作。这里某种形状可以是十字形、菱形、矩形、X形等。这里我补充说明一下,其实所有的窗都是矩形的,那么怎样定义不同的形状呢?是这样操作的:通过把矩形窗中的元素置为1形成不同的形状。更详细的说明可见本文下面对函数getStructuringElement()参数shape的介绍。
OpenCV提供了函数erode()和函数dilate()分别用于图像形态学的腐蚀与膨胀操作,下面分别介绍。
函数dilate()的数学运算表达式如下:
其中(x’,y’)是窗中的元素坐标。
函数erode()的数学运算表达式如下:
其中(x’,y’)是窗中的元素坐标。
图像形态学的腐蚀操作函数erode()的原型如下:
void erode( InputArray src,
OutputArray dst,
InputArray kernel,
Point anchor = Point(-1,-1),
int iterations = 1,
int borderType = BORDER_CONSTANT,
const Scalar& borderValue = morphologyDefaultBorderValue() );
图像形态学的腐蚀操作函数dilate()的原型如下:
void dilate( InputArray src,
OutputArray dst,
InputArray kernel,
Point anchor = Point(-1,-1),
int iterations = 1,
int borderType = BORDER_CONSTANT,
const Scalar& borderValue = morphologyDefaultBorderValue() );
可见,两个函数的原型除了函数名不一样,其它都是一样的,所以我们就统一介绍两个函数参数的意义。
参数意义如下:
src—输入图像,通道数任意,数据深度只能为 CV_8U, CV_16U, CV_16S, CV_32F,CV_64F中的一种。每个通道将被单独处理。
ds—为输出图像,尺寸和数据类型与输入图像一致。
kernel—erode()使用某种形状的窗侵蚀一个图像,dilate()也使用某种形状的窗对图像进行膨胀。参数kernel就表示这个窗。显然这个窗越大,显然每次对图像的腐蚀或膨胀越多,反之亦然。有下面两种构造这个窗的方法。有下面两种构造这个窗的方法。
①使用函数getStructuringElement()来获取,函数getStructuringElement()的原型如下:
Mat getStructuringElement(int shape, Size ksize, Point anchor = Point(-1,-1));
函数getStructuringElement()的参数意义如下:
shape—窗的形状,MORPH_RECT为矩形,矩形中的每一个元素的值为1;MORPH_CROSS代表十字形结构,十字形的长和宽由ksize定,十字形上的元素值也为1;MORPH_ELLIPSE为椭圆,椭圆中的每一个元素的值也为1,椭圆内切于参数ksize定义的矩形大小。可以结合下面这个表更好理解。
下面上使用函数erode()和函数dilate()进行腐蚀和膨胀处理的示例代码:
代码中用到的图像下载链接:https://pan.baidu.com/s/1Acoq3mR2RK0KHtYBCtq9qg?pwd=708g
//博主微信/QQ 2487872782
//有问题可以联系博主交流
//有图像处理需求也可联系博主
//图像处理技术交流QQ群 271891601
//OpenCV版本:3.0
//VS版本:2013
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include<opencv2/imgcodecs/imgcodecs.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
int main()
{
//载入原图
Mat image = imread("F:/material/images/P0046-erode_dilate-02.bmp",0);
//显示原图
imshow("原图的灰度图", image);
//获取自定义核
Mat element = getStructuringElement(MORPH_RECT, Size(3, 3));
Mat out1, out2;
//进行膨胀操作
dilate(image, out1, element);
//进行腐蚀操作
erode(image, out2, element,cv::Point(-1,-1),2);
//显示效果图
imshow("膨胀操作效果图", out1);
imshow("腐蚀操作效果图", out2);
waitKey(0);
return 0;
}
代码运行结果如下图所示:
# 博主微信/QQ 2487872782
# 有问题可以联系博主交流
# 有图像处理需求也可联系博主
# 图像处理技术交流QQ群 271891601
# !/usr/bin/env python
# -*- coding: utf-8 -*-
# OpenCV的版本为4.1
import cv2 as cv
import numpy as np
A = np.zeros((9, 9), dtype='uint8')
A[3:6, 3:6] = 5
A[4, 4] = 9
structure1 = cv.getStructuringElement(cv.MORPH_RECT, (3, 3))
structure2 = cv.getStructuringElement(cv.MORPH_CROSS, (3, 3))
dilate_out1 = cv.dilate(A, structure1)
dilate_out2 = cv.dilate(A, structure2)
运行结果如下图所示:
从以上运行结果可以看出,膨胀操作的运算规则的确是我上面介绍的那样。为了避免大家来回滚动页面,我再将运算规则摘录如下:
图像的腐蚀和膨胀实际上是用某种形状的窗去遍历图像中的每一个元素,并用这个形状中的最大值或最小值做为锚点的值(锚点的概念可参考我的另一篇博文 https://blog.csdn.net/wenhao_ir/article/details/124173092)。若取的是最大值,则是膨胀操作,若取的是最小值,则是腐蚀操作。这里某种形状可以是十字形、菱形、矩形、X形等。这里我补充说明一下,其实所有的窗都是矩形的,那么怎样定义不同的形状呢?是这样操作的:通过把矩形窗中的元素置为1形成不同的形状。更详细的说明可见本文对函数getStructuringElement()参数shape的介绍。
函数dilate()的数学运算表达式如下:
其中(x’,y’)是窗中的元素坐标。
再来探究腐蚀操作。
探究腐蚀操作的示例代码如下:
运行结果如下:
知道了腐蚀和膨胀的具体运算过程后,我们便可以知道当参数shape取不同形状时,效果有什么区别。具体效果有什么不同,大家在理解以上运算过程后,便可以在脑海中想像了,这里博主就不再码字了。
文章出处登录后可见!