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

Вот что бы я хотел сделать:

Я регулярно фотографирую на веб-камеру. Что-то вроде замедленной съемки. Однако, если на самом деле ничего не изменилось, то есть изображение почти выглядит одинаково, я не хочу сохранять последний снимок.

Я полагаю, что есть какой-то способ количественной оценки разницы, и мне пришлось бы эмпирически определить порог.

Я ищу простоту, а не совершенство. Я использую питон.


person carrier    schedule 10.10.2008    source источник
comment
По теме: stackoverflow.com/questions/25977/   -  person Anoyz    schedule 09.06.2015


Ответы (23)


Главная идея

Вариант 1. Загрузите оба изображения как массивы (scipy.misc.imread) и вычислите поэлементную (попиксельную) разницу. Рассчитайте норму разницы.

Вариант 2: Загрузите оба изображения. Вычислите некоторый вектор признаков для каждого из них (например, гистограмму). Вычисляйте расстояние между векторами признаков, а не изображениями.

Однако сначала нужно принять некоторые решения.

Вопросы

Сначала вам следует ответить на эти вопросы:

  • Изображения одинаковой формы и размеров?

    В противном случае вам может потребоваться изменить их размер или обрезать их. Библиотека PIL поможет сделать это на Python.

    Если они сделаны с одинаковыми настройками и одним и тем же устройством, вероятно, они одинаковы.

  • Хорошо ли выровнены изображения?

    В противном случае вы можете сначала запустить кросс-корреляцию, чтобы сначала найти наилучшее выравнивание. У SciPy есть функции для этого.

    Если камера и сцена неподвижны, изображения, скорее всего, будут хорошо совмещены.

  • Всегда ли экспозиция изображений одинакова? (Яркость / контраст одинаковы?)

    В противном случае вы можете захотеть нормализовать изображения.

    Но будьте осторожны, в некоторых ситуациях это может принести больше вреда, чем пользы. Например, один яркий пиксель на темном фоне сильно изменит нормализованное изображение.

  • Важна ли информация о цвете?

    Если вы хотите заметить изменения цвета, у вас будет вектор значений цвета на точку, а не скалярное значение, как в полутоновом изображении. При написании такого кода вам нужно больше внимания.

  • Есть ли на изображении четкие края? Вероятны ли они переехать?

    Если да, вы можете сначала применить алгоритм обнаружения краев (например, вычислить градиент с помощью преобразования Собела или Превитта, применить некоторый порог), а затем сравнить края на первом изображении с краями на втором.

  • Есть ли на изображении шум?

    Все датчики загрязняют изображение некоторым количеством шумов. У недорогих датчиков больше шума. Возможно, вы захотите применить некоторое шумоподавление, прежде чем сравнивать изображения. Размытие - самый простой (но не лучший) подход.

  • Какие изменения вы хотите заметить?

    Это может повлиять на выбор нормы для разницы между изображениями.

    Рассмотрите возможность использования нормы Манхэттена (сумма абсолютных значений) или нулевой нормы (количество элементов, не равных нулю), чтобы измерить, насколько изменилось изображение. Первый сообщит вам, насколько сильно изображение выключено, второй - только на сколько пикселей различается.

Пример

Я предполагаю, что ваши изображения хорошо выровнены, одинакового размера и формы, возможно, с разной экспозицией. Для простоты я конвертирую их в оттенки серого, даже если это цветные (RGB) изображения.

Вам понадобится этот импорт:

import sys

from scipy.misc import imread
from scipy.linalg import norm
from scipy import sum, average

Основная функция, чтение двух изображений, преобразование в оттенки серого, сравнение и печать результатов:

def main():
    file1, file2 = sys.argv[1:1+2]
    # read images as 2D arrays (convert to grayscale for simplicity)
    img1 = to_grayscale(imread(file1).astype(float))
    img2 = to_grayscale(imread(file2).astype(float))
    # compare
    n_m, n_0 = compare_images(img1, img2)
    print "Manhattan norm:", n_m, "/ per pixel:", n_m/img1.size
    print "Zero norm:", n_0, "/ per pixel:", n_0*1.0/img1.size

