Насколько стабильны / согласованы значения цвета в изображениях? - PullRequest
2 голосов
/ 10 июля 2020

Допустим, я анализирую файл изображения с несколькими различными библиотеками и запрашиваю у библиотеки значение RGB в пикселях (20, 30).

При каких условиях я могу ожидать получения согласованных результатов для разных библиотек и версии библиотеки?

Интуитивно я бы предположил, что с более простыми форматами, такими как PPM или (с некоторыми ограничениями) BMP, я, вероятно, мог бы ожидать согласованных результатов, а с JPEG я бы получил результаты повсюду даже в относительно простых случаев, когда этого не избежать.

Это заставляет меня думать о PNG: если я беру входное изображение, конвертирую его в PNG с заданной глубиной цвета (например, 8-битный на канал RGBA, с все значения прозрачности установлены на полностью непрозрачные) и нет цветового профиля, если я могу ожидать:

  1. все распространенные библиотеки будут интерпретировать результирующий PNG таким же образом (давая тот же массив Значения RGB (A) при чтении файла)?

  2. все распространенные библиотеки, чтобы иметь возможность повернуть указанный массив значений RGB (A) обратно в PNG, который все общие библиотеки будут интерпретировать одинаково?

(Очевидно, сами байты файла, вероятно, будут другими из-за метаданных, порядка пакетов и т. д. c . - Я говорю здесь только о значениях пикселей. Кроме того, очевидно, что на начальном этапе преобразования изображение может измениться, если исходный вход имел цветовой профиль et c.)

Например, если вы получили этот образец файла:

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, если в диалоговом окне профиля выбрать «Сохранить».

Ответы [ 2 ]

2 голосов
/ 23 июля 2020

JPEG

Из-за различных преобразований (JPEG кодирует цвета в YCbCr) декодированные цвета могут отличаться, как показано в примере кода в вопросе ( см. Также ).

PNG

TL; DR: На практике кажется, что PNG может надежно сохранять точные значения цвета для разных языков / библиотек.

PNG хранит Значения RGB (или оттенков серого) (возможно, с использованием палитры). Хотя он поддерживает, например, гамма-коррекцию с фрагментом gAMA и различные формы управления цветом (например, фрагменты cHRM, iCCP, sRGB), библиотеки, похоже, часто их игнорируют.

I создал изображение, содержащее #808080 серый, добавил различные значения gAMA, и все следующие значения (128, 128, 128) были указаны в качестве значений цвета для всех файлов:

  • ImageMagick (convert file.png -crop 1x1+5+5 -depth 8 txt:-)
  • GIMP (при открытии изображения и использовании информационной панели все изображения также выглядят одинаково яркими)
  • Python PIL / Pillow
  • Golang
  • Python ImageIO в режиме по умолчанию.

ImageIO интересен тем, что в нем есть опция ignoregamma , которая по умолчанию имеет значение True. Если его отключить, значение серого будет интерпретироваться как 186 вместо 128 в изображении, сохраненном из GIMP. Это достаточно серьезная разница, поэтому существующие библиотеки вряд ли внезапно изменят свое поведение по умолчанию: comparison between grey-128 and grey-186

The Golang Исходный код программы чтения PNG подтверждает, что, похоже, не интерпретирует дополнительные фрагменты информации о цвете.

Вероятно, было бы неплохо опустить эти фрагменты. Firefox интерпретирует PNG без фрагмента gAMA как имеющий цвет (128, 128, 128). PNG с исходным фрагментом gAMA также правильно интерпретируется; PNG, в котором GIMP встроил профиль I CC, уже отключен на 1, показывая (127, 127, 127), а PNG с отредактированными значениями гаммы сильно отличаются (как и ожидалось).

2 голосов
/ 22 июля 2020

Среди преимуществ PNG:

Без потерь : Без потерь: фильтрация и сжатие сохраняют всю информацию.

Следовательно, при условии, что фильтрация и сжатие были (не) выполнены правильно, значения цвета в PNG гарантированно согласованы.

Важно, прозрачность (альфа) сохраняется в формате PNG без предварительного умножения ; поэтому убедитесь, что эквивалент getpixel() на каждом используемом вами языке не умножается предварительно, если вам нужны необработанные значения. (Если последовательно приготовленных значений будет достаточно, убедитесь, что функции все умножаются заранее.)

Примечание: разница, которую вы наблюдали в Golang, вероятно, была связана с преобразованием из RGB в YCbCr .

Авторитетный источник: https://www.w3.org/TR/PNG (содержит 15 совпадений по «проигрышу»)

...