互联网@时事传播图像处理

OpenCV图像处理系列八 --- 腐蚀与膨胀

2019-04-22  本文已影响13人  307656af5a04

今天,我们一起来学习图像形态学操作中两种最基本的形态学操作,即腐蚀与膨胀。

一、理论

数学形态学(Mathematical morphology) 是一门建立在格论和拓扑学基础之上的图像分析学科,是数学形态学图像处理的基本理论。其基本的运算包括:腐蚀和膨胀、开运算和闭运算、骨架抽取、极限腐蚀、击中击不中变换、形态学梯度、Top-hat变换、颗粒分析、流域变换等。

腐蚀与膨胀主要实现以下功能:

1、腐蚀

腐蚀对图像求局部最小值;腐蚀操作就是将图像(或图像的一部分区域,我们称之为A)与卷积核(我们称之为B)进行卷积。

核可以是任何的形状和大小,它拥有一个单独定义出来的参考点,我们称其为锚点。多数情况下,核是一个小的中间带有参考点和实心正方形或者圆盘,其实,我们可以把核视为模板或者掩码。

1)腐蚀的数学表达式

腐蚀的数学表达式

2)腐蚀效果演示

腐蚀效果演示

3)腐蚀的作用:

2、膨胀

膨胀对图像求局部的最大值;核B与图形卷积,即计算核B覆盖的区域的像素点的最大值,并把这个最大值赋值给参考点指定的像素;这样就会使图像中的高亮区域逐渐增长。

核可以是任何的形状和大小,它拥有一个单独定义出来的参考点,我们称其为锚点。多数情况下,核是一个小的中间带有参考点和实心正方形或者圆盘,其实,我们可以把核视为模板或者掩码。

1)膨胀的数学表达式

膨胀的数学表达式 膨胀

膨胀的作用:

小结:

可以看做膨胀是将白色区域扩大,腐蚀是将黑色区域扩大。

二、OpenCV腐蚀与膨胀API函数详解

1、腐蚀

1)函数原型:

void erode(InputArray src, 
    OutputArray dst, 
    InputArray kernel,
    Point anchor = Point(-1, -1), 
    int iterations = 1,
    int borderType = BORDER_CONSTANT,
    const Scalar& borderValue = 
    morphologyDefaultBorderValue());

2)函数功能:

用指定的卷积核腐蚀图像,使用像素邻域内的局部极小运算符来腐蚀一张图片,从src输入,由dst输出,支持就地(in-place)操作。

3)参数详解:

第三个参数一般用getStructuringElement()函数获取卷积核的大小;getStructuringElement函数会返回指定形状和尺寸的结构元素(内核矩阵)。

其中,getStructuringElement函数的第一个参数表示内核的形状,我们可以选择如下三种形状之一:

而getStructuringElement函数的第二和第三个参数分别是内核的尺寸以及锚点的位置。

我们一般在调用erode以及dilate函数之前,先定义一个Mat类型的变量来获得getStructuringElement函数的返回值。对于锚点的位置,有默认值Point(-1, -1),表示锚点位于中心;并且需要注意,十字形的element形状唯一依赖于锚点的位置;而在其他情况下,锚点只是影响了形态学运算结果的偏移。

4)实例:

#include <iostream>
#include <opencv2/imgproc.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>

using namespace std;
using namespace cv;

int main()
{
    //载入原图 
    Mat image = imread("lena.png");

    if (image.empty())
    {
        printf("image error!");
        return -1;
    }

    //创建窗口 
    namedWindow("【原图】腐蚀操作");
    namedWindow("【效果图】腐蚀操作");

    //显示原图
    imshow("【原图】腐蚀操作", image);


    //获取自定义核
    Mat element = getStructuringElement(
        MORPH_RECT, 
        Size(15, 15));

    Mat out;

    //进行腐蚀操作
    erode(image, out, element);

    //显示效果图
    imshow("【效果图】腐蚀操作", out);

    waitKey(0);

    return 0;
}

实验结果:

卷积核为15腐蚀的实验结果

2、膨胀

1)函数原型:

