【 imgproc 模块. 图像处理】腐蚀与膨胀(Eroding and Dilating)

一、形态学操作

  • 简单来讲,形态学操作就是基于形状的一系列图像处理操作。通过将结构元素 作用于输入图像来产生输出图像。

  • 最基本的形态学操作有两种:腐蚀与膨胀(Erosion 与 Dilation)。 主要应用有:

    • 消除噪声
    • 分割(isolate)独立的图像元素,以及连接(join)相邻的元素。
    • 寻找图像中的明显的极大值区域或极小值区域。
  • 教程中主要通过以下图像讨论膨胀与腐蚀操作(注:图像中的字母为黑色,背景为白色,而不是一般意义的背景为黑色,前景为白色):

    Original image

二、膨胀

 

  • 此操作将图像 A 与任意形状的内核 (B),通常为正方形或圆形,进行卷积。

  • 内核 B 有一个可定义的 锚点, 通常定义为内核中心点。

  • 进行膨胀操作时,将内核 B 划过图像,将内核 B 覆盖区域的最大相素值提取,并代替锚点位置的相素。显然,这一最大化操作将会导致图像中的亮区开始”扩展” (因此有了术语膨胀 dilation )。对上图采用膨胀操作我们得到:

    Dilation result - Theory example

 

背景(白色)膨胀,而黑色字母缩小了。如果对图像取反,再膨胀,字母就会变大(膨胀)。

    API:

@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 #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() );

三、腐蚀

 

  • 腐蚀在形态学操作家族里是膨胀操作的孪生姐妹。它提取的是内核覆盖下的相素最小值。

  • 进行腐蚀操作时,将内核 B 划过图像,将内核 B 覆盖区域的最小相素值提取,并代替锚点位置的相素。

  • 以与膨胀相同的图像作为样本,我们使用腐蚀操作。从下面的结果图我们看到亮区(背景)变细,而黑色区域(字母)则变大了。

    Erosion result - Theory example

  API:

@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 #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() );

四、opencv例程

#include"stdafx.h"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "highgui.h"
#include <stdlib.h>
#include <stdio.h>

using namespace cv;

/// 全局变量
Mat src, erosion_dst, dilation_dst;

int erosion_elem = 0;
int erosion_size = 0;
int dilation_elem = 0;
int dilation_size = 0;
int const max_elem = 2;
int const max_kernel_size = 21;

/** Function Headers */
void Erosion(int, void*);
void Dilation(int, void*);

/** @function main */
int main(int argc, char** argv)
{
    /// Load 图像
    src = imread("膨胀腐蚀例图.png"); //载入图片

    if (!src.data)  //判断图像数据是否存在
    {
        return -1;
    }

    /// 创建显示窗口
    namedWindow("Erosion Demo", CV_WINDOW_NORMAL);
    namedWindow("Dilation Demo", CV_WINDOW_NORMAL);
    cvMoveWindow("Dilation Demo", src.cols, 0);//将显示窗口左上角移动到显示屏上指定的位置

    /// 创建腐蚀 Trackbar
    /*int createTrackbar(const String& trackbarname, const String& winname,
                              int* value, int count,
                              TrackbarCallback onChange = 0,
                              void* userdata = 0);
参数1:滑动条的名称。
参数2:窗口的名称,就是说这个创建的滑动条所要依附到哪个窗口上。
参数3:表示滑块的位置。在创建时,滑块的初始位置的值就是该指针所指向地址(理解为一个变量)当前的值。
参数4:表示滑块可以滑到的最大值位置。滑块的最小值始终为0。
参数5:TrackbarCallback类型的onChange,它有默认值为0。这是一个指向回调函数的指针,每次滑块位置改变时,这个函数都会进行回调。并且这个函数的原型必须为  void XXXXX(int, void*);
参数6:void*类型的userdata,它也有默认值为0。这个参数是用户传给回调函数的数据,用来处理滑动条的调用。如果使用的第3个参数value实参是全局变量的话,完全可以不用去管这个userdata参数。
*/
    createTrackbar("Element:\n 0: Rect \n 1: Cross \n 2: Ellipse", "Erosion Demo",
        &erosion_elem, max_elem,
        Erosion);
    
    createTrackbar("Kernel size:\n 2n +1", "Erosion Demo",
        &erosion_size, max_kernel_size,
        Erosion);

    /// 创建膨胀 Trackbar
    createTrackbar("Element:\n 0: Rect \n 1: Cross \n 2: Ellipse", "Dilation Demo",
        &dilation_elem, max_elem,
        Dilation);

    createTrackbar("Kernel size:\n 2n +1", "Dilation Demo",
        &dilation_size, max_kernel_size,
        Dilation);

    /// Default start
    Erosion(0, 0);
    Dilation(0, 0);

    waitKey(0);
    return 0;
}

/**  @function Erosion  */
void Erosion(int, void*)
{
    int erosion_type;
    if (erosion_elem == 0) { erosion_type = MORPH_RECT; }
    else if (erosion_elem == 1) { erosion_type = MORPH_CROSS; }
    else if (erosion_elem == 2) { erosion_type = MORPH_ELLIPSE; }

    Mat element = getStructuringElement(erosion_type,
        Size(2 * erosion_size + 1, 2 * erosion_size + 1),
        Point(erosion_size, erosion_size));

    /// 腐蚀操作
    erode(src, erosion_dst, element);
    imshow("Erosion Demo", erosion_dst);
}

/** @function Dilation */
void Dilation(int, void*)
{
    int dilation_type;
    if (dilation_elem == 0) { dilation_type = MORPH_RECT; }
    else if (dilation_elem == 1) { dilation_type = MORPH_CROSS; }
    else if (dilation_elem == 2) { dilation_type = MORPH_ELLIPSE; }

    Mat element = getStructuringElement(dilation_type,
        Size(2 * dilation_size + 1, 2 * dilation_size + 1),
        Point(dilation_size, dilation_size));
    /*这个函数的第一个参数表示内核的形状,有三种形状可以选择。
    矩形:MORPH_RECT;
    交叉形:MORPH_CORSS;
    椭圆形:MORPH_ELLIPSE;
    第二和第三个参数分别是内核的尺寸以及锚点的位置。一般在调用erode以及dilate函数之前,先定义一个Mat类型的变量来获得getStructuringElement函数的返回值。对于锚点的位置,有默认值Point(-1,-1),表示锚点位于中心点。element形状唯一依赖锚点位置,其他情况下,锚点只是影响了形态学运算结果的偏移。
    */
    ///膨胀操作
    dilate(src, dilation_dst, element);
    imshow("Dilation Demo", dilation_dst);
}

 

posted @ 2018-12-05 15:54  鸡鸣昧旦  阅读(621)  评论(0编辑  收藏  举报