Как сравнить. img1 и img2 - это 2D-массивы SciPy здесь:

def compare_images(img1, img2):
    # normalize to compensate for exposure difference, this may be unnecessary
    # consider disabling it
    img1 = normalize(img1)
    img2 = normalize(img2)
    # calculate the difference and its norms
    diff = img1 - img2  # elementwise for scipy arrays
    m_norm = sum(abs(diff))  # Manhattan norm
    z_norm = norm(diff.ravel(), 0)  # Zero norm
    return (m_norm, z_norm)

Если файл представляет собой цветное изображение, imread возвращает трехмерный массив, средние значения каналов RGB (последняя ось массива) для получения интенсивности. Нет необходимости делать это для изображений в градациях серого (например, .pgm):

def to_grayscale(arr):
    "If arr is a color image (3D array), convert it to grayscale (2D array)."
    if len(arr.shape) == 3:
        return average(arr, -1)  # average over the last axis (color channels)
    else:
        return arr

Нормализация тривиальна, вы можете выбрать нормализацию до [0,1] вместо [0,255]. arr - это массив SciPy, поэтому все операции поэлементны:

def normalize(arr):
    rng = arr.max()-arr.min()
    amin = arr.min()
    return (arr-amin)*255/rng

Запустите функцию main:

if __name__ == "__main__":
    main()

Теперь вы можете поместить все это в сценарий и запустить с двумя изображениями. Если сравнить изображение с собой, разницы нет:

$ python compare.py one.jpg one.jpg
Manhattan norm: 0.0 / per pixel: 0.0
Zero norm: 0 / per pixel: 0.0

Если размыть изображение и сравнить с оригиналом, есть некоторая разница:

$ python compare.py one.jpg one-blurred.jpg 
Manhattan norm: 92605183.67 / per pixel: 13.4210411116
Zero norm: 6900000 / per pixel: 1.0

P.S. Весь скрипт compare.py.

Обновление: актуальные методы

Поскольку вопрос касается видеопоследовательности, где кадры, вероятно, будут почти одинаковыми, и вы ищете что-то необычное, я хотел бы упомянуть некоторые альтернативные подходы, которые могут быть актуальны:

  • вычитание и сегментация фона (для обнаружения объектов переднего плана)
  • разреженный оптический поток (для обнаружения движения)
  • сравнение гистограмм или другой статистики вместо изображений

Я настоятельно рекомендую взглянуть на книгу «Изучение OpenCV», главы 9 (части изображения и сегментация) и 10 (отслеживание и движение). Первый учит использовать метод вычитания фона, второй дает некоторую информацию о методах оптического потока. Все методы реализованы в библиотеке OpenCV. Если вы используете Python, я предлагаю использовать OpenCV ≥ 2.3 и его cv2 модуль Python.

Самый простой вариант вычитания фона:

  • узнать среднее значение μ и стандартное отклонение σ для каждого пикселя фона
  • сравнить текущие значения пикселей с диапазоном (μ-2σ, μ + 2σ) или (μ-σ, μ + σ)

Более продвинутые версии учитывают временные ряды для каждого пикселя и обрабатывают нестатические сцены (например, движущиеся деревья или траву).

Идея оптического потока состоит в том, чтобы взять два или более кадров и назначить вектор скорости каждому пикселю (плотный оптический поток) или некоторым из них (разреженный оптический поток). Чтобы оценить разреженный оптический поток, вы можете использовать метод Лукаса-Канаде (it также реализован в OpenCV). Очевидно, что если есть большой поток (высокое среднее значение по максимальным значениям поля скорости), то что-то движется в кадре, и последующие изображения будут более разными.

