在C,C ++中实现腐蚀,膨胀
c++
image-processing
6
0

我对二进制图像中的扩张方法有理论上的了解。

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 ++中实现这一点。我不确定如何开始以及如何结合集合。我想到了通过合并获得原始图像,三个移位图像和最终图像。全部使用矩阵。

在什么地方可以得到一些示例解决方案开始或有什么想法可以进行?

谢谢。

参考资料:
Stack Overflow
收藏
评论
共 2 个回答
高赞 时间 活跃

那里有大量的示例实现。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(mask的一半大小)为中心的大小为nxn的内核掩模,然后仅获取掩模所在像素的强度值是一个(我们正在将它们添加到列表中)。提取该像素的所有邻居后,我们将输出图像像素设置为该列表的最大值(最大强度)以进行扩张,并设置为min进行侵蚀(当然这仅适用于灰度图像和二进制蒙版)
上面的语句中X / Y和I / J的索引都假定从0开始。如果愿意,您总是可以将I / J的索引重写为掩码大小的一半(从-sz到+ sz)进行了很小的更改(我链接到的教程使用的方式)...


范例
考虑一下放置在像素(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) );
|      |       |     |
 --------------------
收藏
评论

也许看一个更好的方法是如何产生膨胀的输出像素。对于图像中的相应像素,对齐结构元素,以使结构元素的原点位于该图像像素处。如果存在任何重叠,请将该位置处的扩散输出像素设置为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的左上像素。您可以使用impliate MATLAB函数对此进行验证。

收藏
评论
新手导航
  • 社区规范
  • 提出问题
  • 进行投票
  • 个人资料
  • 优化问题
  • 回答问题

关于我们

常见问题

内容许可

联系我们

@2020 AskGo
京ICP备20001863号