【发布时间】:2020-09-15 20:11:52
【问题描述】:
所以我写了一个像绘画应用桶工具一样工作的洪水填充函数:你点击一个封闭的形状,它会用一种颜色填充。
我有两个问题:
性能 - 假设我的画布是 600*600(370,000 像素),我在其中画了一个大圆圈,例如其中有大约 100K 像素,它可能需要大约 40(!!!)秒填满这个圈子!那太疯狂了! 恰好 10,000 个像素的正方形平均需要 0.4-0.5 秒,但是(我猜)由于程序使用的数组的大小增长得如此之快,所以 10 倍大小的正方形需要大约 100 倍的长度来填充。
填充物有些奇怪。我不太确定它是如何发生的,但它总是会留下一些未填充的像素。一点也不多,但真的很奇怪。
我的洪水填充函数使用 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