我制作了一个拍摄照片的脚本,从左上角开始(在我的测试图像的情况下为白色像素),并继续像魔术棒工具一样通过图像,选择像素一个类似的颜色。
但是,即使经过循环的次数超过图像中的像素,脚本也没有完成执行。
测试图像大约为160K像素。 Tools.loadImage()
是一种自编的方法。我在其他地方使用它,它很可能有效。以下不是我的全部代码,而是与问题相关的部分。
static int[][][] image;
public static void main(String[] args) {
image = Tools.loadImage(path1);
int height = image.length;
int width = image[0].length;
int[][][] newImage = new int[height][width][4];
ArrayList<Integer> toCheck = new ArrayList<Integer>();
ArrayList<Integer> checked = new ArrayList<Integer>();
int[] baseColor = image[0][0];
toCheck.add(0);
while (!toCheck.isEmpty()) {
i++;
int coords = toCheck.get(0);
int x = coords % width;
int y = coords / width;
if (check(x, y, baseColor, 128)) {
coords = y * width + x - 1;
if (x > 0 && !(checked.contains(coords) || toCheck.contains(coords))) {
toCheck.add(coords);
}
coords = y * width + x + 1;
if (x < width - 1 && !(checked.contains(coords) || toCheck.contains(coords))) {
toCheck.add(coords);
}
coords = (y - 1) * width + x;
if (y > 0 && !(checked.contains(coords) || toCheck.contains(coords))) {
toCheck.add(coords);
}
coords = (y + 1) * width + x;
if (y < height - 1 && !(checked.contains(coords) || toCheck.contains(coords))) {
toCheck.add(coords);
}
}
checked.add(coords);
toCheck.remove(0);
}
}
static boolean check(int x, int y, int[] color, int threshold) {
for (int i = 0; i < 3; i++) {
if (Math.abs(image[y][x][i] - color[i]) > threshold) {
return false;
}
}
return true;
}
PS。如果你想指出明显的方法来使这个循环更快,那也是值得赞赏的。
答案 0 :(得分:2)
要检查的添加位置错误。
while (!toCheck.isEmpty()) {
i++;
int coords = toCheck.get(0);
checked.add(coords); // important
toCheck.remove(0); // might as well do this here too
int x = coords % width;
int y = coords / width;
coords在循环中被重复覆盖,因此不添加当前像素,而是添加四个邻居中的最后一个。因此,某些条件稍后失败,并且在Check中添加了一些错误的像素。
答案 1 :(得分:1)
你正在覆盖循环体中的coords
,所以在每次迭代结束时你都会标记错误的像素。在弹出toCheck
的下一个点之后立即移动标记是完全安全的。
从表现来看,请考虑使用BitSet
checked
(根据@JB Nizet的建议)和ArrayDeque
toCheck
。