围绕任何 alpha 透明图像绘制轮廓或描边的算法

标签 algorithm image-processing

不确定我目前正在开发的这个算法是否有任何名称 - “growing neighborhood algorithm”听起来是个合适的名称。那么我的问题是什么?

我想在 alpha 透明图像周围画笔划来勾勒出它的轮廓。笔画的大小应该是用户可定义的。

我有一个由 0 和 1 填充的数组,将数组的每一项都视为一个单元格,就像《生命游戏》中那样。 0项为空(透明像素),1项为第一代细胞(非透明像素),代数由周围笔划的大小定义。

此示例描绘了一个由 alpha 值包围的矩形:

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

然后我想通过包围每个 0 代摩尔邻居来让它们生长出新一代。这是第二代(笔划为 1px)- 因此数组看起来如下增长:

0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 2 2 2 2 2 2 0 0
0 0 2 1 1 1 1 2 0 0
0 0 2 1 1 1 1 2 0 0
0 0 2 1 1 1 1 2 0 0
0 0 2 1 1 1 1 2 0 0
0 0 2 2 2 2 2 2 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0

第3代和第4代(3px笔画):

4 4 4 4 4 4 4 4 4 4
4 3 3 3 3 3 3 3 3 4
4 3 2 2 2 2 2 2 3 4
4 3 2 1 1 1 1 2 3 4
4 3 2 1 1 1 1 2 3 4
4 3 2 1 1 1 1 2 3 4
4 3 2 1 1 1 1 2 3 4
4 3 2 2 2 2 2 2 3 4
4 3 3 3 3 3 3 3 3 4
4 4 4 4 4 4 4 4 4 4

到目前为止一切顺利。我通过以下代码片段完成了这个简单的任务:

for (int gen = 1; gen <= 4; gen++)
{
    for (int x = 1; x < arrayWidth - 1; x++)
    {
        for (int y = 1; y < arrayHeight - 1; y++)
        {
            // See if this cell is in the current generation.
            if (_generation[x + arrayWidth * y] == gen)
            {
                // Generate next generation.
                for (int i = x - 1; i <= x + 1; i++)
                {
                    for (int j = y - 1; j <= y + 1; j++)
                    {
                        if (_generation[i + arrayWidth * j] == 0 || _generation[i + arrayWidth * j] > gen)
                        {
                            _generation[i + arrayWidth * j] = gen + 1;
                        }
                    }
                }
            }
        }
    }
}

这种方法非常适合简单的形状,例如矩形。但是我怎样才能为椭圆做这个呢?一旦我们在单元格中有了某种阶梯图案,我就会得到困惑的结果:

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

0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 2 2 2 2 2 2 0 0 0 0
0 0 0 2 2 1 1 1 1 2 2 0 0 0
0 0 2 2 1 1 1 1 1 1 2 2 0 0
0 2 2 1 1 1 1 1 1 1 1 2 2 0
0 2 1 1 1 1 1 1 1 1 1 1 2 0
0 2 1 1 1 1 1 1 1 1 1 1 2 0
0 2 1 1 1 1 1 1 1 1 1 1 2 0
0 2 1 1 1 1 1 1 1 1 1 1 2 0
0 2 1 1 1 1 1 1 1 1 1 1 2 0
0 2 2 1 1 1 1 1 1 1 1 2 0 0
0 0 2 2 1 1 1 1 1 1 2 2 0 0
0 0 0 2 2 1 1 1 1 2 2 0 0 0
0 0 0 0 2 2 2 2 2 2 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0

0 0 0 3 3 3 3 3 3 3 3 0 0 0
0 0 3 3 2 2 2 2 2 2 3 3 0 0
0 3 3 2 2 1 1 1 1 2 2 3 3 0
3 3 2 2 1 1 1 1 1 1 2 2 3 3
3 2 2 1 1 1 1 1 1 1 1 2 2 3
3 2 1 1 1 1 1 1 1 1 1 1 2 3
3 2 1 1 1 1 1 1 1 1 1 1 2 3
3 2 1 1 1 1 1 1 1 1 1 1 2 3
3 2 1 1 1 1 1 1 1 1 1 1 2 3
3 2 1 1 1 1 1 1 1 1 1 1 2 3
3 2 2 1 1 1 1 1 1 1 1 2 2 3
3 3 2 2 1 1 1 1 1 1 2 2 3 3
0 3 3 2 2 1 1 1 1 2 2 3 3 0
0 0 3 3 2 2 2 2 2 2 3 3 0 0
0 0 0 3 3 3 3 3 3 3 3 0 0 0

