java.awt.image.BufferedImage 使用自定义 ColorSpace 24 位 RGB 到 8 位灰度转换
我想使用 java.awt.image.BufferedImage 进行简单的颜色到灰度转换。我是图像处理领域的初学者,所以如果我感到困惑,请原谅。
我的输入图像是 RGB 24 位图像(无 alpha),我想在输出上获得 8 位灰度 BufferedImage
,这意味着我有一个这样的类(详细信息省略清晰度):
public class GrayscaleFilter {
private BufferedImage colorFrame;
private BufferedImage grayFrame =
new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
到目前为止,我已经成功尝试了两种转换方法,第一种是:
private BufferedImageOp grayscaleConv =
new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
protected void filter() {
grayscaleConv.filter(colorFrame, grayFrame);
}
第二种是:
protected void filter() {
WritableRaster raster = grayFrame.getRaster();
for(int x = 0; x < raster.getWidth(); x++) {
for(int y = 0; y < raster.getHeight(); y++){
int argb = colorFrame.getRGB(x,y);
int r = (argb >> 16) & 0xff;
int g = (argb >> 8) & 0xff;
int b = (argb ) & 0xff;
int l = (int) (.299 * r + .587 * g + .114 * b);
raster.setSample(x, y, 0, l);
}
}
}
第一种方法工作速度更快,但生成的图像非常暗,这意味着我正在失去带宽,这是不可接受的(有灰度和 sRGB ColorModel
之间使用的一些颜色转换映射称为 tosRGB8LUT,据我所知,它对我来说效果不佳,但我不确定,我只是假设使用了这些值)。第二种方法虽然速度较慢,但效果很好。
有没有一种方法可以将这两者结合起来,例如。使用自定义索引 ColorSpace
进行 ColorConvertOp
?如果是,您能给我举个例子吗?
提前致谢。
I want to do a simple color to grayscale conversion using java.awt.image.BufferedImage
. I'm a beginner in the field of image processing, so please forgive if I confused something.
My input image is an RGB 24-bit image (no alpha), I'd like to obtain a 8-bit grayscale BufferedImage
on the output, which means I have a class like this (details omitted for clarity):
public class GrayscaleFilter {
private BufferedImage colorFrame;
private BufferedImage grayFrame =
new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
I've succesfully tried out 2 conversion methods until now, first being:
private BufferedImageOp grayscaleConv =
new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
protected void filter() {
grayscaleConv.filter(colorFrame, grayFrame);
}
And the second being:
protected void filter() {
WritableRaster raster = grayFrame.getRaster();
for(int x = 0; x < raster.getWidth(); x++) {
for(int y = 0; y < raster.getHeight(); y++){
int argb = colorFrame.getRGB(x,y);
int r = (argb >> 16) & 0xff;
int g = (argb >> 8) & 0xff;
int b = (argb ) & 0xff;
int l = (int) (.299 * r + .587 * g + .114 * b);
raster.setSample(x, y, 0, l);
}
}
}
The first method works much faster but the image produced is very dark, which means I'm losing bandwidth which is unacceptable (there is some color conversion mapping used between grayscale and sRGB ColorModel
called tosRGB8LUT which doesn't work well for me, as far as I can tell but I'm not sure, I just suppose those values are used). The second method works slower, but the effect is very nice.
Is there a method of combining those two, eg. using a custom indexed ColorSpace
for ColorConvertOp
? If yes, could you please give me an example?
Thanks in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
此处有一个示例,它与您的第一个示例不同一个小方面是
ColorConvertOp
的参数。试试这个:There's an example here which differs from your first example in one small aspect, the parameters to
ColorConvertOp
. Try this:尝试修改你的第二种方法。不是处理单个像素,而是检索 argb int 值的数组,将其转换并设置回来。
Try modifying your second approach. Instead of working on a single pixel, retrieve an array of argb int values, convert that and set it back.
第二种方法基于像素的亮度,因此可以获得更良好的视觉效果。使用查找数组或哈希表计算 l 时,可以通过优化昂贵的浮点算术运算来加快速度。
The second method is based on pixel's luminance therefore it obtains more favorable visual results. It could be sped a little bit by optimizing the expensive floating point arithmetic operation when calculate l using lookup array or hash table.
这是在某些情况下对我有用的解决方案。
取图像高度 y、图像宽度 x、图像颜色深度 m 和整数位大小 n。仅当 (2^m)/(x*y*2^n) >= 1 时才有效。
在处理初始灰度值时,为每个颜色通道保留一个位整数总计。将每个总计除以 (x*y) 即可得到每个通道的平均值 avr[channel]。将 (192 - avr[channel]) 添加到每个通道的每个像素。
请记住,这种方法可能不会具有与标准亮度方法相同的质量水平,但如果您正在寻找速度和质量之间的折衷方案,并且不想处理昂贵的浮点运算,那么它可能为你工作。
Here is a solution that has worked for me in some situations.
Take image height y, image width x, the image color depth m, and the integer bit size n. Only works if (2^m)/(x*y*2^n) >= 1.
Keep a n bit integer total for each color channel as you process the initial gray scale values. Divide each total by the (x*y) for the average value avr[channel] of each channel. Add (192 - avr[channel]) to each pixel for each channel.
Keep in mind that this approach probably won't have the same level of quality as standard luminance approaches, but if you're looking for a compromise between speed and quality, and don't want to deal with expensive floating point operations, it may work for you.