OpenCV 4.11.0
开源计算机视觉库
加载中…
搜索中…
无匹配项
更多形态学变换

上一篇教程: 腐蚀和膨胀
下一篇教程: 击中-击不中

原作者Ana Huamán
兼容性OpenCV >= 3.0

目标

在本教程中,您将学习如何

  • 使用 OpenCV 函数 cv::morphologyEx 应用形态学变换,例如
    • 开运算
    • 闭运算
    • 形态梯度
    • 顶帽
    • 黑帽

理论

注意
下面的解释来自 Bradski 和 Kaehler 合著的学习 OpenCV 一书。

在上一篇教程中,我们介绍了两种基本的形态学运算:

  • 腐蚀
  • 膨胀

基于这两种运算,我们可以对图像进行更复杂的变换。这里我们简要讨论 OpenCV 提供的 5 种运算:

开运算

  • 它是先对图像进行腐蚀,然后进行膨胀得到的。

    \[dst = open( src, element) = dilate( erode( src, element ) )\]

  • 用于去除小物体(假设物体在黑暗的前景中是明亮的)。
  • 例如,查看下面的示例。左图是原图,右图是在应用开运算后的结果。我们可以观察到,小点消失了。

闭运算

  • 它是先对图像进行膨胀,然后进行腐蚀得到的。

    \[dst = close( src, element ) = erode( dilate( src, element ) )\]

  • 用于去除小孔(暗区)。

形态梯度

  • 它是图像膨胀和腐蚀之间的差值。

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

  • 它可用于查找物体的轮廓,如下所示

顶帽

  • 它是输入图像与其开运算之间的差值。

    \[dst = tophat( src, element ) = src - open( src, element )\]

黑帽

  • 它是闭运算与其输入图像之间的差值。

    \[dst = blackhat( src, element ) = close( src, element ) - src\]

代码

说明

  1. 让我们检查C++程序的总体结构
    • 加载图像
    • 创建一个窗口来显示形态学运算的结果
    • 创建三个轨迹条供用户输入参数
      • 第一个轨迹条 **算子** 返回要使用的形态学运算类型 (**morph_operator**)。
        createTrackbar("算子:\n 0: 开运算 - 1: 闭运算 \n 2: 梯度 - 3: 顶帽 \n 4: 黑帽", window_name, &morph_operator, max_operator, Morphology_Operations );
      • 第二个轨迹条 **元素** 返回 **morph_elem**,它指示我们的内核是什么样的结构
        createTrackbar( "元素:\n 0: 矩形 - 1: 十字形 - 2: 椭圆形", window_name,
        &morph_elem, max_elem,
        Morphology_Operations );
      • 最后一个轨迹条 **内核大小** 返回要使用的内核大小 (**morph_size**)
        createTrackbar( "内核大小:\n 2n +1", window_name,
        &morph_size, max_kernel_size,
        Morphology_Operations );
    • 每次我们移动任何滑块时,用户的函数 **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 );
      }

      我们可以观察到执行形态学变换的关键函数是 cv::morphologyEx。在这个例子中,我们使用四个参数(其余参数使用默认值)

      • **src**: 源(输入)图像
      • **dst**: 输出图像
      • **operation**: 要执行的形态学变换类型。请注意,我们有5个备选方案

        • 开运算: MORPH_OPEN : 2
        • 闭运算: MORPH_CLOSE: 3
        • 梯度: MORPH_GRADIENT: 4
        • 顶帽: MORPH_TOPHAT: 5
        • 黑帽: MORPH_BLACKHAT: 6

        正如你所看到的,这些值范围是 <2-6>,这就是为什么我们将轨迹条输入的值加上 (+2) 的原因

        int operation = morph_operator + 2;
      • **element**: 要使用的内核。我们使用函数 cv::getStructuringElement 来定义我们自己的结构。

结果

  • 编译上述代码后,我们可以执行它,并将图像路径作为参数提供。使用图像:**baboon.png** 的结果
  • 这里有两张显示窗口的快照。第一张图片显示使用十字形内核的 **开运算** 算子后的输出。第二张图片(右侧)显示使用椭圆形内核的 **黑帽** 算子的结果。