在C,C ++中实现侵蚀,扩张

时间:2009-09-24 16:23:32

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

我对二进制图像中的扩张是如何完成有理论上的理解。

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(向左)方向上移动来获得上述结果,并将所有这三个移位结合起来。

现在,我需要弄清楚如何在C,C ++中实现它。 我不知道如何开始以及如何采用集合的联合。 我想到了表示原始图像,三个移位图像和通过结合获得的最终图像;全部使用矩阵。

是否有任何地方可以提供一些示例解决方案或任何想法继续进行?

感谢。

4 个答案:

答案 0 :(得分:13)

那里有大量的示例实现.. 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的索引,只需稍加改动(我链接的教程使用的方式)...... / p>


示例
考虑放置这个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) );
|      |       |     |
 --------------------

答案 1 :(得分: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函数验证这一点。

答案 2 :(得分:1)

答案 3 :(得分: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 */