Сравнение гистограмм может помочь обнаружить внезапные изменения между последовательными кадрами. Этот подход использовался в Courbon et al, 2010:

Сходство последовательных кадров. Измеряется расстояние между двумя последовательными кадрами. Если он слишком высокий, это означает, что второй кадр поврежден и, таким образом, изображение удалено. расстояние Кульбака – Лейблера или взаимная энтропия на гистограммах два кадра:

$$ d (p, q) = \ sum_i p (i) \ log (p (i) / q (i))  $$

где p и q - гистограммы используемых кадров. Порог зафиксирован на 0,2.

person sastanin    schedule 14.10.2010
comment
Я получаю RuntimeWarning: invalid value encountered in double_scalars в строке 44 (return (arr-amin)*255/rng) и ValueError: array must not contain infs or NaNs в строке 30 (z_norm = norm(diff.ravel(), 0)) - person BioGeek; 26.08.2015
comment
@BioGeek, то есть если rng равно нулю. Просто добавьте чек и установите rng = 1 - person haisi; 24.04.2018

Простое решение:

Закодируйте изображение как jpeg и обратите внимание на существенное изменение в размере файла.

Я реализовал нечто подобное с миниатюрами видео и добился большого успеха и масштабируемости.

person keparo    schedule 10.10.2008
comment
Это очень легкое и простое решение, которое намного лучше, чем любое сравнение по пикселям. Если на изображении вашей веб-камеры присутствует небольшой шум или если изображение сдвинуто хотя бы на один пиксель, то прямое сравнение обнаружит все эти бессмысленные изменения. Более надежным подходом было бы вычисление дискретного косинусного преобразования и последующее сравнение изображений в частотной области. Такое сжатие JPEG дает вам большинство преимуществ, не углубляясь в теорию Фурье. - person AndrewF; 14.10.2010
comment
Нравится. Хотя другие решения тоже работают, это дает большое преимущество для общей ситуации: что, если вы не хотите сохранять базовый образ? просто сохраните размер файла как хэш, а затем сравните только числа с вычитанием. В моем случае у меня есть 4 изображения, одно из них очень похожее, а остальные 3 совершенно разные. Просто выполните масштабирование до тех же размеров, до jpg и вычтите. Действительно мило. - person Diego Andrés Díaz Espinoza; 01.07.2018

Вы можете сравнить два изображения с помощью функций из PIL.

import Image
import ImageChops

im1 = Image.open("splash.png")
im2 = Image.open("splash2.png")

diff = ImageChops.difference(im2, im1)

Объект diff - это изображение, в котором каждый пиксель является результатом вычитания значений цвета этого пикселя во втором изображении из первого изображения. Используя изображение diff, вы можете делать несколько вещей. Самая простая - это функция diff.getbbox(). Он покажет вам минимальный прямоугольник, содержащий все изменения между вашими двумя изображениями.

Вероятно, вы можете реализовать приближения других вещей, упомянутых здесь, также с помощью функций из PIL.

person elifiner    schedule 13.10.2008
comment
Я хочу сохранить изображение разницы. означает объект diff, который содержит разницу изображений. как мне его спасти? - person Sagar; 21.02.2014
comment
@Anthony вы можете вызвать save () для объекта diff, указав имя изображения. вот так: diff.save (diff.png) он сохранит для вас разностное изображение. - person Sagar; 26.06.2015

Два популярных и относительно простых метода: (а) уже предложенное евклидово расстояние или (б) нормализованная взаимная корреляция. Нормализованная кросс-корреляция имеет тенденцию быть заметно более устойчивой к изменениям освещения, чем простая кросс-корреляция. В Википедии есть формула для нормализованной взаимной корреляции. Существуют и более сложные методы, но они требуют немного больше работы.

Используя numpy-подобный синтаксис,

dist_euclidean = sqrt(sum((i1 - i2)^2)) / i1.size

dist_manhattan = sum(abs(i1 - i2)) / i1.size

