Пытаюсь сравнить 2 одинаковых изображения через хеш. Разница изображений только в размерах, первое - 800х600 px, второе - 1280х960 px. Делаю так: 1. Уменьшаю изображения до 10х10 px. 2. Применяю фильтр в серые тона. 3. Снимаю хеш. Однако хеш у двух сравниваемых изображений разный, что делаю не так? PHP: $imagick = new Imagick(); $imagick->readImage($_SERVER['DOCUMENT_ROOT'].'/1.jpg'); $imagick->resizeImage(10, 10, Imagick::FILTER_LANCZOS, 1); $imagick->setImageType(Imagick::IMGTYPE_GRAYSCALE); $imagick->writeImage($_SERVER['DOCUMENT_ROOT'].'/image.jpg'); $hash = $imagick->getImageSignature(); print($hash); $imagick->destroy(); echo '<br><img src="image.jpg">';
Попытка решения задачи описана, сам бы так решал, проблема в том, что какие-то тесты не проскакивают, с меня пока что идей нет (
Добрый день! В 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: $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 Четыре байта не совпадают. Удачи!
Планируется хранить информацию для сравнения изображений в БД, а blob занимает место, поэтому такой вариант сравнения отпадает. Вместо сравнения getImageSignature решил попробовать сравнить изображения через getImagePixelColor: PHP: function similar($data) { $image = new Imagick($data); $image->setImageType(Imagick::IMGTYPE_GRAYSCALE); $image->resizeImage(4, 4, Imagick::FILTER_LANCZOS, 1); $width = $image->getImageWidth(); $height = $image->getImageHeight(); for ($x = 0; $x < $width; $x++) { for ($y = 0; $y < $height; $y++) { $pixel = $image->getImagePixelColor($x, $y)->getColor(); $t[] = $pixel['r']; } } $color = implode(',', $t); return $color; } Получилось следующее: 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 Планируется сравнивать по точному совпадению строки, а так же по ближайшему совпадению чисел, на сколько надежен этот способ?
Считывай пиксели картинки путем конвертирования в черно/белый цвет и записывай пиксели в строку 1-белый, 0-черный. PHP: public function iteratorСonvertToBlackAndWhite(): \Closure { return static function ( \GdImage $image, int $x, int $y, int $width, int $height, int $brightness = 128 ): Iterable { $height += $y; $width += $x; for ( $_y = $y; $_y < $height; $_y++ ) { for ( $_x = $x; $_x < $width; $_x++ ) { $index = imagecolorat ( $image, $_x, $_y ); $r = ( $index >> 16 ) & 0xFF; $g = ( $index >> 8 ) & 0xFF; $b = $index & 0xFF; yield [ 'x' => $_x, 'y' => $_y, 'color' => ( ( $r + $g + $b ) / 3 > $brightness ? 16777215 : 0 ) ]; } } }; } PHP: $points .= $result['color'] ? 1 : 0; Далее, полученную строку сверяешь с основной строкой со сверяемой картины. Делается это прикольной функцией https://www.php.net/manual/ru/function.similar-text.php 1110101010110 == 1110101010110 --- Добавлено --- Мой персептрон для распознавания изображений
Интересное решение. Повторил с Imagick. Единственное не понятно значение $brightness = 128 в Вашем примере. ($r+$g+$b)/3>$brightness = 128. что означает 128 ? Синий цвет? PHP: function similar($data) { $image = new Imagick($data); // Конвертируем в 16 bit $image->setImageDepth(16); $image->resizeImage(10, 10, Imagick::FILTER_LANCZOS, 1); $w = $image->getImageWidth(); $h = $image->getImageHeight(); for ($x = 0; $x < $w; $x++) { for ($y = 0; $y < $h; $y++) { $rgb = $image->getImagePixelColor($x, $y)->getColor(); $t[] = (($rgb['r'] + $rgb['g'] + $rgb['b'] / 3) > 128 ? 1 : 0); } } $color = implode(',', $t); return $color; }
Яркость каждого из трёх основных цветов закодирована числом от 0 до 255. Т.е. 256 ( с учетом 0). Делим на 2 и всё что больше 128 по яркости - это 1, иначе 0 черный.