Blog. Just Blog

Сравнение изображений на PHP

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Web-мастеру и не только | Автор: ManHunter
Сравнение изображений на PHP
Сравнение изображений на PHP

На работе возникла интересная задача. В базе имеются объекты, к каждому из которых привязано некоторое количество изображений. Проблема в том, что некоторые изображения дублируются, т.к. одно и то же исходное изображение было подгружено к объекту несколько раз. Дополнительная сложность заключается в том, что дубли могут отличаться по времени загрузки, а также быть в разном формате и с разным сжатием. То есть визуально их можно считать идентичными, а файлы по своим параметрам абсолютно разные. Объектов и изображений достаточно много, просмотреть каждый и обработать вручную нереально. Задача заключалась в автоматизации этого процесса.

Сперва немного теории. Цвет каждой точки изображения можно представить в виде числа. Если к двум числам применить логическую операцию XOR, то совпадающие единичные биты будут обнулены. В результате, чем точнее совпадали исходные числа, тем ближе к нулю будет результат дизъюнкции. Если перенести это на нашу задачу, то чем точнее совпадают цвета на двух картинках, тем ближе к черному цвету получится результат XOR. Для большей точности сравнения исходные изображения желательно перевести в оттенки серого.

Изображение после дизъюнкции
Изображение после дизъюнкции

Вот так примерно выглядит изображение, полученное в результате дизъюнкции двух файлов с идентичными изображениями, но разным коэффициентом JPEG-сжатия. А скрипт для сравнения у меня получился вот такой:
  1. // Файлы для обработки
  2. $file1='image_1.jpg';
  3. $file2='image_2.jpg';
  4.  
  5. $im1=ImageCreateFromJPEG($file1);
  6. $im2=ImageCreateFromJPEG($file2);
  7.  
  8. // Размеры изображения
  9. $width=ImageSX($im1);
  10. $height=ImageSY($im1);
  11.  
  12. $count=0;
  13. for ($x=0$x<$width$x++) {
  14.     for ($y=0$y<$height$y++) {
  15.         // Цвет точки первого изображения
  16.         $rgb1=ImageColorAt($im1,$x,$y);
  17.         $R1=($rgb1 >> 16) & 0xFF;
  18.         $G1=($rgb1 >> 8) & 0xFF;
  19.         $B1=$rgb1 0xFF;
  20.  
  21.         // Цвет точки второго изображения
  22.         $rgb2=ImageColorAt($im2,$x,$y);
  23.         $R2=($rgb2 >> 16) & 0xFF;
  24.         $G2=($rgb2 >> 8) & 0xFF;
  25.         $B2=$rgb2 0xFF;
  26.  
  27.         // Перевести в оттенки серого
  28.         $gray1=(0.2126*$R1+0.7152*$G1+0.0722*$B1);
  29.         $gray2=(0.2126*$R2+0.7152*$G2+0.0722*$B2);
  30.  
  31.         // Если получился цвет, близкий к черному,
  32.         // то считаем, что цвета точек условно равны
  33.         if (($gray1^$gray2) < 5) {
  34.             $count++;
  35.         }
  36.     }
  37. }
  38.  
  39. // Прибраться за собой
  40. ImageDestroy($im1);
  41. ImageDestroy($im2);
  42.  
  43. // Коэффициент похожести изображений в процентах
  44. $similarity=intval($count/$x/$y*100);
Скрипт максимально упрощен, в нем подразумевается, что размеры сравниваемых изображений одинаковые и оба файла в формате JPEG. В реальном проекте всяческих проверок гораздо больше, хотя основной алгоритм сравнения точно такой же.

Решение приравнять изображение к дублям или нет принимается на основании полученного коэффициента похожести в процентах. Для похожих изображений он будет 90% и больше. Если у одного из изображений менялась яркость или контрастность, то придется подкорректировать значение "близости к черному" в сторону увеличения, это подбирается опытным путем.

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

Поделиться ссылкой ВКонтакте
Просмотров: 4329 | Комментариев: 7

Метки: PHP, графика
Внимание! Статья опубликована больше года назад, информация могла устареть!

Комментарии

Отзывы посетителей сайта о статье
Grey (09.08.2018 в 08:20):
Я раньше сравнивал списки адресов, там меньше 95% это уже гарантированное несовпадение, поскольку номер дома имеет чуть ли не ключевую роль. Тут пиксели равны, разве кроме центральной части, на чем пытается обычно фотограф сконцентрировать внимание. Полагаю, что на фотках 50% это тоже совпадение.
ManHunter (08.08.2018 в 13:31):
Смотря насколько изображения разные. Но явно меньше 90.
Grey (08.08.2018 в 12:54):
А у разных изображений в каких пределах коэффициенты?
ManHunter (04.08.2018 в 12:47):
ЦитатаНе знаю, насколько быстро PHP умеет изменять размер изображения, думаю, что достаточно быстро.

Очень быстро, если правильно подойти к задаче: http://www.manhunter.ru/webmas...vyushki.html
wet (03.08.2018 в 21:51):
Я тоже решал подобную задачу, правда просто искал подобные фото на диске. Помогает определить подобие "Расстояние Хэмминга" , число позиций, в которых различаются соответствующие символы двух строк одинаковой длины.
Способ похож на Ваш, только для скорости работа проводилась не с целым изображением, а его уменьшенной копией. Не знаю, насколько быстро PHP умеет изменять размер изображения, думаю, что достаточно быстро.
По факту, уменьшенные изображения если одинаковы, то и оригинальные изображения одинаковы. Уменьшаем радикально, вплоть до 8х8 пикселей.
Соответственно цикл  меньше, время существенно меньше затрачивается, и не зависит от оригинального размера фото.
ManHunter (03.08.2018 в 10:41):
Alkov, если сравнивать тупо "в лоб", то дохрена и больше. В моем случае задача упрощалась, т.к. сравнивать надо было не по всей базе, а в пределах одного объекта, а там несколько изображений. Ну и дополнительно проверялись размеры картинок, если они не совпадали, то сравнение сразу прекращалось.
Alkov (03.08.2018 в 08:49):
И сколько же времени займёт сравнение одного изображения со всем множеством в базе ?

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2024
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.07 сек. / MySQL: 2 (0.0043 сек.) / Память: 4.5 Mb
Наверх