Время прочтения: 5 мин.
Сегодня на своем опыте мы покажем, как решить задачу по подсчету количества людей (и не только) на видео при помощи предобученной нейронной сети и инструмента по разметке данных в языке программирования Python.
Полный код, модули, а также вспомогательные материалы можно найти на github странице.
Итак, постановка задачи.
Предположим у нас имеется набор видеофайлов с видеорегистраторов, установленных в зале обслуживания клиентов или в производственном помещении. Как пример, мы рассмотрим видеофайлы с одного видеорегистратора, который охватывает область с несколькими рабочими местами. Нам необходимо подсчитать количество людей на видео для конкретного рабочего места.
Решение задачи строится в два этапа:
- определить область на видео, расположение конкретного рабочего места;
- проанализировать видео и записать в файл количество людей через заданный интервал времени на выделенной области.
С учетом постановки задачи стоит отметить два нюанса:
Во-первых, для полноты анализа видео в кадре необходимо распознать время и дату, чтобы можно было записывать в файл количество людей в конкретное время. Однако для этого понадобится дополнительная нейронная сеть по распознаванию цифр на картинке (или pytesseract, зависит от качества видео, расположения и шрифта временной метки в кадре), что выходит за рамки данной статьи.
Во-вторых, в большинстве случаев на видео с видеорегистраторов отсутствует или не соответствует действительности информация о частоте кадров, что напрямую влияет на процесс определения текущего времени для обрабатываемого кадра. Таким образом, примем по умолчанию, что видео у нас с частотой 17 кадров в секунду (зачастую видео с видеорегистраторов имеет частоту в диапазоне 10 — 25 кадр/сек), а интервал будет составлять 5 секунд.
Для начала импортируем необходимые библиотеки и модули:
import cv2
import numpy as np
import os
import re
import subprocess
from functions import *
Далее необходимо указать полный путь до расположения видео для обработки, а также директории Temp, в которой располагаются вспомогательные инструменты:
path_to_video = 'Full/path/to/folder/with/videos/'
temp_folder = "Full/path/to/folder/Temp/"
img = temp_folder + "Coordinates.jpg"
predefined_class = temp_folder + "predefined_classes.txt"
Переменные img и predefined_class характеризуют расположение вспомогательных материалов, которые располагаются в папке Temp. На следующем этапе необходимо определить рабочую область на видео для подсчета людей в кадре:
file_name = os.listdir(path_to_video)[0]
get_img_for_coord(path_to_video, file_name, temp_folder)
subprocess.check_call(['python',
'labelImg.py',
img,
predefined_class,
temp_folder], cwd = temp_folder, shell=True)
Переменная file_name содержит в себе имя первого видео в папке, до которой раннее мы указали путь с помощью переменной path_to_video. Т.к. видео с одного видеорегистратора расположены в отдельной папке, рабочую область находим один раз, для каждой из папок. Далее происходит вызов функции get_img_for_coord, на вход функции подаются переменные, которые мы раннее определили. Данная функция сохраняет кадр из видео как .jpg изображение, с именем «Coordinates.jpg». При помощи библиотеки subprocess вызывается модуль labelImg, с помощью которого выделим рабочую область на изображении.
На рисунке желтым цветом обозначен порядок выполнения действий для выделения рабочей области (обозначена зеленым цветом). После закрытия окна программы labelImg, в папку Tempсохраняется .xml файл, в котором содержатся координаты выделенной области. Для извлечения необходимой информации, а именно (xmin, ymin, xmax, ymax) из .xml файла, воспользуемся функцией get_x_y_from_xml. Использование данной функции предполагает наличие только одной рабочей области:
coordinates = tuple(get_x_y_from_xml(temp_folder))
Для примера будем использовать предобученную нейронную сеть архитектуры yolov3-spp, т.к. она обладает хорошей точностью и «относительно высокой скоростью для такой точности» (скорость зависит от мощности устройства, на котором будет производится запуск алгоритма). Подбор архитектуры зависит от типа обрабатываемого видео, если оно высокого разрешения, а силуэт людей хорошо различается, то смело можно использовать нейронную сеть архитектуры yolov3-tiny, которая обладает приемлемой точностью и высокой скоростью обработки (в 10 раз выше, чем у yolov3-spp). Более подробно о характеристиках архитектур можно почитать по ссылке.
Далее переходим непосредственно к обработке видео. В первую очередь необходимо подгрузить веса ‘yolov3-spp.weights’ и конфигурационный файл ‘yolov3-spp.cfg’ нейронной сети, которые располагаются в папке Temp:
net, outputlayers = load_pretrained_model(temp_folder,
'yolov3-spp.weights',
'yolov3-spp.cfg')
Получим список имен всех видео, которые расположены в директории path_to_video:
videos_names = os.listdir(path_to_video)
Наконец, в цикле для каждого видео запускаем алгоритм по подсчету людей в заданной области, ограниченной значениями coordinates в кадре:
interval = 5
for video in videos_names:
l_temp = processing_video(path_to_video,
video,
interval,
net,
outputlayers,
coordinates)
В итоге на вход подаем полноразмерное видео, в котором впоследствии выделяется область и производится подсчет людей:
Результат обработки файлов будет записываться в текстовый документ в следующем виде:
FILENAME<--->TIME<--->COUNT_PEOPLE
video.avi<--->5sec:<--->2
video.avi<--->10sec:<--->1
video.avi<--->15sec:<--->3
video_2.avi<--->5sec:<--->1
video_2.avi<--->10sec:<--->2
video_2.avi<--->15sec:<--->5
Помимо людей, в кадре можно вести подсчет других объектов, yolov3 способна различать 80 различных классов объектов, такие как: автомобили, электроника, животные и многое другое. Полный список классов можно посмотреть по ссылке.
Таким образом, благодаря возможностям предобученной нейронной сети, а также инструментам opencv, labelImg в Python, мы нашли решение поставленной задачи по подсчету количества людей.