• 【 imgproc 模块. 图像处理】形态学变化


    一、更多的形态学变化

        包括开运算 (Opening)、闭运算 (Closing)、形态梯度 (Morphological Gradient)、顶帽 (Top Hat)、黑帽(Black Hat)。具体可参考《数字图像处理 第三版》(冈萨雷斯)——第九章 形态学图像处理注:具体原理都是一些数学计算公式、方法,目前只大概了解,后面可具体研读。

    二、开运算

    (1)教程中的解释:

    • 开运算是通过先对图像腐蚀再膨胀实现的。

      dst = open( src, element) = dilate( erode( src, element ) )

    • 能够排除小团块物体(假设物体较背景明亮)

    • 请看下面,左图是原图像,右图是采用开运算转换之后的结果图。 观察发现字母拐弯处的白色空间消失。

      Opening

    (2)资料整理

            开运算和闭运算都由腐蚀和膨胀复合而成, 开运算是先腐蚀后膨胀, 而闭运算是先膨胀后腐蚀。膨胀:亮区扩大;腐蚀:亮区缩小。

                  

           一般来说, 开运算可以使图像的轮廓变得光滑, 还能使狭窄的连接断开和消除细毛刺。 
    如图8.11所示, 开运算断开了团中两个小区域间两个像素宽的连接〈断开了狭窄连接〉,并且去除了右侧物体上部突出的一个小于结构元素的2×2的区域〈去除细小毛刺〉: 但与腐蚀不同的是, 图像大的轮廓并没有发生整体的收缩, 物体位置也没有发生任何变化。 

     (3)opencv代码实现

    #include"stdafx.h"
    #include<opencv2/opencv.hpp>
    int open_value = 0;
    int open_max = 5;
    int morph_elem = 0;
    int max_elem = 2;
    cv::Mat src,dst;
    void openOperator(int,void*);
    
    int main(int argc, char** argv) {
        src = cv::imread("lena512color.tiff");
        if (src.empty()) {
            printf("Image load failed...");
            return -1;
        }
        cv::namedWindow("src", CV_WINDOW_NORMAL);
        cv::createTrackbar("Opening_value:","src", &open_value, open_max, openOperator);
        cv::createTrackbar("Element:
     0: Rect - 1: Cross - 2: Ellipse", "src",&morph_elem, max_elem,openOperator);
        openOperator(0, 0); //这句注释掉时,刚开始运行时若不移动滑动条则图片不会显示
        cvWaitKey(0);
        return 0;
    }
    
    void openOperator(int, void*) {
        /*getStructuringElement(int shape, Size ksize, Point anchor = Point(-1,-1));
        @用法:返回一个特定形状(shape),大小(size),及锚点(anchor)的核,锚点为(-1,-1)时默认为中心
        @参数:int shape     MORPH_RECT    = 0, MORPH_CROSS   = 1, MORPH_ELLIPSE = 2 
        */
        cv::Mat element = cv::getStructuringElement(morph_elem, cv::Size(2 * open_value + 1, 2 * open_value + 1), cv::Point(open_value, open_value));
        morphologyEx(src, dst, cv::MORPH_OPEN, element);//element 为输入的结构元,用于卷积的矩阵
        /*@API:void morphologyEx( InputArray src, OutputArray dst,
                                    int op, InputArray kernel,
                                    Point anchor = Point(-1,-1), int iterations = 1,
                                    int borderType = BORDER_CONSTANT,
                                    const Scalar& borderValue = morphologyDefaultBorderValue() );   
          @用法:
          @参数:op形态学操作类型
        MORPH_ERODE    = 0,  MORPH_DILATE   = 1,  MORPH_OPEN     = 2,  MORPH_CLOSE    = 3,
              MORPH_GRADIENT = 4, MORPH_TOPHAT   = 5, MORPH_BLACKHAT = 6,  MORPH_HITMISS  = 7
          @参数:InputArray kernel,用于进行形态学操作的核,可以用getStructuringElement(int shape, Size ksize, Point anchor = Point(-1,-1));获取
          @参数:anchor,锚点,核的锚点位置,默认(-1,-1)则为中心
          @参数:iterations,腐蚀、膨胀次数次数
          @参数:borderType,参数外推方法,
          ...具体用到再查*/  
        cv::imshow("src", dst);
    }

    二、闭运算

    (1)教程中的解释:

    • 闭运算是通过先对图像膨胀再腐蚀实现的。

      dst = close( src, element ) = erode( dilate( src, element ) )

    能够排除小型黑洞(黑色区域)。

    Closing example

    (2)相关资料整理:

    闭运算同样可以使轮廓变得光滑, 但与开运算相反, 它通常能够弥合狭窄的间断, 填充小的孔洞。

     (3)opencv实现代码:类似开运算

    三、形态梯度

    • 膨胀图与腐蚀图之差

      dst = morph_{grad}( src, element ) = dilate( src, element ) - erode( src, element )

    • 能够保留物体的边缘轮廓,如下所示:

      Gradient

    四、顶帽

    • 原图像与开运算结果图之差
    • dst = tophat( src, element ) = src - open( src, element )

         Top Hat

    五、黑帽

    • 闭运算结果图与原图像之差

      dst = blackhat( src, element ) = close( src, element ) - src

      Black Hat

    六、测试代码(官方)

    #include "opencv2/imgproc/imgproc.hpp"
    #include "opencv2/highgui/highgui.hpp"
    #include <stdlib.h>
    #include <stdio.h>
    
    using namespace cv;
    
    /// 全局变量
    Mat src, dst;
    
    int morph_elem = 0;
    int morph_size = 0;
    int morph_operator = 0;
    int const max_operator = 4;
    int const max_elem = 2;
    int const max_kernel_size = 21;
    
    char* window_name = "Morphology Transformations Demo";
    
    /** 回调函数申明 */
    void Morphology_Operations( int, void* );
    
    /** @函数 main */
    int main( int argc, char** argv )
    {
      /// 装载图像
      src = imread( argv[1] );
    
      if( !src.data )
      { return -1; }
    
     /// 创建显示窗口
     namedWindow( window_name, CV_WINDOW_AUTOSIZE );
    
     /// 创建选择具体操作的 trackbar
     createTrackbar("Operator:
     0: Opening - 1: Closing 
     2: Gradient - 3: Top Hat 
     4: Black Hat", window_name, &morph_operator, max_operator, Morphology_Operations );
    
     /// 创建选择内核形状的 trackbar
     createTrackbar( "Element:
     0: Rect - 1: Cross - 2: Ellipse", window_name,
                     &morph_elem, max_elem,
                     Morphology_Operations );
    
     /// 创建选择内核大小的 trackbar
     createTrackbar( "Kernel size:
     2n +1", window_name,
                     &morph_size, max_kernel_size,
                     Morphology_Operations );
    
     /// 启动使用默认值
     Morphology_Operations( 0, 0 );
    
     waitKey(0);
     return 0;
     }
    
     /**
      * @函数 Morphology_Operations
      */
    void Morphology_Operations( int, void* )
    {
      // 由于 MORPH_X的取值范围是: 2,3,4,5 和 6
      int operation = morph_operator + 2;
    
      Mat element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) );
    
      /// 运行指定形态学操作
      morphologyEx( src, dst, operation, element );
      imshow( window_name, dst );
      }
    One day,I will say "I did it"
  • 相关阅读:
    EntityFramework 启用迁移 EnableMigrations 报异常 "No context type was found in the assembly"
    JAVA 访问FTP服务器示例(2)
    NuGet Package Manager 更新错误解决办法
    JAVA 访问FTP服务器示例(1)
    RemoteAttribute 的使用问题
    诡异的 javascript 变量
    javascript apply用法
    Babun 中文乱码
    GSM呼叫过程
    转站博客园
  • 原文地址:https://www.cnblogs.com/Vince-Wu/p/10076240.html
Copyright © 2020-2023  润新知