首页 > 解决方案 > 图像中的颜色值有多稳定/一致?

问题描述

假设我用多个不同的库解析一个图像文件,并向库询问像素 (20, 30) 处的 RGB 值。

在什么条件下,我可以期望在库和库版本之间获得一致的结果?

直观地说,我会假设使用更简单的格式,如 PPM 或(有一些限制)BMP,我可能会期望得到一致的结果,而使用 JPEG,即使在相对简单的情况下,我也会得到所有地方的结果,而无法避免这种情况。

这让我想到了 PNG:如果我采用输入图像,将其转换为具有定义颜色深度的 PNG(例如,每通道 8 位 RGBA,所有透明度值设置为完全不透明)并且没有颜色配置文件,应该我可以期待:

  1. 所有通用库都以相同的方式解释生成的 PNG(在读取文件时产生相同的 RGB(A) 值数组)?

  2. 所有通用库都能够将所述RGB(A)值数组转换回所有通用库将以相同方式解释的PNG吗?

(显然,由于元数据、数据包的顺序等,文件字节本身可能会有所不同。我在这里只讨论像素值。此外,如果原始输入有颜色,显然初始转换步骤可能会改变图像简介等)

例如,如果您获得此示例文件:

wget https://upload.wikimedia.org/wikipedia/commons/thumb/7/7a/Sun_getting_through_fog_in_the_New_Zealand_bush%2C_Bryant_Range.jpg/500px-Sun_getting_through_fog_in_the_New_Zealand_bush%2C_Bryant_Range.jpg

然后用 Python 解码:

import PIL.Image                                                                               
img = PIL.Image.open('500px-Sun_getting_through_fog_in_the_New_Zealand_bush,_Bryant_Range.jpg')
print(img.getpixel((100,100)))  # prints (73, 50, 60)

你会得到与 Golang 不同的结果:

package main

import (
    "fmt"
    "image"
    "log"
    "os"

    "image/color"
    _ "image/jpeg"
    _ "image/png"
)

func main() {
    reader, err := os.Open("500px-Sun_getting_through_fog_in_the_New_Zealand_bush,_Bryant_Range.jpg")
    if err != nil {
        log.Fatal(err)
    }
    m, _, err := image.Decode(reader)
    if err != nil {
        log.Fatal(err)
    }
    c := m.At(100, 100).(color.YCbCr)
    fmt.Printf("%+v\n", c)
    r, g, b := color.YCbCrToRGB(c.Y, c.Cb, c.Cr)
    fmt.Printf("%v %v %v\n", r, g, b)  // prints 72 50 59
}

如果您在配置文件对话框中选择“保留”,GIMP 将像素 (100, 100) 解码为 (73, 50, 60),即与 PIL 相同。

标签: imageimage-processingcolorspng

解决方案


PNG的优点之一是:

无损:无损失:过滤和压缩保留所有信息。

因此,假设过滤压缩(未)正确完成,PNG 中的颜色值可以保证一致。

重要的是,透明度(alpha)存储在预乘的 PNG中;因此,如果您想要原始值,请确保您使用的每种语言中的等价物getpixel()不会预乘。(如果一致熟化的值就足够了,请确保所有函数都是预乘的。)

注意:您在 Golang 中观察到的差异可能是由于从 RGB 到YCbCr的转换。

权威来源:https ://www.w3.org/TR/PNG (包含“损失”的15个匹配项)


推荐阅读