代码卡在循环中

时间:2017-06-04 08:06:45

标签: java

我制作了一个拍摄照片的脚本,从左上角开始(在我的测试图像的情况下为白色像素),并继续像魔术棒工具一样通过图像,选择像素一个类似的颜色。

但是,即使经过循环的次数超过图像中的像素,脚本也没​​有完成执行。

测试图像大约为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。如果你想指出明显的方法来使这个循环更快,那也是值得赞赏的。

2 个答案:

答案 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