Несколько дней назад, просматривая хакерские новости, я был впечатлен этим проектом, созданным Джейсоном Мэйсом, инженером Google. С того момента, как я впервые увидел этот проект, я решил (по крайней мере, попытаться) повторить его. Так как моим инструментом для работы в основном являются Python, было принято решение все делать с помощью него. Итак, приступим:

Что понадобится:


Python 3.x.x (я использую Python 3.7.4)
OpenCV (я использую версию 4.1.2)

Разбивка различных этапов, описанных в этом проекте.
Разбивка различных этапов, описанных в этом проекте.

Мозговой штурм:

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

Вторая проблема, которую необходимо решить, — это найти способ обнаружить интересующий меня объект, который я хочу удалить. К счастью, с OpenCV есть простой способ: детектор гистограммы ориентированных градиентов, основанный на машине опорных векторов. Это самый быстрый, не самый точный и не самый лучший детектор, но он просто работает.

Рабочий процесс:

Поэтому после мозгового штурма я решил придерживаться следующего рабочего процесса:

  • Создавать HOGDescriptor
  • Получить первый кадр видео для использования в качестве маски
  • Выполните итерацию по каждому кадру и для каждого обнаруженного человека замените область на соответствующие «пустые» из первого кадра
  • Сохранить вывод

Собственно, сам код:

Следуя ранее описанному рабочему процессу,был написан код, который размещен в репозитории GitHub.

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

После тестирования этого кода я понял, что могу быть на правильном пути, однако обнаружение не является достаточно точным, и весь вывод выглядит глючным и нестабильным.
Поэтому я понял, что мне нужно найти способ улучшить его: замена каждого обнаруженного человека первым кадром кажется хорошим подходом, поэтому мне, вероятно, нужно найти лучший способ обнаружения объектов, лучшую модель!
Я вспомнил, как некоторое время назад написал краткое руководство о том, как начать работу с моделью Detectron2 в Facebook, так почему бы не реализовать ее вместо детектора HOG?

Улучшаем результат!

При поиске в модели COC ZOO я нашел модель сегментации экземпляра с 0,07 секундами на каждое время вывода изображения, которая является одной из самых быстрых из доступных (вероятно, не самой точной). Я тогда решил использовать это.
Чтобы подключить пользовательскую модель внутри моего конвейера, необходимо установить все необходимые зависимости, такие как pytorch, torchvision и deteron2:

# install dependencies:
!pip install -U torch==1.4+cu100 torchvision==0.5+cu100 -f https://download.pytorch.org/whl/torch_stable.html
!pip install cython pyyaml==5.1
!pip install -U ‘git+https://github.com/cocodataset/cocoapi.git#subdirectory=PythonAPI'
import torch, torchvision

Следующий код и инструкции проверены на экземплярах Google Colab, этот выбор сделан для того, чтобы облегчить копирование этого эксперимента без борьбы с отсутствующими зависимостями, конфликтами версий и всеми скучными вещами, которые часто случаются.
Затем нам нужно установить Detectron2:

# install detectron2:
!git clone https://github.com/facebookresearch/detectron2 detectron2_repo
!pip install -e detectron2_repo

Теперь мы можем импортировать все необходимые библиотеки и загрузить модель (полный код см. В блокноте Google Colab или в репозитории GitHub):

cfg = get_cfg()
cfg.merge_from_file(model_zoo.get_config_file(“COCO-InstanceSegmentation/mask_rcnn_R_50_DC5_1x.yaml”))
cfg.MODEL.ROI_HEADS.SCORE_THRESH_TEST = 0.5 # set threshold for this model
cfg.MODEL.WEIGHTS = model_zoo.get_checkpoint_url(“COCO-InstanceSegmentation/mask_rcnn_R_50_DC5_1x.yaml”)
predictor = DefaultPredictor(cfg)

Невозможно использовать наш предиктор для вывода классов, предиктор возвращает массив на Tensors, который необходимо преобразовать в массив numpy, а затем можно выполнить итерацию по нему так же, как я делал раньше:

outputs = predictor(frame)
outputs = outputs[“instances”].pred_boxes
.to(‘cpu’)
.tensor
.numpy()
.astype(int)

Посмотрим на финальный результат:

Из рисунка можно наблюдать, как Detectron2 обнаруживает человека с гораздо большей точностью, однако нужно сказать, что, конечно, для этого требуются более «глубокие» конфигурации (зависимости иногда являются проблемой). Однако окончательные результаты говорят сами за себя!

Несколько заключительных соображений:

Несмотря на то, что конечный результат довольно удивителен, всегда есть место для улучшения. Внимательно посмотрев на лыжника позади меня, можно увидеть, что когда я прохожу перед ними, маска заставляет себя исчезнуть (это явление называется окклюзией). Более того, интерполяция между «обрезанным» прямоугольником над текущим кадром достаточно заметна. Чтобы решить обе проблемы, может помочь модель, способная выполнять паноптическую сегментацию.