Как заменить однородный фон прозрачным с помощью Imagemagick

    Бывает, что на сайт загружаются картинки с однородным фоном и возникает потребность в автоматической замене его (фона) на прозрачный.

    Часто такая фича нужна для фотографий товаров в интернет-магазине, картинок, которые накладываются на корпоративный фон и других фоток, не портящих дизайн сайта. Вырезать каждую фотку вручную фотошопом довольно грустно, но есть php-методы, с помощью которых это можно «поставить на поток».
    image

    Как это работает


    Функция попиксельно ищет где заканчивается однородный цвет. После того, как все координаты вычислены — функция просто вырезает все, что находится снаружи.

    Замена белого фона прозрачным возможна только если выходная картинка сохранена в формате PNG или GIF. Подойдут и новые форматы WebP и BPG с поддержкой прозрачности.

    image

    Перед удалением фона всегда лучше ресайзить большую картинку. Если сделать это после — границы могут исказиться.

    Замена фона, пример на bash


    Для удаления фона в ImageMagick есть оператор -trim. Он обрезает картинку по заданному цвету:

    convert image.jpg -quality 100 image.png
    convert image.png -fuzz 20% -fill white -draw "color 5,5 floodfill" -quality 100 image.png
    convert image.png -transparent white image.png
    convert image.png -define convolve:scale="100!,100%" -morphology Convolve "Log:0x2" image.png
    

    Перед обрезкой стандартный JPEG конвертируется в PNG. В lossy JPEG’е фон не будет однородным. Соседние пиксели обычно незначительно отличаются по цвету. Например: белый, светло-серый, светло-голубой. Аргумент fuzz устанавливается в значение >0, чтобы разрешить функции считать соседние цвета одинаковыми.

    Замена фона, пример на PHP


    Пример обрезки белого фона на картинке (входной файл: image.jpg, выходной — trimmed.png):

    <?php
    $image = new Imagick('image.jpg');
    $type=pathinfo('image.jpg', PATHINFO_EXTENSION);
    if($type=='jpg')
    {
      $image->setImageFormat('png');
    }
    $image->borderImage('#ffffff',1, 1);
    $image->trimImage(0);
    $image->setImagePage(0, 0, 0, 0);
    $image->writeImage('trimmed.png');
    ?>
    

    Оператор borderImage рисует вокруг картинки рамку 1х1 в цвет фона, после чего оператор trimImage обрезает ее вместе с рамкой.

    image

    Внимание! Оператор trimImage работает, если Imagick скомпилирован с ImageMagick версии не ниже 6.2.9.

    Как сделать фон однородным


    Похожим способом можно заменить неоднородный фон на однородный при конвертации из JPEG в PNG:

    convert image.jpg -fill none -fuzz 1% -draw 'matte 0,0 floodfill' -flop  -draw 'matte 0,0 floodfill' -flop image.png
    

    В этом примере — каждый пиксель фона зальется одним цветом — пикселя с координатами (0;0).

    image

    Много примеров работы кода


    Как работает обрезка фона с помощью библиотеки Imagick можно проверить тут. Онлайн-инструмент заменяет любой однородный фон на прозрачный, как с этим яблочком. Вот пример с черным фоном и сложными формами для трима (волосы). Конечно, может оставаться небольшая белая рамка. Но выглядит довольно прилично. Даже кошачьи усы вырезает на ура.

    Конспект


    1. Для удаления однотонного фона с картинки можно использовать оператор
      -trim или команду trimImage.
    2. Проверить как работает удаление фона с помощью Imagick можно тут.
    3. Выходную картинку нужно сохранить в любом из форматов с поддержкой прозрачности: PNG, GIF, WebP, BPG.
    • +18
    • 21,1k
    • 9
    .io 38,71
    Компания
    Поделиться публикацией
    Похожие публикации
    Комментарии 9
    • 0
      moccachin у вас habr-эффект или это мой провайдер не хочет открывать картинки на 88 порту?
      > GET http://178.62.80.227:88/acd36c9dc316a2c01784b7f4d1a86506.jpg
    • +4
      Вот у нас как раз подобная проблема стояла, интернет магазин ювелирки, завод даёт крайне корявые фото на простынях, на бархате, на бумажках и т.д (тут много примеров www.ohmygold.ru/catalog/sergi/serga_odinochnaya.html) с почти однородным фоном. Пытался решать, как и Вы, с помощью ImageMagick, в итоге ничего адекватного не получилось. Решили, что вариант нежизнеспособен в случае с реальными фотографими. Попробовал прогнать через ваше решение — аналогично, ничего дельного. Для каких конкретных задач вы используете это добро?
      • +2
        Скорее всего не для случая, когда поставщик идиот, а для случая когда он понимает что делает. Это вроде как новая реализация технологии, которой не одно десятилетие и которая себя отлично зарекомендовала — но для случаев «съёмки на тапок», конечно.
      • +1
        Как и ожидалось, работает так себе.
        Та же ситуация и с автоудалением watermark'ов — в целом да, но качество так себе.
        • +6
          Нужно не просто порог fuzz выкрутить, но ещё и как-то наловчиться делать граничные пикселы полупрозрачными.
          • 0
            дело в том что если граничный пиксель был на картинке с синим фоном например, а вы хотите картинку положить на белый, то этот пиксель уже имеет примесь синего, которая никуда не денется от того что он станет прозрачным, т. е. нужно его перекрасить в цвет самого объекта, который хотим оставить на картинке, автоматические такое не сделать наверное
            • 0
              Во-первых, самый грубый способ — это вычесть цвет фона, заменив его значение на альфу.
              Во-вторых, интерполировать с окружающими пикселами по ту и другую сторону границы.

              В-третьих, размазать маску альфа-канала, создав ореол. Кстати, на сайте imagemagick'а об этом говорится, так что даже ничего велосипедить не потребуется.
              После протравливания синего фона и наложения на белый — ну да, будет голубоватый ореол. Но не будет жутких ступенек.
          • 0
            Обновляли что-то? Вчера пробовал — все криво обрезалось и оставалась рамка примерно в 5 пикселей
            Сегодня отлично обрабатывает те же картинки

            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

            Самое читаемое