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

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

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

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

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

Связанный: stackoverflow.com/questions/25977/…

Anoyz 09.06.2015 16:01
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
191
1
194 830
22

Ответы 22

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

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

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

Это очень легкое и простое решение, которое намного лучше любого пиксельного сравнения. Если на изображении вашей веб-камеры присутствует небольшой шум или если изображение сдвинуто хотя бы на один пиксель, то прямое сравнение выявит все эти бессмысленные изменения. Более надежным подходом было бы вычисление дискретного косинусного преобразования и последующее сравнение изображений в частотной области. Такое сжатие JPEG дает вам большую часть преимуществ, не углубляясь в теорию Фурье.

AndrewF 14.10.2010 21:12

Нравится это. Хотя другие решения тоже работают, это дает большое преимущество для общей ситуации: что, если вы не хотите сохранять «базовое» изображение? просто сохраните размер файла как хэш, а затем сравните только числа с вычитанием. В моем случае у меня есть 4 изображения, одно из них очень похожее, а остальные 3 совершенно разные. Просто выполните масштабирование до тех же размеров, до jpg и вычтите. Действительно мило.

Diego Andrés Díaz Espinoza 01.07.2018 05:09

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

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

Мне не кажется, что в этом ответе хорошо сказано: «Я ищу простоты, а не совершенства. Я использую python».

PilouPili 28.10.2019 14:04

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

Danoram 28.10.2019 14:24

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

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

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

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

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

а как бы вы сравнили пиксели?

carrier 10.10.2008 19:13

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

Ates Goral 15.10.2008 07:45

«сравнить пиксели один за другим». Что это обозначает? Должен ли тест завершиться неудачно, если ОДИН из тестов 64 ^ 2 пикселей на пиксель не пройден?

Federico A. Ramponi 15.10.2008 17:25

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

Ates Goral 15.10.2008 20:31

Очень простой пример, без «нечеткого алгоритма»: параллельный цикл через каждый пиксель (сравните пиксель № п изображения № 1 с пикселем № п изображения № 2) и добавьте разницу значений в переменную.

mk12 08.11.2009 04:00

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

Ates Goral 30.01.2013 23:52

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

Используя 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 представляют собой массивы двухмерных изображений в градациях серого.

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

endolith 17.09.2009 20:16

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

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

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

walkytalky 15.10.2010 15:03

Вы можете сравнить два изображения, используя функции из 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.

Я хочу сохранить изображение разницы. означает объект diff, который содержит разницу изображений. как мне его спасти?

Sagar 21.02.2014 10:30

@Anthony вы можете вызвать save () для объекта diff, указав имя изображения. вот так: diff.save ("diff.png") он сохранит для вас разностное изображение.

Sagar 26.06.2015 11:08

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

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

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

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

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

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

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

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

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

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

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

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

Не могли бы вы рассчитать коэффициент на самих изображениях?

endolith 24.02.2011 23:35

Вам нужно будет рассчитать гистограммы для изображений (с размером ячейки гистограммы в соответствии с требованиями).

vishalv2050 18.03.2011 08:51

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

isk-daemon is an open source database server capable of adding content-based (visual) image searching to any image related website or software.

This technology allows users of any image-related website or software to sketch on a widget which image they want to find and have the website reply to them the most similar images or simply request for more similar photos at each image detail page.

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

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

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

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

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

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()
  • выход:

    Ложь True
    image2 \ 5.jpg image1 \ 815.jpg
    image2 \ 6.jpg image1 \ 819.jpg
    image2 \ 7.jpg image1 \ 900.jpg
    изображение2 \ 8.jpg изображение1 \ 998.jpg
    image2 \ 9.jpg image1 \ 1012.jpg

  • примеры картинок:

    • 815.jpg
      815.jpg

    • 5.jpg
      5.jpg

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

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

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.

Да, skimage действительно хорош для этого приложения. Я много использую from skimage.measure import compare_ssim, compare_mse. skimage.measure docs.

ximiki 11.10.2018 18:10

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

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).

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

Возможно, с 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

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

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

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

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

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

Предиктор видимых различий: алгоритм оценки точности изображения (https://www.spiedigitallibrary.org/conference-proceedings-of-spie/1666/0000/Visible-differences-predictor--an-algorithm-for-the-assessment-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 и поищите что-нибудь вроде «визуальная разница», «оценка качества изображения» и т. д., Если вы заинтересованы / действительно заботитесь об искусстве.

Существует простое и быстрое решение с использованием 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

Вот функция, которую я написал, которая принимает 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))

Другие вопросы по теме