dist_ncc = sum( (i1 - mean(i1)) * (i2 - mean(i2)) ) / (
  (i1.size - 1) * stdev(i1) * stdev(i2) )

при условии, что i1 и i2 представляют собой массивы двухмерных изображений в градациях серого.

person Mr Fooz    schedule 10.10.2008
comment
Функции взаимной корреляции изображений встроены в SciPy (docs.scipy.org/doc/scipy/reference/generated/), а быстрая версия с использованием БПФ доступна в stsci python (stsci.edu/resources/software_hardware/pyraf/stsci_python) - person endolith; 17.09.2009

Тривиальная вещь, которую стоит попробовать:

Измените выборку обоих изображений на маленькие миниатюры (например, 64 x 64) и сравните миниатюры попиксельно с определенным порогом. Если исходные изображения почти такие же, миниатюрные изображения с повторной выборкой будут очень похожими или даже точно такими же. Этот метод устраняет шум, который может возникать, особенно в условиях низкой освещенности. Возможно, будет даже лучше, если вы выберете оттенки серого.

person Ates Goral    schedule 10.10.2008
comment
а как бы вы сравнили пиксели? - person carrier; 10.10.2008
comment
Когда у вас есть эскизы, вы можете просто сравнивать пиксели один за другим. Вы должны рассчитать расстояние между значениями RGB, если вы работаете в цвете, или просто разницу между серыми тонами, если вы находитесь в градациях серого. - person Ates Goral; 15.10.2008
comment
сравните пиксели один за другим. Что это обозначает? Должен ли тест завершиться неудачно, если ОДИН из тестов 64 ^ 2 пикселей на пиксель не пройден? - person Federico A. Ramponi; 15.10.2008
comment
Под сравнением миниатюр по пикселям с определенным порогом я имел в виду создание нечеткого алгоритма для сравнения пикселей. Если рассчитанная разница (зависит от вашего нечеткого алгоритма) превышает определенный порог, изображения не совпадают. - person Ates Goral; 15.10.2008
comment
Очень простой пример без нечеткого алгоритма: параллельный цикл через каждый пиксель (сравните пиксель № n изображения №1 с пикселем № n изображения №2) и добавьте разница в значении переменной - person mk12; 08.11.2009
comment
@ Mk12 Этот метод может не работать с источником шумного изображения, например веб-камерой. - person Ates Goral; 30.01.2013

Я конкретно обращаюсь к вопросу о том, как вычислить, достаточно ли они различны. Я полагаю, вы можете понять, как вычитать пиксели один за другим.

Во-первых, я бы взял кучу изображений, в которых ничего не менялось, и выяснил, насколько сильно изменяется любой пиксель только из-за вариаций в захвате, шума в системе обработки изображений, артефактов сжатия JPEG и момента моментальные изменения освещения. Возможно, вы обнаружите, что следует ожидать разницы в 1 или 2 бита, даже когда ничего не движется.

Тогда для «настоящего» теста вам нужен такой критерий:

  • то же самое, если до P пикселей отличаются не более чем на E.

Так что, возможно, если E = 0,02, P = 1000, это будет означать (приблизительно), что он будет «другим», если любой отдельный пиксель изменится более чем на ~ 5 единиц (при условии 8-битных изображений), или если более чем на 1000 у пикселей вообще были ошибки.

Это предназначено, главным образом, как хороший метод «сортировки» для быстрого определения изображений, которые достаточно близки и не требуют дальнейшего изучения. Изображения, которые «терпят неудачу», могут быть более сложными / дорогостоящими методами, которые не будут давать ложных срабатываний, например, если камера немного трясется, или более устойчива к изменениям освещения.

