如何使用并行计算从 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 );
然而,在我的例子中,我尝试使用 IntStream
和 parallel()
方法来帮助并行化进程:
(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);
}
getRGB
的 offset
参数始终为零。因此,每个块都将以零偏移量写入数组的“最左边”部分(当数组被解释为 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
轴划分图像,以便每个线程复制的区域是连续的。这不是更正确,但它可能更有效,也不是更困难。
我正在尝试使用并行计算从 BufferedImage
中获取 int[]
个像素。更具体地说,我将图像从宽度分成 64 位块,并计算每个部分的像素。我使用并行计算的主要原因是我正在开发一个视频播放器,我想使用多线程来解析帧像素。
通常情况下,您可以使用以下代码轻松获取所有像素:
(1a)
final int width = image.getWidth();
final int[] pixels = image.getRGB(0, 0, width, image.getHeight(), null, 0, width );
然而,在我的例子中,我尝试使用 IntStream
和 parallel()
方法来帮助并行化进程:
(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);
}
getRGB
的 offset
参数始终为零。因此,每个块都将以零偏移量写入数组的“最左边”部分(当数组被解释为 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
轴划分图像,以便每个线程复制的区域是连续的。这不是更正确,但它可能更有效,也不是更困难。