Статья Удаление фона на изображениях с помощью Python

Давайте немного затронем тему удаления фона у фотографий. К примеру, у вас есть фото, в качестве фона на котором неприглядная стена. И желательно бы эту стену удалить. Решение напрашивается довольно простое и очевидное – воспользоваться онлайн-сервисами для этих целей. Но такое решение оправданно в случае, когда вам нужно удалить фон у нескольких картинок. Но, что делать, если этих картинок тысячи? В этом случае использование онлайн-сервиса уже далеко не самое лучшее решение. Тем более что у каждого такого сервиса, в его бесплатном варианте, есть масса ограничений.

0000.jpg

Для кого может понадобиться подобное действо? Для примера, у вас есть много фотографий одежды, которую нужно выставить на продажу. Но вот фона подходящего для фото не нашлось. И теперь вся эта одежда имеет в качестве фона шкафы или еще хуже – серые страшненькие стены. И фотографий этих очень много. А удалить фон нужно было еще вчера, потому как уже сегодня их нужно разместить на маркетплейсе для продажи… В принципе, одежду на продажу можно выставить и так, с фоном. Особо не заморачиваясь. Но считается, что наличие фона на фото отвлекает человека от самой вещи. Не позволяет ему на ней сконцентрироваться. А значит, высока вероятность того, что он пройдет мимо нее и не купит. Таким образом, фото без фона повышают конверсию с сайта. В данном случае продажи.

Ну, или у вас есть фотографии монет, которые сфотографированы на столе. И стол этот в качестве фона не особо-то подходит, так как монета на нем просто теряется. А других фото у вас нет. И надо работать с тем, что есть.

Примеров может быть множество. Но проблема у всех этих случаев одна – нужно удалить фон. И решение есть, причем, реализовано оно так, что с написанием кода может справиться даже школьник. Достаточно следовать примерам, которые есть на странице разработчика. Так о чем же идет речь? А речь идет о специализированной библиотеке для Python.


Что понадобиться?

А понадобиться установить библиотеку rembg. Устанавливается она так же просто, как и остальные модули:

pip install rembg

Но, тут есть несколько нюансов, с которыми я столкнулся при установке и которыми хочу поделиться с вами. Для начала, эта библиотека работает с Python 3.9. Поэтому, если у вас установлен python более свежей версии, вам нужно сходить на сайт (в случае, если вы работаете в Windows, в Linux python версии 3.9) и скачать оттуда установочный файл версии 3.9. Установить его в систему и при создании нового проекта выбрать как используемый в нем по умолчанию.

Второй нюанс заключается в том, что нужно будет включить исполнение PowerShell скриптов. По крайней мере, у меня терминал несколько раз ругнулся на то, что запуск скриптов отключен. Потому мне пришлось его включить и все заработало.


Включаем исполнение PowerShell скриптов

Для его включения жмем комбинацию клавиш «Win+R» и пишем команду gpedit.msc, после чего нажимаем Enter. В открывшемся «Редакторе групповой политики» идем по пути «Конфигурация компьютера -> Административные шаблоны -> Компоненты Windows -> Windows PowerShell». В правой панели ищите политику «Включить выполнение сценариев» и щелкайте на ней для изменения параметров.

screenshot1.png

В открывшемся окне ставите выключатель в положение «Включено» и ниже выбираете пункт из выпадающего списка: «Разрешить локальные сценарии и удаленные подписанные сценарии», после чего жмете кнопку «ОК».

screenshot2.png

А теперь давайте продолжим. Следует еще предупредить, что данная библиотека весит довольно много, а потому, будет скачиваться некоторое время, которое определит скорость вашего сетевого подключения. К примеру, у меня папка проекта после установки библиотеки стала весить 1.11 Гб. Да и при первоначальном запуске она еще что-то стремится докачать. Но, это в первый раз. При следующих запусках она будет просто работать.

Импортируем необходимые библиотеки:

Python:
import os

from rembg import remove
from PIL import Image

На самом деле я еще хотел использовать threading, чтобы обрабатывать изображения в различных потоках. Но, немного потестировав код с потоками пришел к выводу, что в данном случае использование потоков не оправдано. Так как задача по удалению фона с картинки все же довольно ресурсоёмкая, в каждом потоке достаточно сильно нагружается процессор и кушается очень много оперативной памяти.

