Проблема:
У меня есть около 10 000 изображений для сравнения друг с другом. Моя текущая программа сравнивает около 60 изображений каждую секунду, но при такой скорости для завершения потребуется почти 9 дней. Я пытался использовать С++, но окончательный код занял бы почти в 3 раза больше времени, чем код Python.
Вопрос:
Есть ли более быстрый или эффективный способ сравнения изображений? Я в порядке с использованием других языков и других библиотек.
Код:
from PIL import Image
from PIL import ImageChops
import math, operator
from functools import reduce
import os
def rmsdiff(image_1, image_2):
h = ImageChops.difference(image_1, image_2).histogram()
return math.sqrt(reduce(operator.add, map(lambda h, i: i%256*(h**2), h, range(len(h)))) / (float(image_1.size[0]) * image_1.size[1]))
current = 0
try:
dire = "C:\\Users\\Nikola\\Downloads\\photos"
photos = os.listdir(dire)
for idx, val in enumerate(photos):
if val == "":
start = idx
break
for photo_1 in range(start,len(photos)):
if "." not in photos[photo_1]:
continue
print(f'Image: {photos[photo_1]}')
with Image.open(dire+"\\"+photos[photo_1]) as image_1:
image_1 = image_1.resize((16,16))
for photo_2 in range(photo_1+1, len(photos)):
current = photos[photo_2]
try:
if photos[photo_2][-4] != "." and photos[photo_2][-5] != ".":
continue
except:
continue
with Image.open(dire+"\\"+photos[photo_2]) as image_2:
image_2 = image_2.resize((16,16))
try:
value = rmsdiff(image_1, image_2)
if value < 12:
print(f'Similar Image: {photos[photo_1]}')
continue
except:
pass
except KeyboardInterrupt:
print()
print(current)
Чего вы на самом деле пытаетесь достичь? Что вы знаете об изображениях — все ли они одного размера? Тот же формат? Тот же предмет? Что вы знаете об используемой вами машине — многоядерный процессор? Быстрые диски NVMe? Много оперативной памяти?
@ Александр Я сравниваю каждое изображение с другим изображением, которое может быть изменено, размыто, на изображении могут быть артефакты. Оно должно быть достаточно похожим, чтобы в изображении было небольшое количество изменений.
@MarkSetchell Я пытаюсь понять, все ли изображения в определенной степени уникальны. Все изображения имеют разные размеры и форматы, но большинство из них относятся к одной и той же теме. Я не думаю, что мой ноутбук имеет несколько процессоров, у него нет диска NVMe и 8 ГБ ОЗУ.
Вы, кажется, сравниваете каждое изображение со всеми теми, которые следуют за ним в списке каталогов. Это означает, что последнее изображение будет открыто и изменено до размера 16x16 в общей сложности почти 10 000 раз. Если вы сравниваете только версии 16x16, у вас достаточно оперативной памяти для одновременного хранения всех изображений, измененных до 16x16, поэтому вы открываете их и изменяете размер только один раз.
Возможно, вы могли бы использовать functools.lru_cache(), чтобы украсить функцию, которая открывается и изменяет размер до 16x16, если вы не хотите сильно менять свой алгоритм... docs.python.org/3/library/functools.html
Меня не слишком беспокоит изменение моего кода. Если нужно, я поменяю языки.
Если ваши изображения в формате JPEG, вам обязательно следует использовать функцию «сжатие при загрузке», также известную как «черновой» режим в PIL, потому что вы изменяете размер очень маленьким stackoverflow.com/a/57717879/2836621
Что вы имеете в виду под "сравнить"? Каково фактическое правило, которое необходимо реализовать? Если у меня есть несколько изображений в качестве входных данных для этого кода, как я могу вообще знать, что я должен ожидать в качестве вывода?
вы просто спрашиваете о микрооптимизации, что здесь неправильно. вам нужно уменьшить сложность всей операции. en.wikipedia.org/wiki/Content-based_image_retrieval — уменьшите пространство поиска, даже не рассматривая пары, которые явно не похожи. используйте некоторый тип хэширования «контента». ИИ может помочь (отрежьте классификационный слой, вы получите векторный слой). есть еще "перцептивное хеширование"
@ChristophRackwitz Да, я прошу оптимизировать мой код. Я не сказал, что это исходный вопрос, потому что я не думал, что это имеет значение, но я вручную отсортировал около 40000 изображений по 8 различным категориям. Так что я уже сократил время выполнения с ~ 5 месяцев до 9-10 дней.
ты хочешь закончить менее чем за час, то есть за то время, которое требуется, чтобы прочитать все эти изображения? потому что вы можете, если вы не настаиваете на своем подходе
@ChristophRackwitz Я изучил, что такое перцептивное хеширование. Я внедрил его в свой код, ожидая, что он будет медленнее. Первые несколько запусков были медленнее, потому что я не откалибровал их должным образом, но после калибровки хэширование стало в 10 раз быстрее, и я нашел больше похожих изображений. Спасибо






Однако ваша проблема довольно странная. Тот факт, что вам нужно читать сами данные для сравнения, не должен происходить в большинстве случаев, и было бы разумно, если бы у вас были некоторые метаданные для сравнения.
Тем не менее, вот несколько очень разных подходов к ускорению этого.
Следуя моим комментариям, я предполагаю, что загрузка и изменение размера занимают больше всего времени, поэтому я бы стремился к оптимизации.
В настоящее время у меня нет доступного интерпретатора Python для правильного тестирования, но в следующем порядке:
from functools import lru_cache
@lru_cache(maxsize=None)
def loadImage(filename)
im = Image.open(filename)
im = im.resize((16,16))
return im
Это уже должно иметь огромное значение. Затем настройте режим «черновик», например:
im = Image.open(filename)
im.draft('RGB',(32,32))
im = im.resize((16,16)
return im
Вы также можете использовать многопоточную загрузку, если ваш ноутбук имеет приличный процессор.
Я хотел бы проголосовать за этот ответ, но мне нужно более 15 повторений
С чем вы их сравниваете? вы просто проверяете, идентичны ли они или какую эвристику вы используете для сравнения