Время прочтения: 5 мин.

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

Полный код, модули, а также вспомогательные материалы можно найти на github странице.

Итак, постановка задачи.

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

            Решение задачи строится в два этапа:

  1. определить область на видео, расположение конкретного рабочего места;
  2. проанализировать видео и записать в файл количество людей через заданный интервал времени на выделенной области.

С учетом постановки задачи стоит отметить два нюанса:

Во-первых, для полноты анализа видео в кадре необходимо распознать время и дату, чтобы можно было записывать в файл количество людей в конкретное время. Однако для этого понадобится дополнительная нейронная сеть по распознаванию цифр на картинке (или 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, мы нашли решение поставленной задачи по подсчету количества людей.