Я запускаю проект с открытым исходным кодом, OpenImageIO, который содержит утилиту под названием «idiff», которая сравнивает различия с такими пороговыми значениями ( даже более сложный, на самом деле). Даже если вы не хотите использовать это программное обеспечение, вы можете посмотреть исходный код, чтобы узнать, как мы это сделали. Он довольно часто используется в коммерческих целях, и этот метод определения пороговых значений был разработан таким образом, чтобы у нас мог быть набор тестов для программного обеспечения для рендеринга и обработки изображений с «эталонными изображениями», которые могут иметь небольшие отличия от платформы к платформе, или поскольку мы внесли незначительные изменения в tha, поэтому нам нужна была операция «соответствие в пределах допуска».

person Larry Gritz    schedule 14.10.2010

Еще один приятный и простой способ измерить сходство между двумя изображениями:

import sys
from skimage.measure import compare_ssim
from skimage.transform import resize
from scipy.ndimage import imread

# get two images - resize both to 1024 x 1024
img_a = resize(imread(sys.argv[1]), (2**10, 2**10))
img_b = resize(imread(sys.argv[2]), (2**10, 2**10))

# score: {-1:1} measure of the structural similarity between the images
score, diff = compare_ssim(img_a, img_b, full=True)
print(score)

Если другие заинтересованы в более эффективном способе сравнения схожести изображений, я составил учебное пособие и веб-приложение для измерения и визуализации похожих изображений с помощью Tensorflow.

person duhaime    schedule 30.03.2018
comment
Да, skimage действительно приятно использовать для этого приложения. Я использую from skimage.measure import compare_ssim, compare_mse много. skimage.measure docs. - person ximiki; 11.10.2018

У меня была аналогичная проблема на работе: я переписывал конечную точку преобразования изображения и хотел проверить, что новая версия дает такой же или почти такой же результат, как и старая версия. Итак, я написал это:

https://github.com/nicolashahn/diffimg

Что работает с изображениями одинакового размера и на уровне пикселей, измеряет разницу значений в каждом канале: R, G, B (, A), берет среднюю разницу этих каналов, а затем усредняет разницу по все пиксели и возвращает соотношение.

Например, для изображения 10x10 с белыми пикселями и того же изображения, но один пиксель изменился на красный, разница в этом пикселе составляет 1/3 или 0,33 ... (RGB 0,0,0 против 255,0,0 ), а для всех остальных пикселей - 0. При сумме 100 пикселей 0,33 ... / 100 = разница в изображении ~ 0,33%.

Я считаю, что это отлично сработает для проекта OP (я понимаю, что это очень старый пост, но он публикуется для будущих StackOverflowers, которые также хотят сравнивать изображения в python).

person nicolashahn    schedule 27.05.2018

Большинство приведенных ответов не относятся к уровням освещения.

Я бы сначала нормализовал изображение до стандартного уровня освещенности, прежде чем проводить сравнение.

person Community    schedule 10.10.2008
comment
Если вы делаете периодические снимки и сравниваете соседние пары, вы, вероятно, можете позволить себе сохранить первое после того, как кто-то включит свет. - person walkytalky; 15.10.2010

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

Я бы предложил вейвлет-преобразование ваших фреймов (я написал для него расширение C, использующее преобразование Хаара); затем, сравнивая индексы самых больших (пропорциональных) вейвлет-факторов между двумя изображениями, вы должны получить приближение численного подобия.

person tzot    schedule 10.10.2008

Прошу прощения, если уже слишком поздно для ответа, но, поскольку я делал что-то подобное, я подумал, что могу как-то внести свой вклад.

Возможно, с OpenCV вы могли бы использовать сопоставление шаблонов. Предполагая, что вы используете веб-камеру, как вы сказали:

  1. Упростите изображения (может быть, пороговое значение?)
  2. Примените сопоставление с шаблоном и проверьте max_val с помощью minMaxLoc

Совет: max_val (или min_val в зависимости от используемого метода) даст вам числа, большие числа. Чтобы получить разницу в процентах, используйте сопоставление шаблона с тем же изображением - результат будет ваш 100%.

Псевдокод для иллюстрации:

previous_screenshot = ...
current_screenshot = ...

