java - BufferedImage 交换红色和蓝色 channel

标签 java algorithm graphics colors bufferedimage

我的目标是交换 java BufferedImage 的红色和蓝色 channel 。

除了低效地迭代每个像素值和交换 channel 之外,还有什么方法可以实现这一目标吗?我在想一些我不知道的按位魔术或一些集成函数。

感谢任何帮助。

最佳答案

这是一种解决方案,速度非常快,因为它不会真正改变数据,只会改变数据的显示方式。

诀窍在于 channel 顺序(字节顺序)由 SampleModel 控制。并且您可以在不实际更改数据的情况下更改样本模型,以使相同的数据显示不同。

如果您已经有一个 BufferedImage,创建一个带有交换 channel 的示例模型的最简单方法是使用 Raster 创建一个新的子 Raster。 createWritableChild(...) 方法,并在最后一个参数中指定 channel (或“波段”)顺序。

bgr.getRaster().createWritableChild(0, 0, bgr.getWidth(), bgr.getHeight(), 0, 0, 
                                    new int[]{2, 1, 0}); // default order is 0, 1, 2

在下面的例子中,图像数据是相同的(如果有疑问,请尝试移动绘画部分,克隆图像后,看看结果是否相同)。仅交换 channel :

public static void main(String[] args) {
    // Original
    final BufferedImage bgr = new BufferedImage(100, 100, BufferedImage.TYPE_3BYTE_BGR);

    // Paint something
    Graphics2D graphics = bgr.createGraphics();
    try {
        graphics.setColor(Color.BLUE);
        graphics.fillRect(0, 0, bgr.getWidth(), bgr.getHeight());
        graphics.setColor(Color.YELLOW);
        graphics.fillRect(0, 0, bgr.getWidth(), bgr.getHeight() / 3);
        graphics.setColor(Color.GREEN);
        graphics.fillRect(0, 0, bgr.getWidth() / 3, bgr.getHeight());
    }
    finally {
        graphics.dispose();
    }

    // Clone, and swap BGR -> RGB
    ColorModel colorModel = bgr.getColorModel();
    WritableRaster swapped = bgr.getRaster().createWritableChild(0, 0, bgr.getWidth(), bgr.getHeight(), 0, 0, 
                                                                 new int[]{2, 1, 0}); // default order is 0, 1, 2
    final BufferedImage rgb = new BufferedImage(colorModel, swapped, colorModel.isAlphaPremultiplied(), null);

    System.err.println("bgr: " + bgr); // TYPE_3BYTE_BGR (5)
    System.err.println("rgb: " + rgb); // TYPE_CUSTOM (0)

    // Display it all
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            JFrame frame = new JFrame();
            frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

            frame.add(new JLabel(new ImageIcon(bgr)), BorderLayout.WEST);
            frame.add(new JLabel(new ImageIcon(rgb)));

            frame.pack();
            frame.setLocationRelativeTo(null);

            frame.setVisible(true);
        }
    });
}

PS:我从评论中知道 OP 不需要这个,但是如果您出于某种原因确实需要交换像素数据的 channel (即 native 库需要),最快的可能是获取数据,循环并交换红色和蓝色(第 1 和第 3)组件:

byte[] data = ((DataBufferByte) bgr.getRaster().getDataBuffer()).getData();
for (int i = 0; i < data.length; i += 3) {
    // Swap 1st and 3rd component
    byte b = data[i];
    data[i] = data[i + 2];
    data[i + 2] = b;
 }

关于java - BufferedImage 交换红色和蓝色 channel ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53136655/

相关文章:

iphone - 如何改进 2D 横向卷轴 iPhone 游戏的 "smoothness"?

java - 如何检查两个实例在android中具有相同的值?

Java applet 和他们的 future ?

java - 如何只在主 Activity 中显示菜单?

c++ - 迭代对象 vector 并找到与从文本文件中提取的变量相匹配的变量

c++ - 从加载的高度图中索引三角形的方法?

java - 如何修复我的 java 方法以正确迭代字符串?

algorithm - QBasic 中狐兔追逐模拟的最佳方式

algorithm - 如何在 1491625 这样的数字中找到第 n 个数字......?

r - R 中具有 95% 置信区间的箱线图