Вот загрузка процессора во время выполнения кода с использованием потоков:

screenshot4.png

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

screenshot5.png


Функция удаления фона

Давайте теперь создадим функцию, которая, по сути, и будет основной для данного кода. В этой функции мы будем загружать картинку, и удалять фон. Назову ее remove_bg(place). На вход данная функция пользовательский ввод пути, по которому расположены картинки для удаления фона. Затем проверяется наличие директории для сохранения картинок. Если такой директории нет, она создается. Запускается цикл, в котором сканируется полученная директория. Затем проверяется расширение файла. И, если оно соответствует картинке, запускается загрузка файла картинки и удаление фона. После чего, обработанная картинка сохраняется в созданную ранее папку для картинок без фона. Если же расширение файла не соответствует картинке, данный файл пропускается и цикл продолжает работу уже со следующим элементом.

Python:
def remove_bg(place):
    if not os.path.isdir('images_without_bg'):
        os.mkdir('images_without_bg')
    for pict in os.listdir(place):
        if pict.endswith('.png') or pict.endswith('.jpg') or pict.endswith('.jpeg'):
            print(f'[+] Удаляю фон: "{pict}"...')
            output = remove(Image.open(os.path.join(place, pict)))
            output.save(os.path.join('images_without_bg', f'{pict.split(".")[0]}.png'))
        else:
            continue


Проверка правильности пользовательского ввода

Для того, чтобы скрипт не падал с ошибкой от неправильно введенного пути к папке с изображениями, я добавил функцию проверки наличия папки по данному пути get_target_path(). И если папка не будет найдена, скрипт до посинения пользователя будет спрашивать правильность ввода. Ну, а когда папка указана верно, он выводит сообщение, что работает с введенной папкой и возвращает значение пользовательского ввода.

Python:
def get_target_path():
    while not os.path.isdir(user_input := input("[+] Введите путь к папке с изображениями: ")):
        print(f'Папка "{user_input}" не найдена\n')
    print(f"\nРаботаем с папкой {user_input}\n")
    return user_input

И последняя функция, из которой, собственно и стартует программа, это функция main(). Тут вызывается функция удаления фона, в которой, в качестве аргумента пути вызывается функция проверки пользовательского ввода и возвращенное значение передается дальше. Ну и после того, как скрипт отработает, выводиться сообщение о том, что удаление фона завершено.

Python:
def main():
    remove_bg(get_target_path())
    print('\n[+] Удаление фона изображений завершено!')

Для тестирования данного скрипта я просто скачал несколько изображений из интернета. Вот они, в папке для обработки:

screenshot3.png

После того, как скрипт отработал и были сохранены изображения без фона, я свел некоторые из них в одну картинку для того, чтобы показать, как данная библиотека работает. На самом деле, для удаления фона с фотографий одежды или других вещей подойдет идеально. Даже если будут какие-то принципиальные огрехи, их можно поправить руками. Ну, а если отработает не совсем корректно, все же, это не сотни фото. И тут уже можно будет поработать руками.

000.jpg

Что же, на этой оптимистической ноте данную статью можно завершить.

Python:
import os

from rembg import remove
from PIL import Image


def remove_bg(place):
    if not os.path.isdir('images_without_bg'):
        os.mkdir('images_without_bg')
    for pict in os.listdir(place):
        if pict.endswith('.png') or pict.endswith('.jpg') or pict.endswith('.jpeg'):
            print(f'[+] Удаляю фон: "{pict}"...')
            output = remove(Image.open(os.path.join(place, pict)))
            output.save(os.path.join('images_without_bg', f'{pict.split(".")[0]}.png'))
        else:
            continue


def get_target_path():
    while not os.path.isdir(user_input := input("[+] Введите путь к папке с изображениями: ")):
        print(f'Папка "{user_input}" не найдена\n')
    print(f"\nРаботаем с папкой {user_input}\n")
    return user_input


def main():
    remove_bg(get_target_path())
    print('\n[+] Удаление завершено!')


if __name__ == "__main__":
    main()

Таким образом, в статье, надеюсь, было показано, как можно удалить фон с множества фото с помощью Python и специализированной библиотеки. При этом, код скрипта не является сложным для понимания новичками, как это обычно бывает при использовании некоторых библиотек с машинным обучением.

Спасибо за внимание. Надеюсь, что данная информация будет для вас полезна
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!