如何优化此缓冲的图像循环?

时间:2019-11-23 13:04:54

标签: java image loops image-processing optimization

我正在使用以下循环来计算相同大小的两幅图像之间的差异:

static double calculateError(BufferedImage canvas, BufferedImage ideal) {
    double error = 0.0D;

    for (int x = 0; x < Polygonizer.WIDTH; x++) {
      for (int y = 0; y < Polygonizer.HEIGHT; y++) {
        Color c1 = new Color(canvas.getRGB(x, y));
        Color c2 = new Color(ideal.getRGB(x, y));

        error += Math.abs(c1.getRed() - c2.getRed());
        error += Math.abs(c1.getGreen() - c2.getGreen());
        error += Math.abs(c1.getBlue() - c2.getBlue());
      } 
    } 
    return error;
  }

它工作正常,但速度很慢,而且我不知道如何使其更快。

我已经尝试过使用ExecutorService不好,我可以使用一些建议。


编辑:谢谢大家。这是优化的版本:

private static int APPROXIMATION = 1;

private static int[] idealData;

public static final void setIdeal(BufferedImage ideal) {
        int[] rawData = ((DataBufferInt)ideal.getRaster().getDataBuffer()).getData();
        idealData = new int[rawData.length * 3];

        int counter = 0;
        for (int i = 0; i < rawData.length * 3; i += 3) {
            idealData[i]     = (rawData[counter]       & 0xFF);
            idealData[i + 1] = (rawData[counter] >> 8  & 0xFF);
            idealData[i + 2] = (rawData[counter] >> 16 & 0xFF);

            counter++;
        }
    }

    static double calculateError(BufferedImage canvas) {
        long error = 0;

        final int[] canvasData = ((DataBufferInt)canvas.getRaster().getDataBuffer()).getData();

        int counter = 0;
        for (int i = 0; i < canvasData.length; i += APPROXIMATION) {
            error += Math.abs((canvasData[i]       & 0xFF) - (idealData[counter]));
            error += Math.abs((canvasData[i] >>  8 & 0xFF) - (idealData[counter + 1]));
            error += Math.abs((canvasData[i] >> 16 & 0xFF) - (idealData[counter + 2]));

            counter += 3 * APPROXIMATION;
        }

        return error;
    }

2 个答案:

答案 0 :(得分:2)

如果您知道BufferedImage的格式(例如,因为您使用构造函数实例化了它们),那么还有一种更快的方法。

如果BufferedImage的类型为TYPE_3BYTE_BGR,请执行以下操作:

byte[] canvasData = ((DataBufferByte)canvas.getRaster().getDataBuffer()).getData();
byte[] idealData  = ((DataBufferByte)ideal .getRaster().getDataBuffer()).getData();

int error = 0;
for (int i = 0; i < canvasData.length; i++) {
    error += Math.abs((canvasData[i] & 0xFF) - (idealData[i] & 0xFF));
}

如果BufferedImage的类型为TYPE_INT_RGB,请执行以下操作:

int[] canvasData = ((DataBufferInt)canvas.getRaster().getDataBuffer()).getData();
int[] idealData  = ((DataBufferInt)ideal .getRaster().getDataBuffer()).getData();

int error = 0;
for (int i = 0; i < canvasData.length; i++) {
    error += Math.abs((canvasData[i]       & 0xFF) - (idealData[i]       & 0xFF));
    error += Math.abs((canvasData[i] >>  8 & 0xFF) - (idealData[i] >>  8 & 0xFF));
    error += Math.abs((canvasData[i] >> 16 & 0xFF) - (idealData[i] >> 16 & 0xFF));
}

(免责声明:未经测试的代码,但是我经常做的事情足以使我确信)

答案 1 :(得分:1)

您可以为每个点创建两个renderPlot实例,这很多。从int提取RGB的方法要快得多(请查看Color的来源)。

更重要的是,您一点一点地提取点,这通常非常慢(因为它们在Color中的组织方式可能不同)。调用一次将更多的提取到BufferedImage中的方法。

AFAIK有一种让图像计算结果的方法,它可能仍然更快。

  

我已经尝试过使用int[]不好,我真的可以使用一些建议。

这也应该有所帮助,但仅取决于您拥有的内核数。但是,使用并行流通常要简单得多。但这是一个不同的故事(问题)。