# simplify both images somehow

# get the 100% corresponding value
res = matchTemplate(previous_screenshot, previous_screenshot, TM_CCOEFF)
_, hundred_p_val, _, _ = minMaxLoc(res)

# hundred_p_val is now the 100%

res = matchTemplate(previous_screenshot, current_screenshot, TM_CCOEFF)
_, max_val, _, _ = minMaxLoc(res)

difference_percentage = max_val / hundred_p_val

# the tolerance is now up to you

Надеюсь, поможет.

person zanfranceschi    schedule 15.06.2018

Расстояние от Earth mover может быть именно тем, что вам нужно. Однако это может быть abit сложно реализовать в реальном времени.

person shoosh    schedule 10.10.2008
comment
Мне не кажется, что этот ответ хорошо подходит: я ищу простоту, а не совершенство. Я использую питон. - person PilouPili; 28.10.2019
comment
Я думаю, что поскольку эта ветка вопросов получает много трафика, а заголовок, который привлекает большинство зрителей, посвящен количественной оценке разницы между двумя изображениями, он имеет здесь значение. - person Danoram; 28.10.2019

Как насчет вычисления Манхэттенского расстояния двух изображений. Это дает вам n * n значений. Затем вы можете сделать что-то вроде среднего значения строки, чтобы уменьшить до n значений, и функцию над ним, чтобы получить одно единственное значение.

person Tobias    schedule 10.10.2008

Мне очень повезло с изображениями в формате jpg, снятыми той же камерой на штативе, путем (1) значительного упрощения (например, перехода с 3000 пикселей в ширину до 100 пикселей в ширину или даже меньше) (2) сглаживания каждого массива jpg в один вектор (3) попарная корреляция последовательных изображений с помощью простого алгоритма корреляции для получения коэффициента корреляции (4) возведение в квадрат коэффициента корреляции для получения r-квадрата (т.е. доля изменчивости в одном изображении, объясняемая вариациями в следующем) (5) обычно в моем приложении если r-square ‹0,9, я говорю, что эти два изображения разные и что-то произошло между ними.

В моей реализации это надежно и быстро (Mathematica 7)

Стоит поиграть с той частью изображения, которая вас интересует, и сосредоточиться на ней, обрезая все изображения до этой небольшой области, иначе удаленное от камеры, но важное изменение будет пропущено.

Я не знаю, как использовать Python, но уверен, что он тоже делает корреляции, не так ли?

person Roman Dial    schedule 19.02.2011

вы можете вычислить гистограмму обоих изображений, а затем вычислить коэффициент Бхаттачарьи, это очень быстрый алгоритм, и я использовал его для обнаружения изменений кадра в видео о крикете (на C с использованием openCV)

person vishalv2050    schedule 24.02.2011
comment
Не могли бы вы рассчитать коэффициент на самих изображениях? - person endolith; 24.02.2011
comment
Вам нужно будет рассчитать гистограммы для изображений (с размером ячейки гистограммы в соответствии с требованиями). - person vishalv2050; 18.03.2011

Узнайте, как вейвлеты Хаара реализованы с помощью isk-daemon. Вы можете использовать его код imgdb C ++ для вычисления разницы между изображениями на лету:

isk-daemon - это сервер базы данных с открытым исходным кодом, способный добавлять контентный (визуальный) поиск изображений к любому веб-сайту или программному обеспечению, связанному с изображениями.

Эта технология позволяет пользователям любого веб-сайта или программного обеспечения, связанного с изображениями, рисовать на виджете, какое изображение они хотят найти, и заставлять веб-сайт отвечать на них с наиболее похожими изображениями или просто запрашивать больше похожих фотографий на каждой странице с подробными сведениями об изображении.

person Ricardo Cabral    schedule 16.01.2012

У меня была та же проблема, и я написал простой модуль Python, который сравнивает два изображения одинакового размера с помощью ImageChops подушки для создания черно-белого изображения различия и суммирует значения гистограммы.

