【问题标题】:p5.js Flood Fill (bucket tool) works slowly and wierdp5.j​​s Flood Fill(桶工具)工作缓慢而奇怪
【发布时间】:2020-09-15 20:11:52
【问题描述】:

所以我写了一个像绘画应用桶工具一样工作的洪水填充函数:你点击一个封闭的形状,它会用一种颜色填充。

我有两个问题:

  1. 性能 - 假设我的画布是 600*600(370,000 像素),我在其中画了一个大圆圈,例如其中有大约 100K 像素,它可能需要大约 40(!!!)秒填满这个圈子!那太疯狂了! 恰好 10,000 个像素的正方形平均需要 0.4-0.5 秒,但是(我猜)由于程序使用的数组的大小增长得如此之快,所以 10 倍大小的正方形需要大约 100 倍的长度来填充。

  2. 填充物有些奇怪。我不太确定它是如何发生的,但它总是会留下一些未填充的像素。一点也不多,但真的很奇怪。

我的洪水填充函数使用 4 个辅助函数:获取和设置像素颜色,检查它是否是要填充的颜色,以及检查它是否是以前检查过的像素。 以下是所有功能:

getPixelColor = (x, y) => {
  let pixelColor = [];
  for (let i = 0; i < pixDens; ++i) {
    for (let j = 0; j < pixDens; ++j) {
      index = 4 * ((y * pixDens + j) * width * pixDens + (x * pixDens + i));
      pixelColor[0] = pixels[index];
      pixelColor[1] = pixels[index + 1];
      pixelColor[2] = pixels[index + 2];
      pixelColor[3] = pixels[index + 3];
    }
  }
  return pixelColor;
};

setPixelColor = (x, y, currentColor) => { //Remember to loadPixels() before using this function, and to updatePixels() after.
  for (let i = 0; i < pixDens; ++i) {
    for (let j = 0; j < pixDens; ++j) {
      index = 4 * ((y * pixDens + j) * width * pixDens + (x * pixDens + i));
      pixels[index] = currentColor[0];
      pixels[index + 1] = currentColor[1];
      pixels[index + 2] = currentColor[2];
      pixels[index + 3] = currentColor[3];
    }
  }
}

isDuplicate = (posHistory, vector) => {
  for (let i = 0; i < posHistory.length; ++i) {
    if (posHistory[i].x === vector.x && posHistory[i].y === vector.y) {
      return true;
    }
  }
  return false;
}

compareColors = (firstColor, secondColor) => {
  for (let i = 0; i < firstColor.length; ++i) {
    if (firstColor[i] !== secondColor[i]) {
      return false;
    }
  }
  return true;
}

floodFill = () => {
  loadPixels();
  let x = floor(mouseX);
  let y = floor(mouseY);
  let startingColor = getPixelColor(x, y);
  if (compareColors(startingColor, currentColor)) {
    return false;
  }
  let pos = [];
  pos.push(createVector(x, y));
  let posHistory = [];
  posHistory.push(createVector(x, y));
  while (pos.length > 0) {
    x = pos[0].x;
    y = pos[0].y;
    pos.shift();
    if (x <= width && x >= 0 && y <= height && y >= 0) {
      setPixelColor(x, y, currentColor);
      let xMinus = createVector(x - 1, y);
      if (!isDuplicate(posHistory, xMinus) && compareColors(getPixelColor(xMinus.x, xMinus.y), startingColor)) {
        pos.push(xMinus);
        posHistory.push(xMinus);
      }
      let xPlus = createVector(x + 1, y);
      if (!isDuplicate(posHistory, xPlus) && compareColors(getPixelColor(xPlus.x, xPlus.y), startingColor)) {
        pos.push(xPlus);
        posHistory.push(xPlus);
      }
      let yMinus = createVector(x, y - 1);
      if (!isDuplicate(posHistory, yMinus) && compareColors(getPixelColor(yMinus.x, yMinus.y), startingColor)) {
        pos.push(yMinus);
        posHistory.push(yMinus);
      }
      let yPlus = createVector(x, y + 1);
      if (!isDuplicate(posHistory, yPlus) && compareColors(getPixelColor(yPlus.x, yPlus.y), startingColor)) {
        pos.push(yPlus);
        posHistory.push(yPlus);
      }
    }
  }
  updatePixels();
}

如果有人可以帮助我解决功能问题,我真的很感激。 非常感谢!!

编辑:所以我更新了我的洪水填充功能本身并删除了一组我从未使用过的颜色。这个数组非常大,几乎每次运行都会调用一些 push() 和 shift() 方法。 不幸的是,小形状的执行时间是 99.9%(例如,10,000 的填充需要相同的 0.5 秒,但是像 100,000 像素这样的大填充现在需要大约 30 秒而不是 40 秒,所以这是正确的一步方向。 我猜 RAM 使用率也下降了,因为它是一个非常大的数组,但我没有测量它。 它留下未填充像素的奇怪问题仍然存在。

【问题讨论】:

    标签: javascript p5.js flood-fill


    【解决方案1】:

    一点建议:

    您实际上不必使用posHistory 数组来确定是否设置颜色。如果当前像素与startingColor颜色相同则设置颜色,否则不设置。这将具有相同的效果。

    posHistory 数组在执行过程中会越来越大。因此,为了确定是否填充单个像素,必须做很多工作。我认为这可能是您的代码运行缓慢的原因。

    至于“怪事”:

    我以前也遇到过这种情况。我认为这是因为未填充的像素与startingColor 的颜色不同。假设您在白色背景上绘制黑色形状,您会期望在某处的黑色和白色部分之间看到一些灰色像素(接近白色)。这些像素起到平滑形状的作用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-11-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-24
      • 2021-12-14
      • 1970-01-01
      相关资源
      最近更新 更多