扫描线填充算法如何以优化的方式迭代以下图像上的像素位置?

Posted

技术标签:

【中文标题】扫描线填充算法如何以优化的方式迭代以下图像上的像素位置?【英文标题】:How would scanline fill algorithm iterate the pixel positions on the following image in an optimised way? 【发布时间】:2021-11-17 12:19:49 【问题描述】:

谁能解释一下扫描线填充算法如何将蓝色位置变成粉红色?我想知道当观察到障碍物时迭代将如何变化。以第三行为例,该算法很容易将位置 40 到 46 视为同一组的一部分。但是算法将如何以及何时迭代位置 52 到 59?

如果可能,请从左到右解释,而不是从上到下。还要提到一种优化的迭代方法。

【问题讨论】:

这个网站的好习惯是在询问之前先做个人努力。 @Nehal Kalita:我的意思是:尝试理解现有的实现会有所帮助。我非常不愿意仅仅复制代码而不了解它是如何工作的。 @Sneaky Polar Bear ,关于洪水填充算法的***页面指出,这种方法在已知的洪水填充算法中最为流行,因为它会测试最多填充的像素 3 次,这与使用堆栈或测试最多填充像素 4 次的队列。 抱歉,您能否链接说这句话的参考资料。需要明确的是,我同意在某些情况下 linescan 可以更快,但通常(当速度不是问题或可以接受时)我更喜欢 4 或 8 nn 填充填充,因为它的鲁棒性(没有任何边缘情况)和易于调试/ 实施。 线扫描优于 nn 技术的主要好处之一是线程更容易(这也是一个主要基于您的应用程序的问题),因此在微控制器(一个内核)上,您无法受益来自线程,但在具有 8 个以上处理器的现代计算机上......收益可能非常显着 【参考方案1】:

这是来自***的简单代码:

fn fill(x, y):
  if not Inside(x, y) then return
  let s = new empty stack or queue
  add (x, y) to s
  while s is not empty:
    Remove an (x, y) from s
    let lx = x
    while Inside(lx - 1, y):
      Set(lx - 1, y)
      lx = lx - 1
    while Inside(x, y):
      Set(x, y)
      x = x + 1
    scan(lx, x - 1, y + 1, s)
    scan(lx, x - 1, y - 1, s)

fn scan(lx, rx, y, s):
  let added = false
  for x in lx .. rx:
    if not Inside(x, y):
      added = false
    else if not added:
      Add (x, y) to s
      added = true

所以“s”是一个种子列表,基本上你放一些随机点(必须为空)来启动算法。

while s is not empty:
    Remove an (x, y) from s

这是一个基本循环,我们在其中消耗种子,当“s”中没有种子时,算法结束。

let lx = x
    while Inside(lx - 1, y):
      Set(lx - 1, y)
      lx = lx - 1
    while Inside(x, y):
      Set(x, y)
      x = x + 1

这是跟踪当前扫描线,其中 lx 是最左边的空像素, (x-1) 是最右边的空像素(请注意,这可能会造成混淆,无论如何,x 将至少增加一次,因为所有种子点保证在内部点)。第一个循环向左移动并在每次找到一个空像素时递减 lx。第二个循环向右移动并在每次找到一个空像素时递增 x。您可以按照说明逐个像素设置,但取决于您的库(如果绘制线条比逐个像素编辑便宜),您可以在通过这两个循环后绘制一条线,在 (lx,y) 和 ( x-1,y)。

scan(lx, x - 1, y + 1, s)
    scan(lx, x - 1, y - 1, s)

这是“重新播种”步骤。基本上上述步骤会消耗种子,这是根据刚刚消耗的种子的结果产生新种子的步骤。 “y+1”和“y-1”是刚刚绘制的线上方和下方的单个像素偏移量,而“lx”和“x-1”描述了这一步刚刚计算的线。

fn scan(lx, rx, y, s):
  let added = false
  for x in lx .. rx:
    if not Inside(x, y):
      added = false
    else if not added:
      Add (x, y) to s
      added = true

这里发生的所有事情都是扫描线上的任何空像素(请记住,这是根据参数检查的最后一行的上方和下方)被添加到种子数组中以供稍后测试(这不是向前递增,而是向后但详尽地搜索沿线的每个点)。请记住,这里 s 需要是一个 byref 参数,因为您将对其进行编辑。

另外一个注意事项:当我说“空像素”时,我的意思是两件事(尽管它们在本 aglo 中的处理方式通常相同):1 像素不是边缘点,2 像素尚未被算法。

如下图所示,任何种子都可以按任何顺序从种子列表中拉出,并且算法仍然可以正常运行。

【讨论】:

如果这个解释没有帮助,我可以尝试添加一些基本图纸。 lmk 图纸会很有帮助。抱歉迟了回应。我没有再次检查这个问题。 @NehalKalita 图片添加到答案以演示指定的瓷砖。 (注意种子的选择是随机的,但是是有序的还是随机的在算法上没有区别) 感谢您的演示。从 Wikipedia 页面,我不理解算法,因为我认为使用的变量定义不正确。

以上是关于扫描线填充算法如何以优化的方式迭代以下图像上的像素位置?的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV实战——像素操作

扫描线填充算法

扫描线填充算法与种子填充算法的区别是啥

特殊blob填充算法的名称

在python中迭代图像的所有像素的最快方法

图形填充之边缘填充算法