如何使用并行计算从 BufferedImage 中获取 RGB 像素的 int[]?

How do I fetch an int[] of RGB pixels from a BufferedImage using parallel computing?

我正在尝试使用并行计算从 BufferedImage 中获取 int[] 个像素。更具体地说,我将图像从宽度分成 64 位块,并计算每个部分的像素。我使用并行计算的主要原因是我正在开发一个视频播放器,我想使用多线程来解析帧像素。

通常情况下,您可以使用以下代码轻松获取所有像素:

(1a)

final int width = image.getWidth();
final int[] pixels = image.getRGB(0, 0, width, image.getHeight(), null, 0, width );

然而,在我的例子中,我尝试使用 IntStreamparallel() 方法来帮助并行化进程:

(1b)

  public static int[] getRGBFast(@NotNull final BufferedImage image) {
    final int width = image.getWidth();
    final int height = image.getHeight();
    final int[] rgb = new int[width * height];
    final int num = width / 64;
    final int leftover = width - num * 64;
    IntStream.range(0, num + (width % 64 == 0 ? 0 : 1))
        .parallel()
        .forEach(chunk -> {
          final int pixel = chunk << 6;
          if (chunk == num) {
            image.getRGB(pixel, 0, leftover, height, rgb, 0, width);
          } else {
            image.getRGB(pixel, 0, 64, height, rgb, 0, width);
          }
        });
    return rgb;
  }

当比较(1a)(1b)的结果时,似乎几乎所有的像素都错位了。我使用下面的代码来比较两个数组:

    for (int i = 0; i < rgb.length; i++) {
      final int color = rgb[i];
      final int old = original[i];
      if (color != old) {
        System.out.printf("Index: %d mismatch [%d,%d]%n", i, color, old);
      }
    }

最后几千行的结果are as follows。它后面还有更多行显示像素不匹配。对于视觉方面,我 运行 代码 10 次并为其显示图像。出于某种原因,每次迭代的结果似乎都不同:

作为参考,原图是这样的:

我不确定我的算法哪里有缺陷。谁能指出我可能遇到的问题?

在此代码中,

  if (chunk == num) {
    image.getRGB(pixel, 0, leftover, height, rgb, 0, width);
  } else {
    image.getRGB(pixel, 0, 64, height, rgb, 0, width);
  }

getRGBoffset 参数始终为零。因此,每个块都将以零偏移量写入数组的“最左边”部分(当数组被解释为 2D width x height 图像时最左边的部分)。不同的线程写入同一区域,最后一个写入 运行“获胜”,它逐行变化 运行,甚至逐像素变化 运行 - 这解释了不同结果和故障。

为避免移动块,偏移量应与x坐标匹配(一般来说,偏移量应为左上角像素的索引,x + y * width,此处为y为零,因此仅 x 剩余):(未测试)

  if (chunk == num) {
    image.getRGB(pixel, 0, leftover, height, rgb, pixel, width);
  } else {
    image.getRGB(pixel, 0, 64, height, rgb, pixel, width);
  }

顺便说一下,我建议沿 y 轴而不是 x 轴划分图像,以便每个线程复制的区域是连续的。这不是更正确,但它可能更有效,也不是更困难。