BufferedImage 交换红色和蓝色通道
BufferedImage swap red and blue channel
我的目标是交换 java BufferedImage
.
的红色和蓝色通道
除了低效地迭代每个像素值和交换通道之外,还有什么方法可以实现这一目标吗?我在想一些我不知道的按位魔术或一些集成函数。
感谢任何帮助。
也许您创建了一个 BufferedImage
的新实例,具有相同的 WritableRaster raster
和相同的属性,但使用颜色交换的 ColorModel:
例如:
ColorModel swappedColorModel = new DirectColorModel(24,
0x000000ff, // Red -> Blue
0x0000ff00, // Green
0x00ff0000, // Blue -> Red
0x0 // Alpha
);
BufferedImage swapedColorImage = new BufferedImage (swappedColorModel,
originalImage.getRaster(),
swappedColorModel.isAlphaPremultiplied(),
properties);
我没有试过这个代码
这是一种解决方案,速度非常快,因为它不会真正改变数据,只会改变数据的显示方式。
诀窍在于通道顺序(字节顺序)由SampleModel
控制。并且您可以在不实际更改数据的情况下更改样本模型,以使相同的数据显示不同。
如果您已经有 BufferedImage
,创建带有交换通道的示例模型的最简单方法是创建一个新的子 Raster
,使用 Raster.createWritableChild(...)
方法,并指定最后一个参数中的通道(或 "band")顺序。
bgr.getRaster().createWritableChild(0, 0, bgr.getWidth(), bgr.getHeight(), 0, 0,
new int[]{2, 1, 0}); // default order is 0, 1, 2
下面的例子中,图片数据是一样的(如果有疑问,尝试移动绘画部分,克隆图片后,看结果是一样的)。仅交换频道:
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 不需要这个,但是如果您出于某种原因确实需要交换像素数据的通道(即本机库需要) ,最快的可能是获取数据,循环并交换红色和蓝色(第一个和第三个)组件:
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
.
除了低效地迭代每个像素值和交换通道之外,还有什么方法可以实现这一目标吗?我在想一些我不知道的按位魔术或一些集成函数。
感谢任何帮助。
也许您创建了一个 BufferedImage
的新实例,具有相同的 WritableRaster raster
和相同的属性,但使用颜色交换的 ColorModel:
例如:
ColorModel swappedColorModel = new DirectColorModel(24,
0x000000ff, // Red -> Blue
0x0000ff00, // Green
0x00ff0000, // Blue -> Red
0x0 // Alpha
);
BufferedImage swapedColorImage = new BufferedImage (swappedColorModel,
originalImage.getRaster(),
swappedColorModel.isAlphaPremultiplied(),
properties);
我没有试过这个代码
这是一种解决方案,速度非常快,因为它不会真正改变数据,只会改变数据的显示方式。
诀窍在于通道顺序(字节顺序)由SampleModel
控制。并且您可以在不实际更改数据的情况下更改样本模型,以使相同的数据显示不同。
如果您已经有 BufferedImage
,创建带有交换通道的示例模型的最简单方法是创建一个新的子 Raster
,使用 Raster.createWritableChild(...)
方法,并指定最后一个参数中的通道(或 "band")顺序。
bgr.getRaster().createWritableChild(0, 0, bgr.getWidth(), bgr.getHeight(), 0, 0,
new int[]{2, 1, 0}); // default order is 0, 1, 2
下面的例子中,图片数据是一样的(如果有疑问,尝试移动绘画部分,克隆图片后,看结果是一样的)。仅交换频道:
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 不需要这个,但是如果您出于某种原因确实需要交换像素数据的通道(即本机库需要) ,最快的可能是获取数据,循环并交换红色和蓝色(第一个和第三个)组件:
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;
}