在 C、C++ 中实现腐蚀、膨胀
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1472768/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
implementing erosion, dilation in C, C++
提问by Amro
I have theoretical understanding of how dilation in binary image is done.
我对二进制图像中的膨胀是如何完成的有理论上的理解。
AFAIK, If my SE (structuring element) is this
AFAIK,如果我的 SE(结构元素)是这个
0 1
1 1.
where . represents the centre, and my image(binary is this)
在哪里 。代表中心,我的形象(二进制是这个)
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
so the result of dilation is
所以膨胀的结果是
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
I got above result by shifting Image in 0, +1 (up) and and -1(left) direction, according to SE, and taking the union of all these three shifts.
根据 SE,我通过在 0、+1(向上)和 -1(向左)方向上移动 Image 并结合所有这三个移动来获得上述结果。
Now, I need to figure out how to implement this in C, C++. I am not sure how to begin and how to take the union of sets. I thought of representing original image,three shifted images and final image obtained by taking union; all using matrix.
现在,我需要弄清楚如何在 C、C++ 中实现它。我不确定如何开始以及如何进行集合的并集。我想到了表示原始图像,三个移位图像和取并得到的最终图像;都使用矩阵。
Is there any place where I can get some sample solution to start with or any ideas to proceed ?
有什么地方可以让我开始获得一些示例解决方案或任何想法吗?
Thanks.
谢谢。
回答by Amro
There are tons of sample implementations out there.. Googleis your friend :)
EDIT
The following is a pseudo-code of the process (very similar to doing a convolution in 2D). Im sure there are more clever way to doing it:
那里有大量的示例实现......谷歌是你的朋友 :)
编辑
以下是该过程的伪代码(非常类似于在 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;
}
}
}
The above code is based on this tutorial(check the source code at the end of the page).
以上代码基于本教程(查看页面末尾的源代码)。
EDIT2:
编辑2:
list.add( inImage(X+I-sz, Y+J-sz) );
list.add( inImage(X+I-sz, Y+J-sz) );
The idea is that we want to superimpose the kernel mask (of size nxn) centered at sz (half size of mask) on the current image pixel located at (X,Y), and then just get the intensities of the pixels where the mask value is one (we are adding them to a list). Once extracted all the neighbors for that pixel, we set the output image pixel to the maximum of that list (max intensity) for dilation, and min for erosion (of course this only work for grayscale images and binary mask)
The indices of both X/Y and I/J in the statement above are assumed to start from 0.
If you prefer, you can always rewrite the indices of I/J in terms of half the size of the mask (from -sz to +sz) with a small change (the way the tutorial I linked to is using)...
这个想法是,我们想在位于 (X,Y) 的当前图像像素上叠加以 sz(掩码的一半大小)为中心的内核掩码(大小为 nxn),然后只需获取掩码所在像素的强度值为 1(我们将它们添加到列表中)。一旦提取了该像素的所有邻居,我们将输出图像像素设置为该列表的最大值(最大强度)用于膨胀,最小值用于腐蚀(当然这仅适用于灰度图像和二进制掩码)
两个 X 的索引上面语句中的 /Y 和 I/J 假定从 0 开始。如果您愿意,您可以随时根据掩码大小的一半(从 -sz 到 +sz)重写 I/J 的索引小改动(我链接的教程使用的方式)...
Example:
Consider this 3x3 kernel mask placed and centered on pixel (X,Y), and see how we traverse the neighborhood around it:
示例:
考虑这个 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) );
| | | |
--------------------
回答by Jason B
Perhaps a better way to look at it is how to produce an output pixel of the dilation. For the corresponding pixel in the image, align the structuring element such that the origin of the structuring element is at that image pixel. If there is any overlap, set the dilation output pixel at that location to 1, otherwise set it to 0.
也许更好的方式是如何产生膨胀的输出像素。对于图像中的相应像素,对齐结构元素,使结构元素的原点位于该图像像素处。如果有任何重叠,则将该位置的膨胀输出像素设置为 1,否则将其设置为 0。
So this can be done by simply looping over each pixel in the image and testing whether or not the properly shifted structuring element overlaps with the image. This means you'll probably have 4 nested loops: x img, y img, x se, y se. So for each image pixel, you loop over the pixels of the structuring element and see if there is any overlap. This may not be the most efficient algorithm, but it is probably the most straightforward.
因此,这可以通过简单地遍历图像中的每个像素并测试适当移动的结构元素是否与图像重叠来完成。这意味着您可能有 4 个嵌套循环:x img、y img、x se、y se。因此,对于每个图像像素,您遍历结构元素的像素并查看是否有任何重叠。这可能不是最有效的算法,但可能是最直接的。
Also, I think your example is incorrect. The dilation depends on the origin of the structuring element. If the origin is...
另外,我认为你的例子是不正确的。膨胀取决于结构元素的来源。如果起源是...
at the top left zero: you need to shift the image (-1,-1), (-1,0), and (0,-1) giving:
在左上角零:您需要移动图像 (-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
at the bottom right: you need to shift the image (0,0), (1,0), and (0,1) giving:
在右下角:您需要移动图像 (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 uses floor((size(SE)+1)/2) as the origin of the SE so in this case, it will use the top left pixel of the SE. You can verify this using the imdilateMATLAB function.
MATLAB 使用 floor((size(SE)+1)/2) 作为 SE 的原点,因此在这种情况下,它将使用 SE 的左上角像素。您可以使用imdilateMATLAB 函数验证这一点。
回答by Sk.
/* 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 */