【问题标题】:How do I fetch an int[] of RGB pixels from a BufferedImage using parallel computing?如何使用并行计算从 BufferedImage 中获取 RGB 像素的 int[]?
【发布时间】:2021-10-25 03:45:39
【问题描述】:

我正在尝试使用并行计算从 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 次代码并显示了它的图像。出于一个奇怪的原因,每次迭代的结果似乎都不同:

作为参考,原图如下:

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

【问题讨论】:

  • 不应该scansizewidth
  • @tgdavies 我在这里有点困惑。我被告知它通常应该是宽度。就我而言,我正在处理 64 位宽度的块,因此我将其设置为 64。但是对于剩余部分,我将其设置为剩余部分。如果我将它设置为宽度,我会得到奇怪的结果。
  • wh 指的是图像中的区域,但scansize 只是rgbArray 的名义宽度。
  • @tgdavies 嗯。我试过了,现在似乎已经填满了整个数组,但是,比较时有些像素不匹配。也许我在某个地方多次填充一个像素?
  • 请用您的新代码更新您的问题并说明哪些像素不匹配。

标签: java parallel-processing bufferedimage


【解决方案1】:

在这段代码中,

  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 图像时最左边的部分),偏移量为零。不同的线程写入同一个区域,最后一个运行“wins”,逐个运行,逐行,甚至逐个像素地变化 - 这解释了不同的结果和故障。

为了避免移动块,偏移量应该与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 轴划分图像,以便每个线程复制的区域是连续的。这不是更正确,但它可能更有效,也不会更困难。

【讨论】:

  • 这似乎成功了。感谢所有帮助过的人!而且我想知道使用 y 轴而不是 x 轴。我想知道为什么它会更有效率?
  • @BrandonLi 与一系列列不同,一系列行将是连续的,这通常有利于引用的局部性,并且在多线程场景中也降低了False Sharing (当两个“相邻”线程写入彼此靠近的数组元素时,可能会发生这种情况)。在这种情况下,这些影响可能很小,但总的来说,这就是为什么块通常是图像的水平切片(或方形图块,但很少是垂直切片)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-02-22
  • 1970-01-01
  • 1970-01-01
  • 2013-11-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多