ImageIO读取的RGB值略微不同于其他方法 [英] ImageIO reading slightly different RGB values than other methods

查看:207
本文介绍了ImageIO读取的RGB值略微不同于其他方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我发现在使用Java(实际上是 paint.NET )时,我得到的颜色不同于我正在使用ImageMagick,Gimp,Python和Octave。最后4个都同意彼此,所以我假设是正确的。

I've found that I'm getting different RGB when using Java (& actually paint.NET) than I am using ImageMagick, Gimp, Python, and Octave. The last 4 all agreeing with eachother and so I'm assuming to be correct.

对于这些例子,我正在使用这个测试图像: http://farm3.static.flickr.com/2811/9177301733_9836174725_o.jpg

For these examples, I'm using this test image: 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的快速测试:

Here's a quick test using 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代码也证明了这个问题:

Here's some java and python code that also demonstrates the problem:

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脚本:

And here is the corresponding python script:

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]

我试过用这个12monkeys库,希望能解决这个问题,但不会骰子。如何使用java提取正确的RGB值?当然我不是第一个遇到这个问题的人!

I've tried using this 12monkeys library in the hope that that would fix it but no dice. Any other ideas how I can extract correct RGB values using java? Surely I'm not the first person to have this problem!

我试过 getRaster()。getSample()但得到了相同的无效结果: System.out.println(raster.getSample(4144,2768,0)+,+ raster.getSample(4144,2768,1)+,+ raster.getSample(4144,2768,2)); 输出: 125,107,69

I tried getRaster().getSample() but got the same invalid result: System.out.println(raster.getSample(4144, 2768, 0)+","+ raster.getSample(4144, 2768, 1)+","+ raster.getSample(4144, 2768, 2)); output: 125,107,69

这是一些输出,显示哪些RGB值被三种不同的工具解码图像左上角的前9个(3x3平方)像素。如您所见,Python和ImageMagick是齐声的。 Java有时会匹配。我把一个X放在java不同意的地方......:

Here is some output that shows what RGB values are decoded by three different tools for the first 9 (3x3 square of) pixels in the top left of the image. As you can see, Python and ImageMagick are in unison. Java sometimes matches. I've put an X where java disagrees...:

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代码生成正确的值?

Why is Java giving different values for some pixels? Alternatively, is there another (fast) way to generate correct values using native Java code?

我提交了我的代码来演示这个问题并将其推送到github( imageio-test )以便我可以很容易地在不同的机器上测试它。事实证明,Java在OSX和Ubuntu Linux上都是一致的,但是Python,ImageMagick和Octave是不一致的。换句话说,在Linux机器上,所有工具都互相认同,因此,我现在认为java一直都是正确的,而且其他工具在OSX上给出了错误的结果!我仍然不明白为什么,我没有任何具体的证据证明哪些值是正确的,但我正在某处......

I committed my code that demonstrates this problem and pushed it to github (imageio-test) so that I could easily test it out on different machines. It turns out that Java was consistent across both OSX and Ubuntu Linux, but it was Python, ImageMagick and Octave that were inconsistent. In other words, on the Linux box, all tools agree with each other, and therefore, I'm now thinking that java was right all along, and it's the other tools that are giving incorrect results on OSX! I still don't really understand why and I haven't got any concrete proof as to which values are the correct ones but I'm getting somewhere...

推荐答案

实际上,我想解决问题,并说我很惊讶这么多不同的平台和工具实际上产生了相同的价值。 : - )

首先,JPEG是有损图像压缩方法。这意味着无法再现原始的确切数据。或者,如果您愿意,几个不同的像素值可能在某种程度上都是正确的。

First of all, JPEG is a lossy image compression method. This means that reproducing the exact data of the original is not possible. Or, if you like, several different pixel values may all be "correct" in some way.

技术原因并非所有JPEG软件都能从中生成完全相同的值相同的源文件通常是不同的舍入/钳位值,或浮点运算的整数近似值以获得更好的性能。例如,其他变化可能源于应用于恢复二次采样的色度值的不同插值算法(即,更平滑的图像可能看起来更令人愉悦,但不一定更正确)。

