Изображения, открытые в Pillow и OpenCV, не эквивалентны

Я загрузил тестовое изображение из Википедии (дерево, показанное ниже), чтобы сравнить Pillow и OpenCV (с использованием cv2) в python. На первый взгляд два изображения выглядят одинаково, но их соответствующие хэши md5 не совпадают; и если я вычту два изображения, результат даже не будет близким к сплошному черному (изображение, показанное под оригиналом). Исходное изображение - JPEG. Если я сначала конвертирую его в PNG, хеши совпадают.

На последнем изображении показано частотное распределение различий значений пикселей.

Как указала Катри, мое вычитание вызывало целочисленное переполнение. Я тоже обновился до преобразования dtype=int перед вычитанием (чтобы показать отрицательные значения), а затем взял абсолютное значение перед построением разницы. Теперь разностное изображение воспринимается сплошным черным цветом.

Это код, который я использовал:

from PIL import Image
import cv2
import sys
import md5
import numpy as np

def hashIm(im):
    imP = np.array(Image.open(im))

    # Convert to BGR and drop alpha channel if it exists
    imP = imP[..., 2::-1]
    # Make the array contiguous again
    imP = np.array(imP)
    im = cv2.imread(im)

    diff = im.astype(int)-imP.astype(int)

    cv2.imshow('cv2', im)
    cv2.imshow('PIL', imP)
    cv2.imshow('diff', np.abs(diff).astype(np.uint8))
    cv2.imshow('diff_overflow', diff.astype(np.uint8))

    with open('dist.csv', 'w') as outfile:
        diff = im-imP
        for i in range(-256, 256):
            outfile.write('{},{}\n'.format(i, np.count_nonzero(diff==i)))

    cv2.waitKey(0)
    cv2.destroyAllWindows()

    return md5.md5(im).hexdigest() + '   ' + md5.md5(imP).hexdigest()

if __name__ == '__main__':
    print sys.argv[1] + '\t' + hashIm(sys.argv[1])

Исходное фото дерева (из статьи о дереве в Википедии)

Распределение частот обновлено, чтобы отображать отрицательные значения.

Обновленная разница


Это то, что я видел до того, как внедрил изменения, рекомендованные Кэтри.

Разница

Dist


person chew socks    schedule 22.04.2018    source источник
comment
Я могу ошибаться, но я думаю, что здесь могут быть ошибки округления np.array(Image.open(im)), а iirc imshow растягивает цвета, чтобы соответствовать диапазону (посмотрите на фактические значения im-imP, они, вероятно, будут очень маленькими)   -  person Nullman    schedule 22.04.2018
comment
Я просто попробовал его, но здесь никаких различий (win10 + python3.6 + opencv-python = = 3.4.0.12 + Подушка == 5.1.0).   -  person Joost    schedule 22.04.2018
comment
@Nullman Интересная идея, но я не совсем понимаю, что вы имеете в виду, говоря об ошибках округления. np.array(Image.open(im)) дает dtype=np.uunt8. Выложил график распределения значений в im-imP.   -  person chew socks    schedule 22.04.2018
comment
поскольку joost удалось запустить его без проблем, возможно, что-то действительно изменилось в вашей версии этих библиотек. какие версии вы используете?   -  person Nullman    schedule 22.04.2018
comment
@Joost Интересно ... Возможно, изображение было перекодировано, когда я загрузил его в SO. Не могли бы вы попробовать с оригиналом, если вы еще этого не сделали?   -  person chew socks    schedule 22.04.2018
comment
@Nullman Я использую Ubuntu 16.04, Python2.7.12, opencv-2.4.9.1, opencv-python 3.4.0.12, numpy 1.14.2, Pillow 5.1.0. Я нахожусь в virtualenv, поэтому, по крайней мере, библиотеки Python должны быть в актуальном состоянии.   -  person chew socks    schedule 22.04.2018
comment
Я также запустил код (эти 2 строки перевернуты! im = cv2.imread(im) imP = np.array(Image.open(im)), и он отлично работает для меня, я получил cv2 версии 3.3.0 и подушку 4.3.0 на python 3.6.3 на win10   -  person Nullman    schedule 22.04.2018
comment
@Nullman Ну, я буду ... вот что я получаю, пытаясь сделать свой пост красивее. Сейчас я редактировал с идентичной копией cat chck.py, в которой они расположены в правильном порядке. Интересно, что вы оба на Win10. Я посмотрю, смогу ли я сегодня попробовать это на коробке с Windows.   -  person chew socks    schedule 22.04.2018
comment
я думаю, что основная разница здесь в том, что мы оба на python3   -  person Nullman    schedule 22.04.2018
comment
Я использовал как тот, что был загружен в SO, так и из Википедии, но оба показали то же самое.   -  person Joost    schedule 22.04.2018


Ответы (1)


Исходное изображение - JPEG.

Декодирование JPEG может давать разные результаты в зависимости от версии libjpeg, оптимизации компилятора, платформы и т. Д.

Проверьте, какая версия libjpeg используется Pillow и OpenCV.

См. Этот ответ для получения дополнительной информации: Изображения JPEG имеют разные значения пикселей на нескольких устройствах или здесь.

Кстати, (im-imP) вызывает uint8 переполнение (невозможно получить такое большое количество больших различий пикселей, не увидев его в вашем частотная диаграмма). Попытайтесь привести к типу int перед вычислением частоты.

person Catree    schedule 22.04.2018
comment
Спасибо! Не знал этого о JPEG. Я обновил свою частотную диаграмму, чтобы использовать int. Оказывается, все значения im-imP != 0 отрицательны. Я еще не нашел точных версий, но мой OpenCV довольно старый, и он использует встроенные исходники для libjpeg - person chew socks; 22.04.2018