Вы можете получить либо эту оценку напрямую, либо процентное значение по сравнению с полной разницей между черным и белым.

Он также содержит простую функцию is_equal с возможностью предоставления нечеткого порога ниже (и включая) проходов изображения как равных.

Подход не очень продуман, но, возможно, будет полезен другим, борющимся с той же проблемой.

https://pypi.python.org/pypi/imgcompare/

person datenhahn    schedule 21.11.2016

Несколько более принципиальный подход - использовать глобальный дескриптор для сравнения изображений, такой как GIST или CENTRIST. Хеш-функция, описанная здесь, также предоставляет аналогичное решение.

person Felix Goldberg    schedule 29.11.2017

Существует простое и быстрое решение с использованием numpy путем вычисления среднеквадратичной ошибки:

before = np.array(get_picture())
while True:
    now = np.array(get_picture())
    MSE = np.mean((now - before)**2)

    if  MSE > threshold:
        break

    before = now
person Arian Soltani    schedule 18.07.2019

import os
from PIL import Image
from PIL import ImageFile
import imagehash
  
#just use to the size diferent picture
def compare_image(img_file1, img_file2):
    if img_file1 == img_file2:
        return True
    fp1 = open(img_file1, 'rb')
    fp2 = open(img_file2, 'rb')

    img1 = Image.open(fp1)
    img2 = Image.open(fp2)

    ImageFile.LOAD_TRUNCATED_IMAGES = True
    b = img1 == img2

    fp1.close()
    fp2.close()

    return b





#through picturu hash to compare
def get_hash_dict(dir):
    hash_dict = {}
    image_quantity = 0
    for _, _, files in os.walk(dir):
        for i, fileName in enumerate(files):
            with open(dir + fileName, 'rb') as fp:
                hash_dict[dir + fileName] = imagehash.average_hash(Image.open(fp))
                image_quantity += 1

    return hash_dict, image_quantity

def compare_image_with_hash(image_file_name_1, image_file_name_2, max_dif=0):
    """
    max_dif: The maximum hash difference is allowed, the smaller and more accurate, the minimum is 0.
    recommend to use
    """
    ImageFile.LOAD_TRUNCATED_IMAGES = True
    hash_1 = None
    hash_2 = None
    with open(image_file_name_1, 'rb') as fp:
        hash_1 = imagehash.average_hash(Image.open(fp))
    with open(image_file_name_2, 'rb') as fp:
        hash_2 = imagehash.average_hash(Image.open(fp))
    dif = hash_1 - hash_2
    if dif < 0:
        dif = -dif
    if dif <= max_dif:
        return True
    else:
        return False


def compare_image_dir_with_hash(dir_1, dir_2, max_dif=0):
    """
    max_dif: The maximum hash difference is allowed, the smaller and more accurate, the minimum is 0.

    """
    ImageFile.LOAD_TRUNCATED_IMAGES = True
    hash_dict_1, image_quantity_1 = get_hash_dict(dir_1)
    hash_dict_2, image_quantity_2 = get_hash_dict(dir_2)

    if image_quantity_1 > image_quantity_2:
        tmp = image_quantity_1
        image_quantity_1 = image_quantity_2
        image_quantity_2 = tmp

        tmp = hash_dict_1
        hash_dict_1 = hash_dict_2
        hash_dict_2 = tmp

    result_dict = {}

    for k in hash_dict_1.keys():
        result_dict[k] = None

    for dif_i in range(0, max_dif + 1):
        have_none = False

        for k_1 in result_dict.keys():
            if result_dict.get(k_1) is None:
                have_none = True

        if not have_none:
            return result_dict

        for k_1, v_1 in hash_dict_1.items():
            for k_2, v_2 in hash_dict_2.items():
                sub = (v_1 - v_2)
                if sub < 0:
                    sub = -sub
                if sub == dif_i and result_dict.get(k_1) is None:
                    result_dict[k_1] = k_2
                    break
    return result_dict