void dilate(InputArray src,
    OutputArray dst,
    InputArray kernel,
    Point anchor = Point(-1, -1),
    int iterations = 1,
    int borderType = BORDER_CONSTANT,
    const Scalar& borderValue =
    morphologyDefaultBorderValue());

2)函数功能:
使用像素邻域内的局部极大运算符来膨胀一张图片,从src输入,由dst输出,支持就地(in-place)操作。

3)参数详解:

4)实例:

int main()
{

    //载入原图 
    Mat image = imread("3.png");

    if (image.empty())
    {
        printf("image error!");
        return -1;
    }

    //创建窗口 
    namedWindow("【原图】膨胀操作");
    namedWindow("【效果图】膨胀操作");

    //显示原图
    imshow("【原图】膨胀操作", image);

    //获取自定义核
    Mat element = getStructuringElement(
        MORPH_RECT, 
        Size(5, 5));

    Mat out;
    //进行膨胀操作
    dilate(image, out, element);

    //显示效果图
    imshow("【效果图】膨胀操作", out);

    waitKey(0);

    return 0;
}

实验结果:

卷积核为5膨胀的实验结果

三、综合实例

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

using namespace std;
using namespace cv;

//原始图和效果图
Mat g_srcImage, g_dstImage;

//0表示腐蚀erode, 1表示膨胀dilate
int g_nTrackbarNumer = 0;

//结构元素(内核矩阵)的尺寸
int g_nStructElementSize = 3; 

//膨胀和腐蚀的处理函数
void Process();

//回调函数
void on_TrackbarNumChange(int, void *);

//回调函数
void on_ElementSizeChange(int, void *);

int main()
{
    //载入原图
    g_srcImage = imread("lena.png");

    if (!g_srcImage.data) 
    { 
        printf("image error!");
        return -1; 
    }

    //显示原始图
    namedWindow("【原始图】");
    imshow("【原始图】", g_srcImage);

    //进行初次腐蚀操作并显示效果图
    namedWindow("【效果图】");

    //获取自定义核
    Mat element = getStructuringElement(
        MORPH_RECT, 
        Size(2 * g_nStructElementSize + 1, 
            2 * g_nStructElementSize + 1), 
        Point(g_nStructElementSize, 
            g_nStructElementSize));
    
    erode(g_srcImage, g_dstImage, element);
    
    imshow("【效果图】", g_dstImage);

    //创建轨迹条
    createTrackbar("腐蚀/膨胀",
        "【效果图】", 
        &g_nTrackbarNumer, 
        1, 
        on_TrackbarNumChange);

    createTrackbar("内核尺寸", 
        "【效果图】", 
        &g_nStructElementSize, 
        21, 
        on_ElementSizeChange);

    waitKey(0);
    return 0;
}

//进行自定义的腐蚀和膨胀操作
void Process()
{
    //获取自定义核
    Mat element = getStructuringElement(
        MORPH_RECT, 
        Size(2 * g_nStructElementSize + 1, 
            2 * g_nStructElementSize + 1), 
        Point(g_nStructElementSize, 
            g_nStructElementSize));

    //进行腐蚀或膨胀操作
    if (g_nTrackbarNumer == 0) {
        erode(g_srcImage, g_dstImage, element);
    }
    else {
        dilate(g_srcImage, g_dstImage, element);
    }

    //显示效果图
    imshow("【效果图】", g_dstImage);
}

//腐蚀和膨胀之间切换开关的回调函数
void on_TrackbarNumChange(int, void *)
{
    //腐蚀和膨胀之间效果已经切换,
    //回调函数体内需调用一次Process函数,
    //使改变后的效果立即生效并显示出来
    Process();
}

//腐蚀和膨胀操作内核改变时的回调函数
void on_ElementSizeChange(int, void *)
{
    //内核尺寸已改变,回调函数体内需
    //调用一次Process函数,使改变后的
    //效果立即生效并显示出来
    Process();
}

实验结果:

用滑动条控制图像腐蚀膨胀以及内核大小

好了,今天OpenCV学到这里就结束了,喜欢的朋友可以给我点个赞哦!!!

上一篇下一篇

猜你喜欢

热点阅读