Java图像通道顺序变换(rgb转为bgr)

原理

  • 要使得rgb和bgr互换,只需调换r和b通道。Java中借助BufferedImage进行转化,详见代码。
    在这里插入图片描述

效果

在这里插入图片描述
在这里插入图片描述

Java代码

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class RGB2BGR {
	public static void main(String[] args) throws IOException {
		FileInputStream fileInputStream = new FileInputStream("d:\\rgb.jpg");
		byte[] imgBytes = new byte[fileInputStream.available()];
		fileInputStream.read(imgBytes);
		fileInputStream.close();
		BufferedImage bufferedImage = ImageIO.read(new ByteArrayInputStream(imgBytes));
		int width = bufferedImage.getWidth();
		int height = bufferedImage.getHeight();
        // 获取图片中每个rgb像素的int类型表示
		int[] rgbPixels = bufferedImage.getRGB(0, 0, width, height, null, 0, width);
		int[] bgrPixels = new int[rgbPixels.length];
		for (int i = 0; i < rgbPixels.length; i++) {
			int color = rgbPixels[i];
			int red = ((color & 0x00FF0000) >> 16);
			int green = ((color & 0x0000FF00) >> 8);
			int blue = color & 0x000000FF;
            // 将rgb三个通道的数值合并为一个int数值,同时调换b通道和r通道
			bgrPixels[i] = (red & 0x000000FF) | (green << 8 & 0x0000FF00) | (blue << 16 & 0x00FF0000);
		}
		bufferedImage.setRGB(0, 0, width, height, bgrPixels, 0, width);
		ImageIO.write(bufferedImage, "jpg", new File("d:\\bgr.jpg"));
	}
}

python代码

import cv2

img = cv2.imread('d:\\rgb.jpg')
img = img[:,:, (2, 1, 0)]
cv2.imwrite('d:\\bgr.jpg',img)

Java vs Python 代码量

在这里插入图片描述
Life is short, you need Python
在这里插入图片描述

参考文章

  • https://www.cnblogs.com/roucheng/p/3527655.html
  • https://blog.youkuaiyun.com/river66/article/details/89514816

思路来源

在这里插入图片描述
走过的弯路:ColorConvertOp只能在不同颜色空间之间相互转换,rgb和bgr都属于ColorSpace.CS_sRGB(可以调试观察BufferedImage的各个属性值),所以下面的转换是失败的,转换后的图片和转换前是一样的,因为都是同个颜色空间,所以底层只是做了复制,具体可以查看源码。

// 转RGB格式
// 参考:https://www.zhangshengrong.com/p/2EaE0rPR1M/
BufferedImage rgbImage = new BufferedImage(bgrImage.getWidth(), bgrImage.getHeight(), bgrImage.TYPE_3BYTE_BGR);
new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_sRGB), null).filter(bgrImage, rgbImage);
ImageIO.write(rgbImage, "jpg", new File("d:\\rgb.jpg"));
<think>好的,我需要解决用户的问题:如何使用ND4J的INDArray将RGB图像转换为BGR格式。首先,我得回忆一下ND4J的INDArray操作,特别是多维数组的处理。用户提供的引用[2]提到了使用mul方法进行元素乘法,这可能与通道顺序调整有关吗? 首先,RGBBGR的区别在于颜色通道顺序RGB是红、绿、蓝,而BGR是蓝、绿、红。所以转换的关键在于交换第一个和第三个颜色通道。假设图像数据的形状是(高度,宽度,通道),也就是常见的HWC格式,那么第三个维度就是通道。 接下来,我需要确认INDArray的结构。用户提到的引用[1]中,图片的shape是[1080, 1440, 3],也就是HWC排列。因此,转换需要交换通道的位置。例如,原始索引为0的通道是R,索引2是B,交换这两个即可得到BGR。 在ND4J中,可以使用permute方法来重新排列维度。permute方法接受新的维度顺序作为参数。例如,对于一个三维数组,原顺序是(0,1,2),对应H、W、C。要交换C的顺序,将最后一个维度调整为(2,1,0)?或者可能需要更具体的调整。例如,假设原来的通道顺序是R(索引0)、G(索引1)、B(索引2),要变成BGR,就需要将通道顺序变为索引2、1、0。因此,应该对第三个维度进行反转。 具体来说,可以使用INDArray的get方法配合NDArrayIndex来提取各个通道,然后按顺序合并。例如,先提取B通道(索引2),然后G(索引1),最后R(索引0),再将它们堆叠起来。或者是否有更高效的permute或rearrange操作? 另外,需要注意是否数据是连续的的,或者是否需要使用dup()来复制数组以避免视图问题。此外,可能需要使用ND4J的concat方法将通道重新组合。 例如,步骤可能如下: 1. 从原始INDArray中分别提取R、G、B通道。 2. 按B、G、R的顺序将这三个通道合并,形成新的INDArray。 或者,如果INDArray支持沿着通道轴的反转,可以直接反转第三个维度的顺序。例如,使用slice和reverse操作。 另外,检查ND4J的文档是否有内置的函数可以直接交换通道。例如,是否存在类似OpenCV中的cvtColor函数,但如果没有,就需要手动操作。 例如,在代码中,假设原始图像rgbArray,形状为[height, width, 3],那么可以这样做: INDArray bgrArray = Nd4j.create(rgbArray.shape()); bgrArray.put(new INDArrayIndex[]{all(), all(), point(0)}, rgbArray.get(all(), all(), point(2))); bgrArray.put(new INDArrayIndex[]{all(), all(), point(1)}, rgbArray.get(all(), all(), point(1))); bgrArray.put(new INDArrayIndex[]{all(), all(), point(2)}, rgbArray.get(all(), all(), point(0))); 或者,使用更简洁的方式: INDArray bgrArray = rgbArray.get(NDArrayIndex.all(), NDArrayIndex.all(), NDArrayIndex.interval(2, -1)); 但这样可能无法直接得到正确的顺序。另一种方法是使用permute,但permute改变的是维度的顺序,而不是通道顺序。例如,如果原数组是HWC,想要交换通道,可能需要使用permute(0,1,2)来保持H和W不变,但改变通道顺序。不过,permute通常用于改变维度顺序,比如将HWC转换为CHW,而不是改变同一维度的顺序。 或许更有效的方法是使用INDArray的get操作配合NDArrayIndex来提取各个通道,然后使用Nd4j.concat()将它们按BGR顺序合并。例如: INDArray rChannel = rgbArray.get(..., 0); INDArray gChannel = rgbArray.get(..., 1); INDArray bChannel = rgbArray.get(..., 2); 然后,将bChannel、gChannel、rChannel沿着通道轴(第三维)连接起来。但concat需要指定连接的维度,假设通道轴是2,那么: INDArray bgrArray = Nd4j.concat(2, bChannel, gChannel, rChannel); 但需要确认每个通道的shape是否正确。例如,每个通道的shape应该是[height, width, 1],而concat沿着axis=2后,得到[height, width, 3]。 因此,正确的步骤应该是: 1. 分割原始数组的通道。 2. 按BGR顺序重新组合。 另外,还可以使用INDArray的permute方法来调整维度,但可能不适用,因为permute是交换维度而不是同一维度内的顺序。 总结,步骤可能如下: - 使用get方法提取各个通道。 - 使用concat按BGR顺序合并。 现在需要验证这种方法的正确性,并确保操作后的数组数据正确无误。同时,需要注意内存和效率问题,但用户可能更关注正确性。 此外,用户提供的引用[2]中的mul方法可能不直接相关,但说明ND4J支持元素级操作,而通道交换可能需要更复杂的索引操作。 最后,给出代码示例,并解释每个步骤的作用,确保用户能够理解如何实现转换。</think>要将 RGB 图像转换为 BGR 格式,需调整颜色通道顺序。假设图像数据的 `INDArray` 形状为 `(height, width, channels)`(即 HWC 格式),以下是实现步骤及代码示例: --- ### 方法说明 1. **提取通道**:分别提取 RGB 的三个通道(索引 0 为 R,1 为 G,2 为 B)。 2. **重新组合**:按 BGR 顺序(即 B→G→R)将通道合并,生成新的 `INDArray`。 --- ### 代码实现 ```java // 原始RGB图像,假设形状为 [height, width, 3] INDArray rgbArray = ...; // 提取各通道(注意:索引从0开始) INDArray rChannel = rgbArray.get(NDArrayIndex.all(), NDArrayIndex.all(), NDArrayIndex.point(0)); // R INDArray gChannel = rgbArray.get(NDArrayIndex.all(), NDArrayIndex.all(), NDArrayIndex.point(1)); // G INDArray bChannel = rgbArray.get(NDArrayIndex.all(), NDArrayIndex.all(), NDArrayIndex.point(2)); // B // 按BGR顺序合并通道(沿第2维度拼接) INDArray bgrArray = Nd4j.concat(2, bChannel, gChannel, rChannel); ``` --- ### 关键点解释 - **索引操作**:`get(NDArrayIndex.all(), NDArrayIndex.all(), NDArrayIndex.point(n))` 用于提取第 `n` 个通道。 - **拼接维度**:`Nd4j.concat(2, ...)` 表示沿通道维度(索引 2)拼接数据。 - **性能优化**:直接操作内存索引,无需逐像素处理,效率较高[^2]。 --- ### 应用场景 此方法适用于需与 BGR 格式兼容的深度学习框架(如 OpenCV 或某些预训练模型)交互的场景。例如,在引用[4]提到的车牌识别项目中,若模型输入为 BGR,可通过此方法预处理图像[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值