9

我对二值图像中的膨胀是如何完成的有理论上的理解。

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,我通过在 0、+1(上)和和 -1(左)方向上移动 Image 并结合所有这三个移位,得到了上述结果。

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

有什么地方可以让我开始使用一些示例解决方案或继续进行任何想法吗?

谢谢。

4

4 回答 4

17

那里有大量的示例实现.. 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;
  }
 }
}

以上代码基于本教程(查看页面末尾的源代码)。


编辑2

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

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


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

 --------------------
|      |       |     |    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) );
|      |       |     |
 --------------------
于 2009-09-24T18:41:27.633 回答
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 函数来验证这一点。

于 2009-09-24T18:57:47.333 回答
1

开放式CV

示例:腐蚀和膨胀

于 2009-09-24T17:58:25.333 回答
0
/* 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 */ 
于 2010-01-17T06:37:26.637 回答