二值图像处理腐蚀与膨胀

举报
Gere 发表于 2022/08/07 19:22:57 2022/08/07
【摘要】 本篇博客主要介绍使用OpenCV中的函数接口实现对一个图片的腐蚀或者膨胀,听起来有点像是对图像进行放大和缩小的意思,如果你也是这样认为,那我只能说你跟我一样肤浅!!在OpenCV中几乎所有的操作都是针对图像的像素点进行的,包括灰化,二值化,模糊化等,膨胀和腐蚀也是一样,都是针对传入图像的像素点进行操作的!!!膨胀:此操作将图像(A)与任意形状的内核 (B),通常为正方形或圆形,进行卷积。内核...

本篇博客主要介绍使用OpenCV中的函数接口实现对一个图片的腐蚀或者膨胀,听起来有点像是对图像进行放大和缩小的意思,如果你也是这样认为,那我只能说你跟我一样肤浅!!
在OpenCV中几乎所有的操作都是针对图像的像素点进行的,包括灰化,二值化,模糊化等,膨胀和腐蚀也是一样,都是针对传入图像的像素点进行操作的!!!

膨胀:
此操作将图像(A)与任意形状的内核 (B),通常为正方形或圆形,进行卷积。内核 B 有一个可定义的 锚点, 通常定义为内核中心点。进行膨胀操作时,将内核 B 划过图像,将内核 B 覆盖区域的最大相素值提取,并代替锚点位置的相素。显然,这一最大化操作将会导致图像中的亮区开始”扩展” (因此有了术语膨胀 dilation )。
这种操作会造成图像中像素值高的区域变大,而像素值小的区域变小,等一下看你一下效果你就知道了!!!

腐蚀:
跟膨胀操作造作的效果刚好相反。腐蚀在形态学操作家族里是膨胀操作的孪生姐妹。它提取的是内核覆盖下的相素最小值。进行腐蚀操作时,将内核 B 划过图像,将内核 B 覆盖区域的最小相素值提取,并代替锚点位置的相素。以与膨胀相同的图像作为样本,我们使用腐蚀操作。从下面的结果图我们看到亮区(背景)变细,而黑色区域(字母)则变大了。

下面看一下效果图:
膨胀:
这里写图片描述这里写图片描述

腐蚀:
这里写图片描述 这里写图片描述

我感觉GIF动画的效果还是很明显的,实际程序的运行效果跟膨胀/腐蚀的理论产生的效果一致!!!

下面看一下具体实现代码:

#include <iostream>
#include <opencv2\opencv.hpp>
#include <string>
using namespace cv;
using namespace std;
int dilateSize = 1;
int erodeSize = 1;
char * dilateBar = "dilate_KSize";
char * dilate_window = "Dilate";
char * erodeBar = "erode_KSize";
char * erode_window = "Erode";
Mat source, dilate_result, erode_result,dilate_element,erode_element;
void onDilateCallBack(int position,void* userdata) {
    if (position <= 0) {
        position = 1;
    }
    dilateSize = position;
    dilate_element = getStructuringElement(MORPH_RECT, Size(dilateSize, dilateSize));
    dilate(source, dilate_result, dilate_element);
    imshow(dilate_window, dilate_result);
}

void onErodeCallBack(int position, void* userdata) {
    if (position <= 0) {
        position = 1;
    }
    erodeSize = position;
    erode_element = getStructuringElement(MORPH_RECT, Size(erodeSize, erodeSize));
    erode(dilate_result, erode_result, erode_element);
    imshow(erode_window, erode_result);
}

int main() {

    source = imread("tw.jpg", IMREAD_COLOR);
    dilate_result = Mat(source.rows,source.cols,CV_8UC3);
    cvNamedWindow(dilate_window, CV_WINDOW_AUTOSIZE);
    createTrackbar(dilateBar, dilate_window, &dilateSize, 50, onDilateCallBack);
    onDilateCallBack(1, dilateBar);
    cvNamedWindow(erode_window, CV_WINDOW_AUTOSIZE);
    createTrackbar(erodeBar, erode_window, &erodeSize, 50, onErodeCallBack);
    onErodeCallBack(1, erodeBar);
    waitKey(0);
    return 0;
}

