У меня есть два изображения (первая и вторая ссылка).
Третье изображение было создано imagick, по коду:
$image1 = new \imagick(dirname(dirname(dirname(__DIR__))) . "/1.jpg");
$image2 = new \imagick(dirname(dirname(dirname(__DIR__))) . "/2.jpg");
$result = $image1->compareImages($image2, \Imagick::METRIC_MEANSQUAREERROR);
$result[0]->setImageFormat("jpg");
header("Content-Type: image/jpeg");
echo $result[0];
exit();
Могу я указать изменения по-другому? Например, различия отмечены красной рамкой.
Это на самом деле нетривиально :-) Есть пара проблем, во-первых, вам нужно определить различия - вы можете сделать это путем различия (-compose difference
). Затем вам нужно установить пороговые различия в зависимости от того, насколько они отличаются друг от друга, но поскольку вы используете JPEG, который является потерянным, на каждом пикселе есть различия в кодировании конца квантования. Как только у вас есть различия, вам нужно очертить их, но если вы нарисуете их наивно, вы получите квадрат вокруг каждого пикселя, который будет отличаться от одного прямоугольника вокруг каждой фигуры, поэтому вам нужно сделать некоторые размытия и пороговые значения (или что-то еще иначе) объединить соседние различия в отдельные куски. После того, как вы нашли куски, вам нужно поместить вокруг них фрейм - вы можете либо сделать "Анализ связанных компонентов", либо еще что-то, чтобы найти края комков - я выбрал "Морфологию края". Затем вам нужно покрасить края и собрать их обратно поверх исходного изображения. Команда выглядит так в командной строке:
convert a.jpg \
\( +clone b.jpg -compose difference -composite \
-threshold 1% -separate -evaluate-sequence Add \
-blur 0x5 -threshold 10% \
-morphology edgeout diamond:3 \
-fill red -opaque white -transparent black -write mask.png \) \
-compose srcover -composite result.png
Разумеется, это будет выглядеть по-разному в зависимости от того, на каком из двух исходных изображений вы накладываете контуры: я выбрал композицию на первый, но вы можете выбрать вторую.
Я написал маску в файл mask.png
чтобы вы могли видеть, что я на самом деле mask.png
в круглых скобках, и наложил вокруг нее границу, чтобы вы могли видеть ее ниже:
Вот еще один вариант для экспериментов - трудно понять, что будет лучше всего работать со всеми вашими изображениями :-)
convert a.jpg \
\( +clone b.jpg -compose difference -composite -threshold 1% \
-statistic maximum 25x25 \
-morphology edgeout diamond:5 \
-fill red -opaque white -transparent black -write mask.png \
\) -compose srcover -composite result.png
25x25
дорого.
Этот ответ аналогичен приведенному выше, за исключением того, что он реализован в PHP.
Кроме того, если вы собираетесь сделать что-то подобное, представьте разное изображение как анимацию. Либо Gif, либо используя javascript для обмена изображениями. Наличие отмеченных регионов может стать намного проще для пользователей.
Кроме того, время обработки можно немного ускорить, выполнив два меньших сравнения: один вертикальный и один горизонтальный по сравнению с одним большим сравнением.
$image1 = new Imagick(__DIR__."/compare1.jpg");
$image2 = new Imagick(__DIR__."/compare2.jpg");
$image1->compositeImage($image2, \Imagick::COMPOSITE_DIFFERENCE, 0, 0);
$overlay = clone $image1;
$overlay->negateImage(false);
$overlay->setImageAlphaChannel(\Imagick::ALPHACHANNEL_DEACTIVATE);
$overlay->transformImageColorSpace(\Imagick::COLORSPACE_GRAY);
// Doing one big compare is slow
//$overlay->statisticImage(\Imagick::STATISTIC_MINIMUM, 20, 20);
// Doing a horizontal and vertical compare is faster
$overlay->statisticImage(\Imagick::STATISTIC_MINIMUM, 20, 2);
$overlay->statisticImage(\Imagick::STATISTIC_MINIMUM, 2, 20);
$overlay->statisticImage(\Imagick::STATISTIC_GRADIENT, 4, 4);
$red = new Imagick();
$red->newPseudoImage(
$overlay->getImageWidth(),
$overlay->getImageHeight(),
'xc:red'
);
$red->compositeImage($overlay, \Imagick::COMPOSITE_COPYOPACITY, 0, 0);
$withOutline = clone $image2;
$withOutline->compositeImage($red, \Imagick::COMPOSITE_ATOP, 0, 0);
$outputGif = new Imagick();
$outputGif->addImage($image2);
$outputGif->addImage($withOutline);
$outputGif = $outputGif->deconstructImages();
$outputGif->setImageFormat('gif');
header("Content-Type: image/gif");
echo $outputGif->getImagesBlob();
Поскольку вы можете видеть, что обнаружение мигания значительно облегчает просмотр: