java:图像(BufferedImage)色彩空间转换(灰度)暨获取图像矩阵数据byte[](sRGB/gray)

ColorConvertOp

java.awt.image包下面有个类java.awt.image.ColorConvertOp,类名直译就是"颜色转换操作"。
顾名思义,它的作用就是将一个色彩空间(color space)的图像转换为另一个色彩空间的图像。有了这个神器我们就能轻易的将一张彩色图你像转换成灰度(gray)或其他色彩空间图像。
代码非常简单,只要一行。

	public BufferedImage toGray(BufferedImage srcImg){		
		return new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null).filter(srcImg, null);
	}

依此类推,你可以参照ColorConvertOp的参数说明将图像转为其他格式。
java.awt.color.ColorSpace中列出了很多支持的色彩空间定义TYPE_RGB,TYPE_CMYK,TYPE_HSV,TYPE_YCbCr

Raster.getDataElements

有时我们通过ImageIO得到解码后的图像数据对象(BufferedImage)以后,需要获取图像矩阵的裸数据(即一个存储图像数据的byte数组)。
BufferedImage中提供了一个getRGB()方法,它返回的是一个ARGB格式int[]数组(每个int型元素的4个字节分别代表一个像素的Alpha,Red,Green,Blue四个通道)
如果你要从这个方法获取RGB的数组,你还得自己写转换代码:

	/**
	 * 返回图像的RGB格式字节数组
	 * @param image
	 * @return
	 */
	public static byte[] getMatrixRGB(BufferedImage image){
		int w = image.getWidth();
		int h = image.getHeight();
		int[] intArray = new int[w * h];
		byte[] matrixRGB = new byte[w * h * 3];
		image.getRGB(0, 0, w, h, intArray, 0, w);
		// ARGB->RGB
	    for(int i=0,b=0;i<intArray.length;++i){
	    	matrixRGB[b++]=(byte) (matrixRGB[i]&0x000000FF);
	    	matrixRGB[b++]=(byte) ((matrixRGB[i]&0x0000FF00)>>8);
	    	matrixRGB[b++]=(byte) ((matrixRGB[i]&0x00FF0000)>>16);
	    }
	    return matrixRGB;
	}

好烦呐,我以前就是这么干的,真的没有提供更好的方法吗?
不是没有更好的方法,而是我学艺不精没找到而已。
在仔细研究了BufferedImage的代码之后,才明白getRGB()只是BufferedImage为默认 RGB 颜色模型 (TYPE_INT_ARGB)提供的一个便利性封装。
通过getRGB()源码可以知道BufferedImage对象中真正的图像数据是由成员对象raster(java.awt.image.WritableRaster)管理。而WritableRasterjava.awt.image.Raster的子类。Raster中getDataElements方法可以我们所需要的字节数组。
还以前面图像转灰度举例,如果要从灰度图像中获取图像矩阵的字节数组,代码示例如下:

	/**
	 * 获取灰度图像的字节数组
	 * @param image
	 * @return
	 */
	public static byte[] getMatrixGray(BufferedImage image) {
			// 转灰度图像
			BufferedImage grayImage = new BufferedImage(width, height,  
		                BufferedImage.TYPE_BYTE_GRAY);		
			new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null).filter(image, grayImage);
			// getData方法返回BufferedImage的raster成员对象
		    return (byte[]) grayImage.getData().getDataElements(0, 0, image.getWidth(), image.getHeight(), null);		
	}

注意这里return语句使用了(byte[])强制类型转换,因为getDataElements返回的是打开声明 java.lang.Object对象。
也就是说getDataElements返回的未必是byte[]类型,为什么呢?看下面getDataElements方法的说明:
这里写图片描述
看不懂没关系,我们可以看到这里的返回的类型可能是:TYPE_BYTE,TYPE_USHORT,TYPE_INT,TYPE_SHORT,TYPE_FLOAT,TYPE_DOUBLE。并不一定是byte。
那么问题来了,如何控制返回的数组类型是byte[]呢?
同样,我们可以使用前面的ColorConvertOp对象进行转换。
比如我们需要得到图像的RGB数据:

	/**
	 * 获取图像RGB格式数据
	 * @param image
	 * @return
	 */
	public static byte[] getMatrixRGB(BufferedImage image){
		if(image.getType()!=BufferedImage.TYPE_3BYTE_BGR){
			// 转sRGB格式
			BufferedImage rgbImage = new BufferedImage(
						image.getWidth(), 
						image.getHeight(),  
		                BufferedImage.TYPE_3BYTE_BGR);
			new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_sRGB), null).filter(image, rgbImage);
			// 从Raster对象中获取字节数组
			return (byte[]) rgbImage.getData().getDataElements(0, 0, rgbImage.getWidth(), rgbImage.getHeight(), null);
		}else{
			return (byte[]) image.getData().getDataElements(0, 0, image.getWidth(), image.getHeight(), null);
		}
	}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

10km

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值