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






Простое решение:
Кодируйте изображение как jpeg и ищите существенное изменение в размер файла.
Я реализовал нечто подобное с миниатюрами видео и добился большого успеха и масштабируемости.
Это очень легкое и простое решение, которое намного лучше любого пиксельного сравнения. Если на изображении вашей веб-камеры присутствует небольшой шум или если изображение сдвинуто хотя бы на один пиксель, то прямое сравнение выявит все эти бессмысленные изменения. Более надежным подходом было бы вычисление дискретного косинусного преобразования и последующее сравнение изображений в частотной области. Такое сжатие JPEG дает вам большую часть преимуществ, не углубляясь в теорию Фурье.
Нравится это. Хотя другие решения тоже работают, это дает большое преимущество для общей ситуации: что, если вы не хотите сохранять «базовое» изображение? просто сохраните размер файла как хэш, а затем сравните только числа с вычитанием. В моем случае у меня есть 4 изображения, одно из них очень похожее, а остальные 3 совершенно разные. Просто выполните масштабирование до тех же размеров, до jpg и вычтите. Действительно мило.
Я думаю, вы могли бы просто вычислить евклидово расстояние (то есть sqrt (сумма квадратов разностей, пиксель за пикселем)) между яркостью двух изображений и считать их равными, если это подпадает под некоторый эмпирический порог. И вам лучше сделать это, обернув функцию C.
Дистанция земляных движителей может быть именно тем, что вам нужно. Однако реализация немного в реальном времени может оказаться сложной задачей.
Мне не кажется, что в этом ответе хорошо сказано: «Я ищу простоты, а не совершенства. Я использую python».
Я думаю, поскольку эта ветка вопросов получает много трафика, а заголовок, который привлекает большинство зрителей, посвящен количественной оценке разницы между двумя изображениями, здесь он имеет значение.
Как насчет вычисления Манхэттен Расстояние двух изображений. Это дает вам n * n значений. Затем вы можете сделать что-то вроде среднего значения строки, чтобы уменьшить до n значений, и функцию над ним, чтобы получить одно значение.
Вы видели вопрос Алгоритм поиска похожих изображений? Проверьте это, чтобы увидеть предложения.
Я бы предложил вейвлет-преобразование ваших фреймов (я написал для него расширение C, использующее преобразование Хаара); затем, сравнивая индексы самых больших (пропорциональных) вейвлет-факторов между двумя изображениями, вы должны получить приближение численного подобия.
Тривиальная вещь, которую стоит попробовать:
Измените выборку обоих изображений на маленькие миниатюры (например, 64 x 64) и сравните миниатюры попиксельно с определенным порогом. Если исходные изображения почти такие же, миниатюрные изображения с повторной выборкой будут очень похожими или даже точно такими же. Этот метод устраняет шум, который может возникать, особенно в условиях низкой освещенности. Возможно, будет даже лучше, если вы выберете оттенки серого.
а как бы вы сравнили пиксели?
Когда у вас есть эскизы, вы можете просто сравнивать пиксели один за другим. Вы должны вычислить «расстояние» значений RGB, если вы работаете в цвете, или просто разницу между серыми тонами, если вы находитесь в градациях серого.
«сравнить пиксели один за другим». Что это обозначает? Должен ли тест завершиться неудачно, если ОДИН из тестов 64 ^ 2 пикселей на пиксель не пройден?
Под «сравнением миниатюр попиксельно с определенным порогом» я имел в виду создание нечеткого алгоритма для сравнения пикселей. Если вычисленная разница (зависит от вашего нечеткого алгоритма) превышает определенный порог, изображения «не совпадают».
Очень простой пример, без «нечеткого алгоритма»: параллельный цикл через каждый пиксель (сравните пиксель № п изображения № 1 с пикселем № п изображения № 2) и добавьте разницу значений в переменную.
@ Mk12 Этот метод может не работать с источником шумного изображения, например веб-камерой.
Два популярных и относительно простых метода: (а) уже предложенное евклидово расстояние или (б) нормализованная взаимная корреляция. Нормализованная взаимная корреляция имеет тенденцию быть заметно более устойчивой к изменениям освещения, чем простая взаимная корреляция. Википедия дает формулу для нормализованная взаимная корреляция. Существуют и более сложные методы, но они требуют немного больше работы.
Используя 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)
Большинство приведенных ответов не относятся к уровням освещения.
Я бы сначала нормализовал изображение до стандартного уровня освещенности, прежде чем проводить сравнение.
Если вы делаете периодические снимки и сравниваете соседние пары, вы, вероятно, можете позволить себе сохранить первое после того, как кто-то включит свет.
Вы можете сравнить два изображения, используя функции из 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, который содержит разницу изображений. как мне его спасти?
@Anthony вы можете вызвать save () для объекта diff, указав имя изображения. вот так: diff.save ("diff.png") он сохранит для вас разностное изображение.
Я конкретно обращаюсь к вопросу о том, как вычислить, достаточно ли они различны. Я полагаю, вы можете понять, как вычитать пиксели один за другим.
Во-первых, я бы взял кучу изображений с изменением ничего такого и выяснил, насколько сильно изменяется любой пиксель только из-за изменений в захвате, шума в системе формирования изображений, артефактов сжатия JPEG и моментальных изменений освещения. . Возможно, вы обнаружите, что следует ожидать разницы в 1 или 2 бита, даже когда ничего не движется.
Тогда для «настоящего» теста вам нужен такой критерий:
Так что, возможно, если 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)
Не могли бы вы рассчитать коэффициент на самих изображениях?
Вам нужно будет рассчитать гистограммы для изображений (с размером ячейки гистограммы в соответствии с требованиями).
Посмотрите, как реализованы вейвлеты Хаара с помощью 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 с возможностью предоставления нечеткого порога ниже (и включая) проходов изображения как равных.
Подход не очень продуман, но, возможно, будет полезен другим, борющимся с той же проблемой.
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()
Несколько более принципиальный подход - использовать глобальный дескриптор для сравнения изображений, такой как 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.
У меня была аналогичная проблема на работе: я переписывал конечную точку преобразования изображения и хотел проверить, что новая версия дает такой же или почти такой же результат, как и старая версия. Итак, я написал это:
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 вы могли бы использовать сопоставление шаблонов. Предполагая, что вы используете веб-камеру, как вы сказали:
Совет: 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))
Связанный: stackoverflow.com/questions/25977/…