将此算法应用于椭圆时,由于这个问题,轮廓看起来有点奇怪(左:算法结果,右:要求的结果):

Algorithm result (left), requested result (right)

这里的问题是,我不希望每次出现这种“阶梯”模式时出现那些 2 2 和 3 3 重复 block :

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

我希望上面的第 2 代和第 3 代计算如下所示:

0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 2 2 2 2 0 0 0 0 0
0 0 0 0 2 1 1 1 1 2 0 0 0 0
0 0 0 2 1 1 1 1 1 1 2 0 0 0
0 0 2 1 1 1 1 1 1 1 1 2 0 0
0 2 1 1 1 1 1 1 1 1 1 1 2 0
0 2 1 1 1 1 1 1 1 1 1 1 2 0
0 2 1 1 1 1 1 1 1 1 1 1 2 0
0 2 1 1 1 1 1 1 1 1 1 1 2 0
0 2 1 1 1 1 1 1 1 1 1 1 2 0
0 0 2 1 1 1 1 1 1 1 1 2 0 0
0 0 0 2 1 1 1 1 1 1 2 0 0 0
0 0 0 0 2 1 1 1 1 2 0 0 0 0
0 0 0 0 0 2 2 2 2 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0

0 0 0 0 0 3 3 3 3 0 0 0 0 0
0 0 0 0 3 2 2 2 2 2 3 0 0 0
0 0 0 3 2 1 1 1 1 2 3 0 0 0
0 0 3 2 1 1 1 1 1 1 2 3 0 0
0 3 2 1 1 1 1 1 1 1 1 2 3 0
3 2 1 1 1 1 1 1 1 1 1 1 2 3
3 2 1 1 1 1 1 1 1 1 1 1 2 3
3 2 1 1 1 1 1 1 1 1 1 1 2 3
3 2 1 1 1 1 1 1 1 1 1 1 2 3
3 2 1 1 1 1 1 1 1 1 1 1 2 3
0 3 2 1 1 1 1 1 1 1 1 2 3 0
0 0 3 2 1 1 1 1 1 1 2 3 0 0
0 0 0 3 2 1 1 1 1 2 3 0 0 0
0 0 0 3 2 2 2 2 2 2 3 0 0 0
0 0 0 0 3 3 3 3 3 3 0 0 0 0

我尝试了很多方法来过滤掉那些重复的单元格 block ,但我找不到一个简单通用的解决方案来解决这个问题。

有什么想法可以像我从 Photoshop 或 Paint.NET 获得笔触/轮廓一样吗?

谢谢!

干杯

最佳答案

正确的名称是dilation,查看形态学操作。您应该尝试使用 circle 元素进行扩张,这将为您提供所需的结果。

这是一个 Matlab 代码,展示了它是如何完成的:

im = imcircle(70);
im = padarray(im,[20,20]);
figure;imshow(im);
im2 = imdilate(im,strel('disk',8));
figure;imshow(im2);

enter image description here

关于围绕任何 alpha 透明图像绘制轮廓或描边的算法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12687788/

相关文章:

algorithm - 具有有序节点的树的搜索成本

algorithm - 有色 Petri 网的边界准则

c - 如何有效地在年历上存储任务信息

iphone - 如何使用 iphone 在照片中找到矩形?

php - 调整大小后的图像中有黑色方 block

javascript - 如何将一个字符串分解成多个重叠的更小的字符串?

c++ - 模拟一个游戏,每个玩家都有不同的获胜概率?

python - 用于特定内容边界框测量的最佳线检测器算法

image - 如何将RGB图像转换为单 channel 灰度图像,并使用python保存它?

c# - 凸包中的最远点