Java ImageIO灰度PNG问题
我有一个灰度图像(实际上是“lena”)我想试验一下.我把它作为512×512 PNG文件,有216种灰度.
当我用Java ImageIO阅读它时,会发生什么: String name = args[0]; File fi = new File(name); BufferedImage img = ImageIO.read(fi); 我得到一个只有154种颜色的BufferedImage!我只是意识到这一点,导致我处理过的图像显得粗糙,缺乏深黑色. 更刺激的是,当我使用XnView将PNG转换为GIF时,在这种情况下这是一个无损程序,用上面的代码读取GIF,我在BufferedImage中得到所有216种颜色. 是否有某种文档或描述,当我的PNG读取它时会发生什么?有设置来解决这个问题吗?我在最近的JDK1.8上做过这些实验.只是我对Java PNG支持的信任现在已经丢失,我稍后会使用彩色PNG. 解决方法
欢迎来到Java隐藏色彩管理的“伟大”世界!
对于Java(至少是ImageIO),内部的所有内容都是sRGB,它暗示着颜色管理,这通常会对实际想要做的事情产生相反的效果. 然后,当你访问像素(我假设你使用img.getRGB()或类似的东西?)时,你实际上访问sRGB值(Windows上的Java默认颜色空间). 结果是,当转换为sRGB时,其伽马值为~2.2(sRGB的伽玛实际上有点复杂,但总体上接近2.2),这有效地将(1 / Gamma)= 2.2的伽马校正应用于图像,(a)使你的图像显得“轻”,(b)由于伽玛校正从256到256个离散值,你也有效地松散了你的一些灰色阴影. 如果以不同方式访问BufferedImage的数据,也可以看到效果: ColorSpace colorSpace = img.getColorModel().getColorSpace(); if ( colorSpace instanceof ICC_ColorSpace ) { ICC_Profile profile = ((ICC_ColorSpace)colorSpace).getProfile(); if ( profile instanceof ICC_ProfileGray ) { float gamma = ((ICC_ProfileGray)profile).getGamma(); system.out.println("Gray Profile Gamma: "+gamma); // 1.0 ! } } b)以不同方式访问某些像素值… //access sRGB values (Colors translated from img's ICC profile to sRGB) System.out.println( "pixel 0,0 value (sRGB): " + Integer.toHexString(img.getRGB(0,0)) ); // getRGB() actually means "getSRGB()" //access raw raster data,this will give you the uncorrected gray value //as it is in the image file Raster raster = image.getRaster(); System.out.println( "pixel 0,0 value (RAW gray value): " + Integer.toHexString(raster.getSample(0,0)) ); 如果您的像素(0,0)不是偶然的100%黑色或100%白色,您将看到sRGB值比灰度值“更高”,例如gray = d1 – > sRGB = ffeaeaea(阿尔法,红色,绿色,蓝色). 从我的角度来看,它不仅会降低您的灰度级,还会使您的图像更亮(与使用1 /伽玛值为2.2的伽马校正相同).如果没有嵌入式ICC配置文件的灰色图像的Java将灰色转换为具有R = G = B = grayValue的sRGB,或者将分配ICC灰度配置文件WhitePoint = D50,Gamma = 2.2(至少在Windows上),则更合乎逻辑.由于sRGB不完全是Gamma 2.2,后者仍然会让你失去一些灰色调. 关于它为什么适用于GIF:GIF格式没有“灰度”或ICC配置文件的概念,因此您的图像是256色调色板图像(256色恰好是256色灰度).在打开GIF时,Java假定RGB值是sRGB. 解: 关于您对java或PNG的信任:由于它具有隐含的颜色转换,我在很多方面都在努力研究java ImageIO.我们的想法是内置色彩管理,而开发人员不需要太多关于色彩管理的知识.只要您只使用sRGB(并且您的输入也是sRGB,或者没有颜色配置文件,因此可以合法地认为是sRGB),这在一定程度上有效.如果输入图像中有其他颜色空间(例如AdobeRGB),则会启动麻烦.灰色也是另一回事,尤其是ImageIO假设Gamma = 1.0的(异常)灰度轮廓.现在要了解ImageIO正在做什么,您不仅需要知道您在颜色管理中的ABC,还需要弄清楚java正在做什么.我没有在任何文档中找到此信息!结论:ImageIO确实可以认为是正确的.这通常不是你所期望的,你可能会深入挖掘,找出原因或改变行为,如果它不是你想要做的. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |