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

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

问题描述

我发现使用 Java 时得到的 RGB(实际上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

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

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 像素块的平均误差非常低
  • 整个图像的均方误差非常低
  • 整个图像的平均误差极低

(请注意,以上仅讨论了参考实现).

(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.

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

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 色彩空间中显示 RGB 值.这可能是主流计算中使用的最标准和最广泛使用的色彩空间,所以这毕竟不足为奇.由于色彩空间始终是 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 或其他东西).当然,使用 Adob​​e 的 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 引擎,Little 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天全站免登陆