imagick / php - проверить различия между картинками и определение изменений

1

У меня есть два изображения (первая и вторая ссылка).

Первое изображение

Второе изображение

Третье изображение

Третье изображение было создано 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();

Могу я указать изменения по-другому? Например, различия отмечены красной рамкой.

  • 0
    А? Различия уже красные.
  • 0
    Только красная рамка :) @edit: и изображение со 100% непрозрачностью.
Теги:
image
compare
imagick

2 ответа

2
Лучший ответ

Это на самом деле нетривиально :-) Есть пара проблем, во-первых, вам нужно определить различия - вы можете сделать это путем различия (-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

Изображение 174551

Разумеется, это будет выглядеть по-разному в зависимости от того, на каком из двух исходных изображений вы накладываете контуры: я выбрал композицию на первый, но вы можете выбрать вторую.

Я написал маску в файл mask.png чтобы вы могли видеть, что я на самом деле mask.png в круглых скобках, и наложил вокруг нее границу, чтобы вы могли видеть ее ниже:

Изображение 174551

Вот еще один вариант для экспериментов - трудно понять, что будет лучше всего работать со всеми вашими изображениями :-)

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
  • 0
    Это очень хорошее решение. Это работает так, как я хотел. Но это занимает много времени и кушает ресурсы процессора. Можно ли сделать это более оптимально?
  • 0
    Вы можете попытаться уменьшить размер вдвое или на четверть от первоначального размера, чтобы сделать маску, а затем увеличить ее. 25x25 дорого.
Показать ещё 2 комментария
1

Этот ответ аналогичен приведенному выше, за исключением того, что он реализован в 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();

Поскольку вы можете видеть, что обнаружение мигания значительно облегчает просмотр:

Изображение 174551

  • 0
    Сладкий :-) Голосуй!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню