JPEG图像在多个设备上具有不同的像素值

时间:2014-05-09 13:29:07

标签: android jpeg

我注意到,当在JPEG格式的设备上阅读相同的照片时,像素值不匹配。它们很接近但不同。转换为PNG文件时,像素值似乎匹配。

这似乎是由于跨设备的(非)压缩算法。无论如何,这就是我想到的。有没有办法读取JPEG文件,以便跨设备从照片中检索相同的像素?我在BitmapFactory Options组件中看不到任何选项。

当处理跨设备的图像像素值时,目前应用以下内容来维持大小:

Options options = new Options();
options.inScaled = false;
options.inPreferQualityOverSpeed = true;

目前将像素与以下内容进行比较只是为了看几个(近似匹配,但不相等):

int[] pixels = new int[bitmapF.getWidth() * bitmapF.getHeight()];
bitmapF.getPixels(pixels, 0, bitmapF.getWidth(), 0, 0, bitmapF.getWidth(), bitmapF.getHeight());
Log.d("pixel entries", "pixels = " + pixels[233] + " - " + pixels[4002] + " - " + pixels[11391]);

注意:如果读取未压缩的同一文件的PNG版本,则值与预期的相同。

例如,三星Galaxy S4和三星Galaxy S5甚至具有与资产文件夹中存储的相同jpeg(运行相同测试活动)不同的像素。

例如,像素[233]在s5上为-5205635,在s4上为-5336451。像素[4002]也稍微偏离。但是像素[11391]在这个jpeg图片上的两个设备上是相等的。

6 个答案:

答案 0 :(得分:15)

JPEG标准不要求解码器实现产生逐位相同的输出图像。遗憾的是,指定解码器要求的标准文档ISO 10918-2显然不是免费在线提供的Wikipedia says

  

... JPEG标准(和类似的MPEG标准)包括解码的一些精度要求,包括解码过程的所有部分(可变长度解码,逆DCT,去量化,输出的重归一化);参考算法的输出不得超过:

     
      
  • 每个像素组件的最大1位差异
  •   
  • 每个8×8像素块的低均方误差
  •   
  • [其他]
  •   

使用相同输入的不同解码器输出之间的差异通常是由于不同的内部精度水平,特别是在执行IDCT时。另一个可能的差异来源是平滑,它试图减少“块状”伪影。

和你一样,我希望设置inPreferQualityOverSpeed会产生相同的输出,但实际上没有任何保证。我可以想到至少有两种方法可以让你在两部不同的手机上获得小变化:

  1. 手机可能会运行不同版本的Android,其中BitmapFactory的实施已更改(例如,可能inPreferQualityOverSpeed已被破坏然后修复,反之亦然)或
  2. 电话可以提供BitmapFactory利用的不同硬件功能(例如矢量指令集,DSP协处理器等)。即使标量浮点单元的差异也会导致差异,尤其是JIT编译产生实际的机器指令。
  3. 鉴于标准中的摆动空间加上您的实验观察,似乎保证逐位协议的唯一方法是在您自己的应用程序中执行解码。也许你可以找到一些替代Android兼容的库。

答案 1 :(得分:2)

我想您还应该检查压缩的PNG在设备上的显示方式是否相同。

http://pngquant.org/

如果答案是肯定的,那么唯一剩下的就是弄清楚如何在手机上以编程方式将这些图像转换为相同类型的压缩png。

答案 2 :(得分:1)

JPEG解码器的大部分工作都涉及实数计算。通常这是使用定点整数运算来实现的。这引入了舍入误差。轻微变化是使用JPEG的自然部分。

答案 3 :(得分:1)

是的,不同设备的像素颜色值不同。这非常烦人,特别是如果你想比较颜色。解决方案是比较视觉上相同的颜色(通过人类感知)。

通过人类感知比较两种颜色的最佳方法之一是CIE76。差异称为Delta-E。当它小于1时,人眼无法识别出差异。

您可以找到精彩的颜色实用程序类(ColorUtils),其中包括CIE76比较方法。它由苏黎世大学的Daniel Strebel撰写。

从ColorUtils.class我使用方法:

static double colorDifference(int r1, int g1, int b1, int r2, int g2, int b2)

r1,g1,b1 - 第一种颜色的RGB值

r2,g2,b2 - RGB值或您想要比较的第二种颜色

如果您使用Android,则可以获得以下值:

r1 = Color.red(pixel);

g1 = Color.green(pixel);

b1 = Color.blue(pixel);

答案 4 :(得分:0)

将介质重新调整为所需大小,或使用HTML属性禁用图像缩放。

另一种选择是允许用户在加载缩略图表示后决定以节省带宽。

答案 5 :(得分:0)

我遇到了同样的问题。 PNG和JPEG图像似乎是由不同的设备近似渲染的。 我们使用 BMP 图片(不幸的是尺寸大很多)解决了该问题。