The technical reasons why not all JPEG software produce the exact same values from the same source file, is typically different rounding/clamping of values, or integer approximations of floating point operations for better performance. Other variations may stem from different interpolation algorithms applied to restore the subsampled chroma values, for example (ie. a smoother image may look more pleasing to the eye, but isn't necessarily more correct).

针对类似问题的另一个优秀答案指出JPEG标准不要求解码器实现产生逐位相同的输出图像,并引用维基百科JPEG条目

Another excellent answer to a similar question states that "The JPEG standard does not require that decoder implementations produce bit-for-bit identical output images", and quotes the Wikipedia JPEG entry:


[...] de的精度要求编码[...];参考算法的输出不得超过:

[...] precision requirements for the decoding [...]; the output from the reference algorithm must not exceed:


  • 每个像素组件最多有一位差异

  • 每个8×8像素块的低均方误差

  • 每个8×8像素块的平均误差非常低


  • 整个图像的平均误差极低

  • a maximum of one bit of difference for each pixel component
  • low mean square error over each 8×8-pixel block
  • very low mean error over each 8×8-pixel block
  • very low mean square error over the whole image
  • extremely low mean error over the whole image

(请注意,上面只讨论了参考实现)。

(Note that the above talks about the reference implementation only).

但是,运气好的话,似乎所有的软件/工具实际上都使用(某些版本) libjpeg 。因为它们都使用libjpeg,所以你看到的差异来源很可能与JPEG解码无关。

However, with some luck, it seems that all of your software/tools actually end up using (some version of) libjpeg. Because they all use libjpeg, the source of the differences you see is most likely not related to the JPEG decoding.

即使您的所有软件都使用RGB值将JPEG文件转换为表示形式,它们用于此表示的颜色空间也可能存在差异。

Even if all your software converts the JPEG file to a representation using RGB values, there could be differences in the color space they use for this representation.

看来您使用的所有软件实际上都在 sRGB色彩空间。这可能是主流计算中使用的最标准和最广泛使用的色彩空间,所以这并不奇怪。由于颜色空间始终为sRGB,因此您看到的差异来源很可能不是颜色空间。

It does seem that all of the software you are using actually displays the RGB values in the sRGB color space. This is probably the most standard and widely used color space used in mainstream computing, so that is no surprise after all. As the color space is always sRGB, the source of the differences you see is most likely not the color space.

下一个可能的色差来源是色彩匹配(由色彩匹配模块,CMM或色彩管理系统,CMS完成)不是100%精确的科学(参见例如这个关于黑点补偿的文件或者从小CMS博客)。

The next possible source of color differences, is that color matching (as done by a Color Matching Module, CMM or Color Management System, CMS) is not an 100% exact science (see for example this document on black point compensation or read some of the more technical posts from the Little CMS blog).

很可能Mac OS X上运行的软件使用的是Apple的CMM,而Java总是使用Little CMS(来自OpenJDK 7或Oracle JDK / JRE 8),而且大部分都是Linux平台上的软件也可能使用开源的Little CMS(根据Little CMS主页,你可以在大多数Linux发行版中找到Little CMS)。 Windows上的软件也可能略有偏差(我无法验证Paint.Net是否使用Little CMS,Windows内置CMM或其他东西)。当然,使用Adobe的CMM(即Photoshop)也可能会有所偏差。

Most likely the software running on Mac OS X are using Apple's CMM, while Java is using Little CMS always (from OpenJDK 7 or Oracle JDK/JRE 8), and most software on the Linux platform will likely also use the open source Little CMS (according to the Little CMS home page, "You can find Little CMS in most Linux distributions"). Software on Windows will likely deviate slightly as well (I haven't been able to verify if Paint.Net uses Little CMS, Windows' built in CMM or something else). And of course, using Adobe's CMM (ie. Photoshop) will likely deviate as well.

再次,幸运的是,你测试的很多软件都使用相同的CMM或CMS引擎,小型CMS ,所以你将再次获得相同的结果。但似乎您测试的某些软件使用不同的CMM,并且可能是轻微颜色差异的来源。

Again, with some luck, a lot of the software you tested uses the same CMM or CMS engine, Little CMS, so again you will have a lot of equal results. But it seems that some of the software you tested uses different CMMs, and is a probable source of the slight color differences.

您看到的不同像素值都是正确的。差异源于软件中不同的实现或算法近似,但这并不一定意味着一个值是正确的其他错误。

The different pixel values you see are all "correct". The differences stem from different implementations or approximations of algorithms in software, but that does not necessarily mean that one value is correct and the others are wrong.

PS:如果需要在多个平台上重现完全相同的值,请在所有平台上使用相同的工具堆栈/相同算法。

PS: If you need to reproduce the exact same values across multiple platforms, use the same tool stack/same algorithms on all platforms.

这篇关于ImageIO读取的RGB值略微不同于其他方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