【问题标题】:implementing erosion, dilation in C, C++在 C、C++ 中实现腐蚀、膨胀
【发布时间】:2010-12-01 03:52:05
【问题描述】:

我对如何在二值图像中进行膨胀有理论上的理解。

AFAIK,如果我的 SE(结构元素)是这个

0 1
1 1. 

在哪里。代表中心,我的图像(二进制是这个)

0 0 0 0 0
0 1 1 0 0
0 1 0 0 0
0 1 0 0 0
0 0 0 0 0

所以膨胀的结果是

0 1 1 0 0 
1 1 1 0 0
1 1 0 0 0
1 1 0 0 0
0 0 0 0 0

根据 SE,我通过将 Image 向 0、+1(上)和 -1(左)方向移动,并取所有这三个移动的并集,得到了上述结果。

现在,我需要弄清楚如何在 C、C++ 中实现这一点。 我不确定如何开始以及如何进行集合并集。 我想代表原始图像,三个移位图像和通过联合获得的最终图像;全部使用矩阵。

有什么地方可以让我获得一些示例解决方案或任何想法可以继续吗?

谢谢。

【问题讨论】:

    标签: c++ image-processing mathematical-morphology


    【解决方案1】:

    那里有大量的示例实现。Google 是你的朋友 :)

    编辑
    以下是该过程的伪代码(非常类似于在 2D 中进行卷积)。我相信有更聪明的方法来做到这一点:

    // grayscale image, binary mask
    void morph(inImage, outImage, kernel, type) {
     // half size of the kernel, kernel size is n*n (easier if n is odd)
     sz = (kernel.n - 1 ) / 2;
    
     for X in inImage.rows {
      for Y in inImage.cols {
    
       if ( isOnBoundary(X,Y, inImage, sz) ) {
        // check if pixel (X,Y) for boundary cases and deal with it (copy pixel as is)
        // must consider half size of the kernel
        val = inImage(X,Y);       // quick fix
       }
    
       else {
        list = [];
    
        // get the neighborhood of this pixel (X,Y)
        for I in kernel.n {
         for J in kernel.n {
          if ( kernel(I,J) == 1 ) {
           list.add( inImage(X+I-sz, Y+J-sz) );
          }
         }
        }
    
        if type == dilation {
         // dilation: set to one if any 1 is present, zero otherwise
         val = max(list);
        } else if type == erosion {
         // erosion: set to zero if any 0 is present, one otherwise
         val = min(list);
        }
       }
    
       // set output image pixel
       outImage(X,Y) = val;
      }
     }
    }
    

    以上代码基于此tutorial(查看页尾源码)。


    EDIT2

    list.add(inImage(X+I-sz, Y+J-sz));

    我们的想法是,我们想在位于 (X,Y) 的当前图像像素上叠加以 sz(掩码的一半大小)为中心的内核掩码(大小为 nxn),然后只得到像素的强度其中掩码值为 1(我们将它们添加到列表中)。一旦提取了该像素的所有邻居,我们将输出图像像素设置为该列表的最大值(最大强度)以进行扩张,并设置最小值以进行侵蚀(当然这仅适用于灰度图像和二进制掩码)
    上述语句中 X/Y 和 I/J 的索引均假定从 0 开始。 如果您愿意,您始终可以用掩码的一半大小(从 -sz 到 +sz)重写 I/J 的索引,只需稍作更改(我链接到的教程使用的方式)...


    示例
    考虑这个放置并以像素 (X,Y) 为中心的 3x3 内核掩码,看看我们如何遍历它周围的邻域:

     --------------------
    |      |       |     |    sz = 1;
     --------------------     for (I=0 ; I<3 ; ++I)
    |      | (X,Y) |     |      for (J=0 ; J<3 ; ++J)
     --------------------         vect.push_back( inImage.getPixel(X+I-sz, Y+J-sz) );
    |      |       |     |
     --------------------
    

    【讨论】:

    • 如果我们的内核大小为 MxN = 1x3,其中 M 是宽度,N 是高度呢?
    • 代码只是一个大纲,而不是实际的实现。但是如果你仔细观察,你会发现我只处理了 N*N 个内核,其中 N 是奇数。
    • :) 是的,我明白了。只是想说你可以通过添加 kernelWidth kernelHeght 并检查边界来改进你的代码。
    【解决方案2】:

    也许更好的看待它的方法是如何产生扩张的输出像素。对于图像中的相应像素,对齐结构元素,使结构元素的原点位于该图像像素处。如果有任何重叠,则将该位置的膨胀输出像素设置为1,否则将其设置为0。

    所以这可以通过简单地循环图像中的每个像素并测试正确移动的结构元素是否与图像重叠来完成。这意味着您可能会有 4 个嵌套循环:x img、y img、x se、y se。因此,对于每个图像像素,循环遍历结构元素的像素并查看是否有任何重叠。这可能不是最有效的算法,但可能是最直接的。

    另外,我认为您的示例不正确。膨胀取决于结构元素的起源。如果原点是……

    左上角零:你需要移动图像(-1,-1)、(-1,0)和(0,-1)给:

    1 1 1 0 0
    1 1 0 0 0
    1 1 0 0 0
    1 0 0 0 0
    0 0 0 0 0 
    

    在右下角:你需要移动图像(0,0),(1,0)和(0,1)给:

    0 0 0 0 0
    0 1 1 1 0
    0 1 1 0 0
    0 1 1 0 0
    0 1 0 0 0
    

    MATLAB 使用 floor((size(SE)+1)/2) 作为 SE 的原点,因此在这种情况下,它将使用 SE 的左上角像素。您可以使用 imdilate MATLAB 函数来验证这一点。

    【讨论】:

      【解决方案3】:
      【解决方案4】:
      /* structure of the image variable
       * variable n stores the order of the square matrix */
      
      typedef struct image{
              int mat[][];
              int n;
              }image;
      
      
      /* function recieves image "to dilate" and returns "dilated"*
       * structuring element predefined:
       *             0  1  0
       *             1  1  1
       *             0  1  0
       */
      
      image* dilate(image* to_dilate)
      {
             int i,j;
             int does_order_increase;
             image* dilated;
      
             dilated = (image*)malloc(sizeof(image));
             does_order_increase = 0;
      
      /* checking whether there are any 1's on d border*/       
      
             for( i = 0 ; i<to_dilate->n ; i++ )
             {
                  if( (to_dilate->a[0][i] == 1)||(to_dilate->a[i][0] == 1)||(to_dilate->a[n-1][i] == 1)||(to_dilate->a[i][n-1] == 1) )
                  {
                      does_order_increase = 1;
                      break;
                  }
             }
      
      /* size of dilated image initialized */       
      
             if( does_order_increase == 1)
                 dilated->n = to_dilate->n + 1;
             else
                 dilated->n = to_dilate->n;
      
      /* dilating image by checking every element of to_dilate and filling dilated *
       * does_order_increase serves to cope with adjustments if dilated 's order increase */
      
             for( i = 0 ; i<to_dilate->n ; i++ )
             {
                  for( j = 0 ; j<to_dilate->n ; j++ )
                  {
                       if( to_dilate->a[i][j] == 1)
                       {
                           dilated->a[i + does_order_increase][j + does_order_increase] = 1;
                           dilated->a[i + does_order_increase -1][j + does_order_increase ] = 1;
                           dilated->a[i + does_order_increase ][j + does_order_increase -1] = 1;
                           dilated->a[i + does_order_increase +1][j + does_order_increase ] = 1;
                           dilated->a[i + does_order_increase ][j + does_order_increase +1] = 1;
                       }
                  }
             }
      
      /* dilated stores dilated binary image */
      
             return dilated;
      }
      
      /* end of dilation */ 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-09-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-07-08
        • 1970-01-01
        相关资源
        最近更新 更多