Java ImageIO读取的RGB值与其他方法略有不同

Java ImageIO读取的RGB值与其他方法略有不同,java,jpeg,rgb,javax.imageio,Java,Jpeg,Rgb,Javax.imageio,我发现使用Java时得到的RGB与使用ImageMagick、Gimp、Python和Octave时得到的RGB不同。最后4个都是一致的,所以我假设是正确的 对于这些示例,我使用以下测试图像:http://farm3.static.flickr.com/2811/9177301733_9836174725_o.jpg 测试像素x=4144 y=2768 R G B Java = (125, 107, 69) Paint.NET = (1

我发现使用Java时得到的RGB与使用ImageMagick、Gimp、Python和Octave时得到的RGB不同。最后4个都是一致的,所以我假设是正确的

对于这些示例,我使用以下测试图像:
http://farm3.static.flickr.com/2811/9177301733_9836174725_o.jpg

测试像素
x=4144 y=2768

               R    G    B
Java        = (125, 107, 69)
Paint.NET   = (125, 107, 69)
ImageMagick = (128, 106, 67)
Python      = (128, 106, 67)
Octave      = (128, 106, 67)
Gimp        = (128, 106, 67)
有什么好处

下面是一个使用imagemagick的快速测试:

convert image.jpg -crop 1x1+4144+2768 -depth 8 txt:
输出:

# ImageMagick pixel enumeration: 1,1,65535,srgb
0,0: (32896,27242,17219)  #806A43  srgb(128,106,67)
下面是一些java和python代码,它们也演示了这个问题:

import org.apache.commons.io.FileUtils;
import org.junit.Test;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;

public class ImageIOTest {
    @Test
    public void can_read_file() throws IOException, InterruptedException, URISyntaxException {
        File tempFile = File.createTempFile("image", "jpg");
        FileUtils.copyURLToFile(new URL("http://farm3.static.flickr.com/2811/9177301733_9836174725_o.jpg"), tempFile);

        BufferedImage image = ImageIO.read(tempFile);

        int javaRGB = image.getRGB(4144, 2768);
        int javaRed = (javaRGB >> 16) & 0xFF;
        int javaGreen = (javaRGB >> 8) & 0xFF;
        int javaBlue = (javaRGB >> 0) & 0xFF;
        System.out.printf("rgb: (%d, %d, %d)", javaRed, javaGreen, javaBlue);
    }
}
下面是相应的python脚本:

from PIL import Image
import sys, urllib, cStringIO

file = cStringIO.StringIO(urllib.urlopen("http://farm3.static.flickr.com/2811/9177301733_9836174725_o.jpg").read())

im = Image.open(file)
pix = im.load()
print pix[4144, 2768]
我试着用,希望能解决它,但没有骰子。还有其他的想法吗?如何使用java提取正确的RGB值?我肯定不是第一个有这个问题的人

更新 我尝试了
getRaster().getSample()
,但得到了相同的无效结果:
System.out.println(raster.getSample(41442768,0)+>,“+raster.getSample(41442768,1)+”,“+raster.getSample(41442768,2))输出:
125107,69

更多信息 下面是一些输出,显示了图像左上角前9个(3x3平方)像素由三种不同工具解码的RGB值。如您所见,Python和ImageMagick是一致的。Java有时会匹配。我在java不同意的地方放了一个X…:

Tool          [x, y] = (R , G , B )
ImageIO     : [0, 0] = (86, 90, 93)
Python      : [0, 0] = (86, 90, 93)
ImageMagick : [0, 0] = (86, 90, 93)

ImageIO     : [1, 0] = (86, 90, 93)
Python      : [1, 0] = (86, 90, 93)
ImageMagick : [1, 0] = (86, 90, 93)

ImageIO     : [2, 0] = (90, 91, 95) X
Python      : [2, 0] = (88, 92, 95)
ImageMagick : [2, 0] = (88, 92, 95)

ImageIO     : [0, 1] = (85, 93, 95)
Python      : [0, 1] = (85, 93, 95)
ImageMagick : [0, 1] = (85, 93, 95)

ImageIO     : [1, 1] = (85, 93, 95) X
Python      : [1, 1] = (87, 92, 95)
ImageMagick : [1, 1] = (87, 92, 95)

ImageIO     : [2, 1] = (87, 92, 95)
Python      : [2, 1] = (87, 92, 95)
ImageMagick : [2, 1] = (87, 92, 95)

ImageIO     : [0, 2] = (83, 93, 94)
Python      : [0, 2] = (83, 93, 94)
ImageMagick : [0, 2] = (83, 93, 94)

ImageIO     : [1, 2] = (83, 93, 94) X
Python      : [1, 2] = (84, 92, 94)
ImageMagick : [1, 2] = (84, 92, 94)

ImageIO     : [2, 2] = (83, 91, 93)
Python      : [2, 2] = (83, 91, 93)
ImageMagick : [2, 2] = (83, 91, 93)
为什么Java为某些像素提供不同的值?或者,是否有另一种(快速)方法可以使用本机Java代码生成正确的值

更新2016-09-26: 我提交了演示此问题的代码,并将其推送到github(),以便在不同的机器上轻松测试。事实证明,Java在OSX和UbuntuLinux上是一致的,但Python、ImageMagick和Octave是不一致的。换句话说,在Linux机器上,所有工具都是一致的,因此,我现在认为java一直都是正确的,而其他工具在OSX上给出了错误的结果!我仍然不明白为什么,也没有任何具体的证据来证明哪些值是正确的,但我正在取得进展…

请参阅:
警告:标记为sRGB的颜色空间,没有嵌入的颜色配置文件。Windows和Mac浏览器及应用程序随机处理颜色。

编辑:按版本编辑舍入误差和执行差异;对于这张图片来说,情况根本不是这样。Mac电脑有一种魔力,可以使蓝色和绿色在配色曲线上更亮。更正颜色空间,颜色匹配将给出相同的结果。我支持安迪·费多洛夫的答案,但我也注意到没有人真正给你一个解决方案。。。您已经得出结论,Java是正确的。随你的便。Libjpeg已经很久没有改变了。它稳定可靠,可跨多个平台和环境复制颜色。对老化的标准jpeg的解码未进行重大(无论如何)更改

编辑2:尝试创建一个示例,根据您的项目生成与Mac配置文件相同的值。需要从
库/ColorSync/Profiles
获取Mac的出厂ICC配置文件

这就是我要说的。下面是一个应用了sRGB ICC v4配置文件的示例。这在技术上是将sRGB应用于sRGB,但它解释了这个概念

private ICC_Profile cp=ICC_Profile.getInstance(“src/test/resources/sRGB_ICC_v4_Appearance.ICC”);
专用ICC_颜色空间cs=新ICC_颜色空间(cp);
private int[]getRGBUsingImageIO2(文件文件,int x,int y)引发IOException{
BuffereImage image=ImageIO.read(文件);
ColorConvertOp cco=新的ColorConvertOp(cs,null);
BuffereImage结果=cco.filter(图像,null);
int javaRGB=result.getRGB(x,y);
int javaRed=(javaRGB>>16)&0xFF;
int javaGreen=(javaRGB>>8)&0xFF;
int javaBlue=(javaRGB>>0)&0xFF;
返回新的int[]{javaRed,javaGreen,javaBlue};
}
图像IO 1:[0,0]=[145,146,164] 图像IO 2:[0,0]=[145,147,165] 图像IO 1:[1,0]=[137,138,156] 图像IO 2:[1,0]=[137,139,157] 图像IO 1:[2,0]=[148147161] 图像IO 2:[2,0]=[148148162] 图像IO 1:[0,1]=[150153168] 图像IO 2:[0,1]=[150154169] 图像IO 1:[1,1]=[138,141,156] 图像IO 2:[1,1]=[138142157] 图像IO 1:[2,1]=[145,147,159] 图像IO 2:[2,1]=[145,148,160] 图像IO 1:[0,2]=[154,160,172] 图像IO 2:[0,2]=[154161173] 图像IO 1:[1,2]=[146152164] 图像IO 2:[1,2]=[146,153,165] 图像IO 1:[2,2]=[144148157] 图像IO 2:[2,2]=[144149158]
您能否将您的颜色配置文件提交到imageio测试报告中?

颜色一致性和ICC配置文件

Java在上传图像时不尊重颜色配置文件。不同的操作系统处理RGB颜色也不同

下面是Oracle写的关于导入java.awt.color的内容:

通常,颜色或颜色模型将与ICC配置文件相关联,ICC配置文件是输入、显示或输出配置文件。还有其他类型的ICC配置文件,例如抽象配置文件、设备链接配置文件和命名颜色配置文件,它们不包含适合表示颜色、图像或设备颜色空间的信息。试图从不适当的ICC配置文件创建ICC_ColorSpace对象是错误的

ICC配置文件表示从配置文件颜色空间(如显示器)到配置文件连接空间(PCS)的转换。用于标记图像或颜色的配置文件有一个PCS,它是ICC配置文件格式规范中定义的设备独立空间(一个CIEXYZ空间和两个CIELab空间)之一。大多数感兴趣的配置文件要么具有可逆转换,要么显式指定双向转换。应该使用ICC_颜色空间对象吗 Image IO 1 : [0, 0] = [145, 146, 164] Image IO 2 : [0, 0] = [145, 147, 165] Image IO 1 : [1, 0] = [137, 138, 156] Image IO 2 : [1, 0] = [137, 139, 157] Image IO 1 : [2, 0] = [148, 147, 161] Image IO 2 : [2, 0] = [148, 148, 162] Image IO 1 : [0, 1] = [150, 153, 168] Image IO 2 : [0, 1] = [150, 154, 169] Image IO 1 : [1, 1] = [138, 141, 156] Image IO 2 : [1, 1] = [138, 142, 157] Image IO 1 : [2, 1] = [145, 147, 159] Image IO 2 : [2, 1] = [145, 148, 160] Image IO 1 : [0, 2] = [154, 160, 172] Image IO 2 : [0, 2] = [154, 161, 173] Image IO 1 : [1, 2] = [146, 152, 164] Image IO 2 : [1, 2] = [146, 153, 165] Image IO 1 : [2, 2] = [144, 148, 157] Image IO 2 : [2, 2] = [144, 149, 158]
import java.awt.*; 
import javax.swing.*; 

public class RGB { 
    public static void main(String[] args) { 
        JFrame frame = new JFrame("RGB"); 
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
        RGBpanel panel = new RGBpanel(); 
        frame.getContentPane().add(panel); 
        frame.pack(); 
        frame.setVisible(true); 
    } 
} 

class RGBpanel extends JPanel { 
    public RGBpanel() { 
        setPreferredSize(new Dimension(300,300)); 
        int red = Integer.parseInt(JOptionPane.showInputDialog("Enter red value")); 
        int green = Integer.parseInt(JOptionPane.showInputDialog("Enter green value")); 
        int blue = Integer.parseInt(JOptionPane.showInputDialog("Enter blue value")); 
        Color colour = new Color(red,green,blue); 
        setBackground(colour); 
    } 
}