zoukankan      html  css  js  c++  java
  • 【 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:
     0: Rect 
     1: Cross 
     2: Ellipse", "Erosion Demo",
            &erosion_elem, max_elem,
            Erosion);
        
        createTrackbar("Kernel size:
     2n +1", "Erosion Demo",
            &erosion_size, max_kernel_size,
            Erosion);
    
        /// 创建膨胀 Trackbar
        createTrackbar("Element:
     0: Rect 
     1: Cross 
     2: Ellipse", "Dilation Demo",
            &dilation_elem, max_elem,
            Dilation);
    
        createTrackbar("Kernel size:
     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);
    }
    One day,I will say "I did it"
  • 相关阅读:
    Swift网络库Alamofire的导入
    iOS书摘之Objective-C编程之道 iOS设计模式解析
    Crash日志分析
    自动布局库--Masonry使用
    Xcode Ghost
    Xcode8-beat升级需谨慎
    UIView剖析之Draw、Size、Layout方法
    Xcode警告忽略
    属性(property)与成员变量(ivar)
    sql server分页存储过程
  • 原文地址:https://www.cnblogs.com/Vince-Wu/p/10071431.html
Copyright © 2011-2022 走看看