主要的代码就是两个函数:
膨胀:

dilate(source, dilate_result, dilate_element);

看一下函数的介绍:

** @brief Dilates an image by using a specific structuring element.

The function dilates the source image using the specified structuring element that determines the
shape of a pixel neighborhood over which the maximum is taken:
\f[\texttt{dst} (x,y) =  \max _{(x',y'):  \, \texttt{element} (x',y') \ne0 } \texttt{src} (x+x',y+y')\f]

The function supports the in-place mode. Dilation can be applied several ( iterations ) times. In
case of multi-channel images, each channel is processed independently.

@param src input image; the number of channels can be arbitrary, but the depth should be one of
CV_8U, CV_16U, CV_16S, CV_32F or CV_64F.
@param dst output image of the same size and type as src\`.
@param kernel structuring element used for dilation; if elemenat=Mat(), a 3 x 3 rectangular
structuring element is used. Kernel can be created using getStructuringElement
@param anchor position of the anchor within the element; default value (-1, -1) means that the
anchor is at the element center.
@param iterations number of times dilation is applied.
@param borderType pixel extrapolation method, see cv::BorderTypes
@param borderValue border value in case of a constant border
@sa  erode, morphologyEx, getStructuringElement
 */
CV_EXPORTS_W void dilate( InputArray src, OutputArray dst, InputArray kernel,
                          Point anchor = Point(-1,-1), int iterations = 1,
                          int borderType = BORDER_CONSTANT,
                          const Scalar& borderValue = morphologyDefaultBorderValue() );

在这里,我们只使用了3个参数,分别代表:输入图像、输出图像、内核尺寸,有兴趣的可以自行研究其他参数的作用!!

腐蚀:

erode(dilate_result, erode_result, erode_element);

函数的介绍:

/** @brief Erodes an image by using a specific structuring element.

The function erodes the source image using the specified structuring element that determines the
shape of a pixel neighborhood over which the minimum is taken:

\f[\texttt{dst} (x,y) =  \min _{(x',y'):  \, \texttt{element} (x',y') \ne0 } \texttt{src} (x+x',y+y')\f]

The function supports the in-place mode. Erosion can be applied several ( iterations ) times. In
case of multi-channel images, each channel is processed independently.

@param src input image; the number of channels can be arbitrary, but the depth should be one of
CV_8U, CV_16U, CV_16S, CV_32F or CV_64F.
@param dst output image of the same size and type as src.
@param kernel structuring element used for erosion; if `element=Mat()`, a `3 x 3` rectangular
structuring element is used. Kernel can be created using getStructuringElement.
@param anchor position of the anchor within the element; default value (-1, -1) means that the
anchor is at the element center.
@param iterations number of times erosion is applied.
@param borderType pixel extrapolation method, see cv::BorderTypes
@param borderValue border value in case of a constant border
@sa  dilate, morphologyEx, getStructuringElement
 */
CV_EXPORTS_W 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(膨胀)一样,就不介绍了!!!

在这里可能有的朋友就会想了,经过膨胀后的图片能不能用腐蚀的方法进行还原呢!答案是不能完全的还原,当使用的内核很小时,进过膨胀的图片可以适当的使用腐蚀进行还原,还原的图片跟原图相比在细节上回丢失很多信息,看一下实际的操作效果吧!!

图片原图:
这里写图片描述

内核为3,先对图片进行膨胀,再对膨胀后的图片进行腐蚀,实际运行图如下:
这里写图片描述

内核为10,先对图片进行膨胀,再对膨胀后的图片进行腐蚀,实际运行图如下:
这里写图片描述

可以看出,这种针对像素点的操作是不可逆的,即使可以还原回来,也会在丢失大量细节信息的(也不知道自己理解的对不对,如有不正确的地方,恳请大神指正)!!

有兴趣的朋友可以以关注我,遇到问题大家一起讨论一下!!

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。