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

How would scanline fill algorithm iterate the pixel positions on the following image in an optimised way?

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

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

这是来自维基百科的简单代码:

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 像素尚未被填充通过算法。

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