За последние 24 часа нас посетили 37120 программистов и 7905 роботов. Сейчас ищут 1817 программистов ...

Сравнение изображений через хеш в Imagick

Тема в разделе "Обработка изображений средствами PHP", создана пользователем zhenia3003, 19 апр 2024.

  1. zhenia3003

    zhenia3003 Активный пользователь

    С нами с:
    20 авг 2012
    Сообщения:
    184
    Симпатии:
    3
    Пытаюсь сравнить 2 одинаковых изображения через хеш. Разница изображений только в размерах, первое - 800х600 px, второе - 1280х960 px.
    Делаю так:
    1. Уменьшаю изображения до 10х10 px.
    2. Применяю фильтр в серые тона.
    3. Снимаю хеш.
    Однако хеш у двух сравниваемых изображений разный, что делаю не так?

    PHP:
    1. $imagick = new Imagick();
    2. $imagick->readImage($_SERVER['DOCUMENT_ROOT'].'/1.jpg');
    3. $imagick->resizeImage(10, 10, Imagick::FILTER_LANCZOS, 1);
    4. $imagick->setImageType(Imagick::IMGTYPE_GRAYSCALE);
    5. $imagick->writeImage($_SERVER['DOCUMENT_ROOT'].'/image.jpg');
    6. $hash = $imagick->getImageSignature();
    7. print($hash);
    8. $imagick->destroy();
    9. echo '<br><img src="image.jpg">';
     
  2. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.840
    Симпатии:
    1.338
    Адрес:
    Лень
    после первого пункта, сюда скинь изображения в архиве.
     
  3. Дюран

    Дюран Активный пользователь

    С нами с:
    9 мар 2018
    Сообщения:
    291
    Симпатии:
    21
    Как изображения могут быть одинаковыми если их размеры отличаются?...
     
  4. don.bidon

    don.bidon Активный пользователь

    С нами с:
    28 мар 2021
    Сообщения:
    947
    Симпатии:
    147
    Попытка решения задачи описана, сам бы так решал, проблема в том, что какие-то тесты не проскакивают, с меня пока что идей нет (
     
  5. Vladimir Kheifets

    Vladimir Kheifets Новичок

    С нами с:
    23 сен 2023
    Сообщения:
    485
    Симпатии:
    97
    Адрес:
    Бавария, Германия
    Добрый день!

    В Adobe Fireworks, в начале сделал изображение 1280х960 px, сохранил как 2.jpg, затем тоже изображение
    скалировал до - 800х600 px и сохранил как 1.jpg
    Попытался сравнить два изображения также как и Вы:
    1. Уменьшаю изображения до 10х10 px.
    2. Применяю фильтр в серые тона.
    3. Снимаю $hash1 для файла 1.jpg

    Добавил 4. Снимаю $blob1 для файла 1.jpg
    PHP:
    1. $blob1 = $imagick->getImageBlob();
    Повторяю тоже самое для файла 2.jpg
    т.е. снимаю $hash2 и, $blob2

    Сравниваю $hash1 и $hash2
    hash1:
    80e5071b812affd70e5cb101eae6546ef6db774d2b06592ee73409e0a362327c
    hash2:
    77b75b6c908bc8372f478253344a0bd6315bcafa80a99d0ae432592e29fcdee3

    Чтобы понять почему не совпадают хеш у двух сравниваемых изображений
    сравниваю $blob1 и $blob2.

    Blob compare, display hexadecimal number

    Byte N: 00548 => blob1: 32 != blob2: 31
    Byte N: 00550 => blob1: 32 != blob2: 34
    Byte N: 00551 => blob1: 35 != blob2: 36
    Byte N: 13011 => blob1: 76 != blob2: 74

    Blob compare, display binary number

    Byte N: 00548 => blob1: 00110010 != blob2: 00110001
    Byte N: 00550 => blob1: 00110010 != blob2: 00110100
    Byte N: 00551 => blob1: 00110101 != blob2: 00110110
    Byte N: 13011 => blob1: 01110110 != blob2: 01110100

    Четыре байта не совпадают.

    Удачи!
     
  6. zhenia3003

    zhenia3003 Активный пользователь

    С нами с:
    20 авг 2012
    Сообщения:
    184
    Симпатии:
    3
    Планируется хранить информацию для сравнения изображений в БД, а blob занимает место, поэтому такой вариант сравнения отпадает. Вместо сравнения getImageSignature решил попробовать сравнить изображения через getImagePixelColor:
    PHP:
    1. function similar($data)
    2. {
    3.     $image = new Imagick($data);
    4.     $image->setImageType(Imagick::IMGTYPE_GRAYSCALE);
    5.     $image->resizeImage(4, 4, Imagick::FILTER_LANCZOS, 1);
    6.     $width = $image->getImageWidth();
    7.     $height = $image->getImageHeight();
    8.     for ($x = 0; $x < $width; $x++)
    9.     {
    10.         for ($y = 0; $y < $height; $y++)
    11.         {
    12.         $pixel = $image->getImagePixelColor($x, $y)->getColor();
    13.         $t[] = $pixel['r'];
    14.       }
    15.     }
    16.     $color = implode(',', $t);
    17.     return $color;
    18. }
    Получилось следующее:

    60,46,84,86,75,69,61,29,87,110,97,60,101,101,107,111 - image1.jpg
    60,46,84,86,75,69,62,30,87,110,97,60,101,101,107,111 - image2.jpg (уменьшенная копия image1.jpg)
    92,131,114,77,73,111,99,52,110,144,93,57,147,157,161,123 - image3.jpg
    64,49,81,81,74,70,62,28,88,111,98,63,100,100,107,112 - image4.jpg (обрезанная 10px слева копия image1.jpg)
    31,61,41,16,76,106,78,84,92,107,76,100,42,69,41,21 - image5.jpg
    86,112,124,118,72,107,155,145,71,101,124,135,83,126,123,138 - image6.jpg
    197,81,39,31,223,160,56,33,217,134,58,28,39,43,53,19 - image7.jpg

    Планируется сравнивать по точному совпадению строки, а так же по ближайшему совпадению чисел, на сколько надежен этот способ?
     
  7. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.840
    Симпатии:
    1.338
    Адрес:
    Лень
    Считывай пиксели картинки путем конвертирования в черно/белый цвет и записывай пиксели в строку 1-белый, 0-черный.

    PHP:
    1.     public function iteratorСonvertToBlackAndWhite(): \Closure
    2.     {
    3.         return static function ( \GdImage $image, int $x, int $y, int $width, int $height, int $brightness = 128 ): Iterable
    4.         {
    5.             $height += $y;
    6.             $width += $x;
    7.        
    8.             for ( $_y = $y; $_y < $height; $_y++ )
    9.             {
    10.                 for ( $_x = $x; $_x < $width; $_x++ )
    11.                 {
    12.                     $index = imagecolorat ( $image, $_x, $_y );
    13.                
    14.                     $r = ( $index >> 16 ) & 0xFF;
    15.                     $g = ( $index >> 8 ) & 0xFF;
    16.                     $b = $index & 0xFF;
    17.                
    18.                     yield [
    19.                         'x' => $_x,
    20.                         'y' => $_y,
    21.                         'color' => ( ( $r + $g + $b ) / 3 > $brightness ? 16777215 : 0 )
    22.                     ];
    23.                 }
    24.             }
    25.         };
    26.     }
    PHP:
    1. $points .= $result['color'] ? 1 : 0;
    Далее, полученную строку сверяешь с основной строкой со сверяемой картины. Делается это прикольной функцией https://www.php.net/manual/ru/function.similar-text.php
    1110101010110 == 1110101010110
    --- Добавлено ---
    Мой персептрон для распознавания изображений
    6f7020c44c0cca89cf5f4061d1b070a1.png b4fcd66e10a0737dfd3b9f8a585f77d8.png ef6cc3545af09d9f48d76d4da33685b0.png
     
  8. zhenia3003

    zhenia3003 Активный пользователь

    С нами с:
    20 авг 2012
    Сообщения:
    184
    Симпатии:
    3
    Интересное решение. Повторил с Imagick. Единственное не понятно значение $brightness = 128 в Вашем примере. ($r+$g+$b)/3>$brightness = 128. что означает 128 ? Синий цвет?
    PHP:
    1. function similar($data)
    2. {
    3.     $image = new Imagick($data);
    4.     // Конвертируем в 16 bit
    5.     $image->setImageDepth(16);
    6.     $image->resizeImage(10, 10, Imagick::FILTER_LANCZOS, 1);
    7.     $w = $image->getImageWidth();
    8.     $h = $image->getImageHeight();
    9.     for ($x = 0; $x < $w; $x++)
    10.     {
    11.         for ($y = 0; $y < $h; $y++)
    12.         {
    13.         $rgb = $image->getImagePixelColor($x, $y)->getColor();
    14.         $t[] = (($rgb['r'] + $rgb['g'] + $rgb['b'] / 3) > 128 ? 1 : 0);
    15.       }
    16.     }
    17.     $color = implode(',', $t);
    18.     return $color;
    19. }
     
  9. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.840
    Симпатии:
    1.338
    Адрес:
    Лень
    Яркость каждого из трёх основных цветов закодирована числом от 0 до 255. Т.е. 256 ( с учетом 0). Делим на 2 и всё что больше 128 по яркости - это 1, иначе 0 черный.