def main():
    print(compare_image('image1\\815.jpg', 'image2\\5.jpg'))
    print(compare_image_with_hash('image1\\815.jpg', 'image2\\5.jpg', 7))
    r = compare_image_dir_with_hash('image1\\', 'image2\\', 10)
    for k in r.keys():
        print(k, r.get(k))


if __name__ == '__main__':
    main()
  • вывод:

    Неверно
    Верно
    image2 \ 5.jpg image1 \ 815.jpg
    image2 \ 6.jpg image1 \ 819.jpg
    image2 \ 7.jpg image1 \ 900.jpg
    image2 \ 8 .jpg image1 \ 998.jpg
    image2 \ 9.jpg image1 \ 1012.jpg

  • примеры изображений:

    • 815.jpg
       815.jpg

    • 5.jpg
       5.jpg

person admin    schedule 22.05.2017

Я думаю, вы могли бы просто вычислить евклидово расстояние (то есть sqrt (сумма квадратов разностей, пиксель за пикселем)) между яркостью двух изображений и считать их равными, если это подпадает под некоторый эмпирический порог. И вам лучше сделать это, обернув функцию C.

person Federico A. Ramponi    schedule 10.10.2008

Существует множество показателей для оценки того, похожи ли два изображения и насколько они выглядят.

Я не буду здесь вдаваться в какой-либо код, потому что считаю, что это должна быть научная проблема, а не техническая.

Как правило, вопрос связан с восприятием человеком изображений, поэтому каждый алгоритм опирается на особенности зрительной системы человека.

Классические подходы:

Предиктор видимых различий: алгоритм оценки точности изображения (https://www.spiedigitallibrary.org/conference-proceedings-of-spie/1666/0000/Visible-differences-predictor--an-algorithm-for-the-rating-of/10.1117/12.135952.short?SSO=1)

Оценка качества изображения: от видимости ошибок к структурному сходству (http://www.cns.nyu.edu/pub/lcv/wang03-reprint.pdf).

FSIM: индекс сходства функций для оценки качества изображения (https://www4.comp.polyu.edu.hk/~cslzhang/IQA/TIP_IQA_FSIM.pdf)

Среди них SSIM (оценка качества изображения: от видимости ошибок до структурного сходства) является самым простым для расчета, и его накладные расходы также небольшие, как сообщается в другом документе «Оценка качества изображения на основе сходства градиентов» (https://www.semanticscholar.org/paper/Image-Quality-Assessment-Based-on-Gradient-Liu-Lin/2b819bef80c02d5d4cb56f27b202535e119df988).

Есть еще много других подходов. Взгляните на Google Scholar и поищите что-нибудь вроде «визуальная разница», «оценка качества изображения» и т. Д., Если вы заинтересованы / действительно заботитесь об искусстве.

person cyfex    schedule 07.05.2019

Вот функция, которую я написал, которая принимает 2 изображения (пути к файлам) в качестве аргументов и возвращает среднюю разницу между компонентами пикселей двух изображений. Это очень хорошо помогло мне определить визуально одинаковые изображения (когда они не == одинаковы).

(Я обнаружил, что 8 - хороший предел, чтобы определить, одинаковы ли изображения по сути.)

(Если вы не добавляете предварительную обработку, изображения должны иметь те же размеры.)

from PIL import Image

def imagesDifference( imageA, imageB ):
    A = list(Image.open(imageA, r'r').convert(r'RGB').getdata())
    B = list(Image.open(imageB, r'r').convert(r'RGB').getdata())
    if (len(A) != len(B)): return -1
    diff = []
    for i in range(0, len(A)):
        diff += [abs(A[i][0] - B[i][0]), abs(A[i][1] - B[i][1]), abs(A[i][2] - B[i][2])]
    return (sum(diff) / len(diff))
person Pedro Vernetti    schedule 27.02.2021