Разработка сетевого сервиса автоматического трекинга человека PTZ IP видеокамерой с использованием TensorFlow

Характеристика разработки алгоритма для связи потоков обработки кадра и управления камерой. Обеспечение стабильности трекинга на протяжении длительного времени. Основные методы компьютерного зрения. Особенность обнаружения объектов на изображении.

Рубрика Программирование, компьютеры и кибернетика
Вид дипломная работа
Язык русский
Дата добавления 28.10.2019
Размер файла 1,1 M

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.

Размещено на http://www.allbest.ru/

Федеральное государственное автономное образовательное учреждение высшего образования

«Национальный исследовательский университет

«Высшая школа экономики»

Московский институт электроники и математики им. А.Н. Тихонова Национального исследовательского университета «Высшая школа экономики»

Выпускная квалификационная работа

На тему: «Разработка сетевого сервиса автоматического трекинга человека PTZ IP видеокамерой с использованием TensorFlow»

Выполнил

Барышников Илья Алексеевич

Научный руководитель:

Д.А. Королев

Москва 2019

Аннотация

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

Выпускная квалификационная работа состоит из 59 страниц, содержит 10 рисунка, 1таблицу, 14 листингов и 5 приложений.

Ключевые слова: компьютерное зрение; нейронные сети; автоматический трекинг человека; автоматизированная съемка; TensorFlow.

With the development of online learning resources, many institutions are thinking about the possibility of introducing lecture notes. It is also planned to introduce a survey of students during the delivery of term papers and dissertations for the compilation of an automatic portfolio. To date, such surveys are conducted on stationary cameras or attract mobile video studios. The purpose of this work is to recreate the camera work without human intervention. To solve this problem, existing approaches to tracking people and turnkey solutions for automated research were considered. For work were selected IP security cameras with motion function and TensorFlow library. The paper consists of 59 pages, contains 10 figures, 1 table, 14 listings and 5 applications.

Keywords: computer vision; neural networks; automatic human tracking; automated survey; TensorFlow.

Оглавление

Введение

1. Существующие подходы

1.1 Нейронные сети

1.2 Наборы данных

1.3 Выводы

2. Разработка

2.1 Используемые технологии и методы

2.2 Ход работы

2.3 Отказоустойчивость

Выводы

Список используемых источников

Приложение

Введение

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

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

На рынке представлено несколько реализаций автоматического трекинга человека. В охранных камерах есть встроенный модуль трекинга, однако он хорошо подходит для охранных целей, где совершенно не важна плавность движения камеры или компоновка кадра. Следовательно, данный модуль совершенно не подходит для проведения видеосъемки выступлений. Мною было найдено всего несколько моделей камер, созданных специально для проведения съемки с использованием модуля автоматического трекинга. Цены на такие камеры начинаются от 1000 долларов.

PTZ-камеры охранного типа, поддерживающие удаленное управление по различным протоколам, могут выдавать хорошее качество картинки при стоимости в 100 - 200 долларов.

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

1. Анализ существующих подходов в поиске объектов в кадре.

2. Поиск тела и лица человека в кадре.

3. Разработка алгоритма для связи потоков обработки кадра и управления камерой.

4. Обеспечение стабильности трекинга на протяжении длительного времени.

Объектом исследования является проведение съемки без участия оператора. Исследование направлено на изучение и анализ обработки изображения посредством нейронных сетей.

Методы Исследования. Проведенные в работе исследования и разработки базируются на использовании:

• методов модульного и объектно-ориентированного программирования;

• знаний в области нейронных сетей;

• методов компьютерного зрения;

• правил ведения съемок.

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

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

В рамках работы рассматриваются существующие практики, даже косвенно связанные с целью исследования. Также проводится анализ существующих решений для поиска объектов на изображении. В связи со спецификой работы были введены некоторые ограничения: алгоритм по поиску человека в кадре должен безошибочно работать на 90% изображений, реакция камеры на движение человека должна быть не больше одной секунды, алгоритм должен непрерывно и безошибочно работать в течении 2 часов.

1. Существующие подходы

Для решения вышеуказанных проблем было решено разработать алгоритм для автоматического отслеживания человека в кадре. В качестве камер были выбраны недорогие ip камеры с функцией движения. Данные камеры могут снимать с разрешением 1920Ч1080 (Full HD) и увеличением до 10 раз.

Глобальную задачу можно разделить на две подзадачи. К первой подзадаче можно отнести процесс по поиску человека на каждом кадре непрерывного видеопотока с камеры. Ко второй Ѓ[ поворот камеры в зависимости от положения человека в кадре. Первую подзадачу можно решить с помощью компьютерного зрения, а вторую Ѓ[ используя общий стандарт безопасности для ip камер ONVIF (Open Network Video Interface Forum).

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

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

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

Технологию компьютерного зрения уже внедрили в свою продукцию несколько крупных компаний, к примеру Facebook и Snapchat используют технологию распознавания лиц, чтобы помечать вас на фотографиях или в режиме реального времени накладывать различные фильтры. В поисковиках Yandex и Google существует возможность контентного поиска по изображению. Алгоритм анализирует изображение в запросе и выдает более подходящие результаты. Для выявления подозрительных действий в московском метро также используется компьютерное зрение.

Существует пять основных методов компьютерного зрения:

1) классификация изображений;

2) обнаружение объектов;

3) отслеживание объектов;

4) семантическая сегментация;

5) обнаружение экземпляра.

Классификация изображения - это предсказание категории объекта на новом изображении и измерение точности прогноза. С этой задачей связано множество проблем, таких как изменение точки обзора, изменение масштаба, освещение, фоновый шум и т.д. Чтобы обойти указанные проблемы, был разработан подход, основанный на обучении нейронной сети набором данных с помеченными изображениями. После обучения оцениваются результаты классификатора, на вход подаются совершенно новые изображения, затем сравниваются настоящие метки изображения с предсказанными. Для классификации объектов чаще всего используются сверточные нейронные сети (CNN).

Задача обнаружения объектов на изображении включает в себя выделение всех объектов определенных классов на изображении. В отличии от классификации изображения, в данной задаче классификация и локализация происходят по всем объектам на изображении, что делает невозможным использование CNN. Для обнаружения объектов была разработана R-CNN. В R-CNN входное изображение разбивается на области возможных изображений, после этого для каждой области запускается R-CNN. В последние годы тенденции сместились в сторону новых более быстрых алгоритмов: Faster R-CNN, YOLO, SDD и R-FCN.

Отслеживание объектов заключается в получении начального набора координат для каждого обнаруженного объекта в кадре, создании уникального идентификатора для каждого нового объекта и отслеживании каждого из них. При слежении за объектом его идентификатор остается неизменным, и всегда можно увидеть траекторию движения объекта в кадре. В FCNT (Fully Convolutional Networks Tracker) используется модель VGG, обученная на базе изображений ImageNet. Разработчики установили, что слои сверточной сети на разных уровнях кодируют цель по-разному. Верхний уровень кодирует общие признаки и служит для классификации объекта. Нижний уровень кодирует уникальные признаки и помогает отличать разные объекты с похожим внешним видом.

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

Для стандартизации общения с ip камерами в 2008 году компаниями Bosch, Axis и Sony был разработан стандарт под названием ONVIF. Данный стандарт позволяет взаимодействовать устройствам различных типов и производителей, а также существенно упрощает настройку оборудования и делает возможным простое масштабирование готовой системы устройств.

1.1 Нейронные сети

Существует множество различных подходов к поиску объектов на изображении. Одним из таких подходов являются каскады Хаара. Впервые каскады предложили Виола и Джонс в своей статье «Rapid Object Detection using a Boosted Cascade of Simple Features» [1] в 2001 году. Метод Виола-Джонс основан на машинном обучении, где каскадная функция обучается на множестве положительных и отрицательных изображений. Процесс обучения происходит долго, однако поиск на изображении происходит очень быстро, что дает возможность использовать подход при обработке видео в реальном времени. Для достижения больших скоростей работы были использованы интегральные представления изображений. Это матрица по размерам схожая с исходным изображением, где каждый элемент представляет собой сумму интенсивности пикселей, находящихся левее и выше искомого. Каждый элемент можно рассчитать по формуле:

, (1)

где I(i,j) - яркость пикселя исходного изображения.

В стандартном методе Виолы-Джонса используются прямоугольные признаки (Рисунок 1). Вычисляемые значения таких признаков будут равняться разности суммы значения яркости, закрываемых светлой частью признака, и суммы значения яркости закрываемых темной частью признака.

Рис.1. Признаки Хаара.

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

В статье «Comparative Study of Object Detection Algorithms» [2] приведено сравнение различных алгоритмов обнаружения объектов, использующих сверточные нейронные сети. Модели, требующие больших вычислительных мощностей, достигают наилучшей точности, но их использование невозможно в условиях ограниченных ресурсов. Другие модели являются более быстрыми, однако они не достигают результатов более крупных аналогов. Проведем сравнение трех алгоритмов Faster R-CNN, R-FCN и SSD для поиска наиболее подходящего.

Для решения задачи поиска объекта на изображении алгоритм CNN не подходит, так как его бы пришлось применять к огромному количеству местоположений, что требует большого количества вычислительных мощностей. Для решения этой проблемы был разработан алгоритм региональных сверточных сетей (R-CNN). Алгоритм определяет возможные области, в которых может присутствовать объект и дает около 2000 возможных регионов. Затем запускается CNN для каждого региона, результаты передаются в SVM для классификации региона. Основной проблемой данного алгоритма является долгое обучение и долгая работа.

Fast R-CCN был разработан с целью увеличения скорости предыдущего алгоритма. В данной версии алгоритма изменилась логика работы: теперь извлечение признаков происходит перед поиском регионов. Благодаря этому во время работы запускается только одна CNN. Новый алгоритм показал себя в разы быстрее, чем его предшественник, однако время поиска регионов осталось высоким. Это подтолкнуло к разработке Faster R-CNN: в ней заменен медленный поиск регионов на быструю нейронную сеть предложения регионов RPN. RPN быстро сканирует каждый регион и оценивает необходимость его дальнейшего анализа.

Алгоритм R-FCN во многом повторяет Faster R-CNN: в нем также используется одна сеть CNN и в дальнейшем изображение делится на регионы. После получения возможных регионов алгоритм делит каждый из них на субрегионы и анализирует их сходство с отдельными частями целевых объектов. Если достаточное количество субрегионов подтвердят свою принадлежность к определенному объекту, то весь регион классифицируется как этот объект.

Алгоритм SSD существенно отличается от предыдущих алгоритмов. Если в Faster R-CNN и R-FCN региональные предложения и региональные классификации происходили в два этапа, то в SSD одновременно происходит предсказание класса и ограничивающей рамки. SSD проще, чем другие сети, поскольку он выполняет все вычисления в одной сети. SSD объединяет прогнозы из многочисленных карт характеристик, имеющих различное разрешение, для обработки объектов разных размеров.

В таблице 1 приведены сравнения точности и скорости работы различных алгоритмов. Все расчеты выполнены на GPU, модели обучены на наборе данных COCO. SSD MobileNet показала лучшее время. Faster R-CNN оказалась самой медленной и самой точной.

Таблица 1 Время тестирования на GPU с оценками mAP всех комбинаций.

Модель

mAP

Время, мс

SSD MobileNet

19

40

SSD VGG-16

20.5

130

SSD Resnet-101

26.2

175

SSD Inception Resnet

20.3

80

Faster R-CNN MobileNe

19

118

Faster R-CNN VGG-16

24.9

250

Faster R-CNN Resnet-101

33

396

Faster R-CNN Inception Resnet

34.2

860

R-FCN MobileNet

13.4

75

R-FCN Resnet-101

30.5

386

R-FCN Inception Resnet

30.7

388

1.2 Наборы данных

Точность работы алгоритмов по поиску объектов на изображении напрямую зависит от обучающей выборки. На рынке представлено большое количество различных наборов данных, таких как: ImageNet, SUN, COCO, POSCAL VOC и другие. В таких наборах данных хранятся изображения различных сцен, в которых присутствуют объекты в естественном контексте. Все объекты в обучающей выборке промаркированы.

В статье компании Microsoft «Microsoft COCO: Common Objects in Context» [3] приведено сравнение различных наборов данных. При создании набора данных нужно правильно выбрать категории объектов, что является нетривиальной задачей. Каждая категория должна содержать репрезентативный набор для ее описания. Microsoft при создании COCO провели полномасштабное исследование: они составили список категорий из POSCAL VOC и множества наиболее часто используемых слов. Также детям от 4 и до 8 лет было предложено назвать вещи, которые они чаще всего видят дома или на улице. После этого соавторы ставили оценки каждой категории от 1 до 5, анализируя практическую значимость каждого из классов. Окончательный набор содержал 91 класс.

Следующим шагом идет сбор изображений для каждой категории. Самым простым способом является поиск изображений в Google или Bing, однако изображения, полученные таким образом, будут не репрезентативны. Большинство объектов будут представлены с канонической точки зрения, без зашумленности фона. Поиск изображений по запросу «собака» будет иметь тенденцию выдавать изображение крупных и центрированных собак, для поиска не канонических изображений Microsoft использовала комбинации категорий объектов, таких как «собака + человек».

Маркировка объектов на изображение является самой ресурсоемкой частью работы. При создании COCO были выбраны 11 суперклассов, чтобы работнику требовалось найти животного на изображении, не задумываясь кошка это или собака. После нахождения одного из суперклассов работник помечает найденный объект. Данный этап занял примерно 20 тысяч рабочих часов. В дальнейшем, каждый выделенный суперкласс был классифицирован как один из 91 объекта и по всем была проведена сегментация. Все этапы маркировки заняли более 150 тысяч рабочих часов.

Диаграммы 1-3 показывают сравнительные характеристики четырех различных наборов данных для классификации объектов. В наборах PASCAL VOC и ImageNet представлено более 60% изображений с одним объектом, это значит, что большинство изображений являются каноническими.

1.3 Выводы

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

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

2. Разработка

2.1 Используемые технологии и методы

В качестве языка программирования был выбран язык Python 2.7. Данный язык был выбран по причине качественной работы с фреймворком TensorFlow, наличием библиотек для общения с камерами по протоколу ONVIF, а также хорошей документацией каждого модуля.

Для обучения и запуска моделей используется открытая программная библиотека для машинного обучения TensorFlow.

Набор данных COCO от компании Google был выбран для обучения моделей. Он включает в себя 90 различных объектов, обученных на множестве не эталонных изображений.

Для управления камерами был выбран универсальный протокол ONVIF. С данным протоколом совместимо подавляющее количество IP камер на рынке.

2.2 Ход работы

Общая архитектура программы. Для работы программы создается управляющий поток, в котором запускаются четыре подпотока:

1) WebcamVideoStream (взятие кадра из потока);

2) Tensor (обработка каждого кадра нейронной сетью и локализация объектов на каждом из них);

3) Move (движение камерой за человеком в кадре);

4) Ping (проверка нахождения камеры в сети).

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

Существует два режима работы трекинга. В первом режиме полученное и обработанное изображение выводится на экран, а подпотоке обработки кадра рисуются ограничивающие рамки найденных объектов. Данный режим запуска удобен при отладке движения или при использовании на локальной машине с поддержкой визуального интерфейса. Второй режим работы скрывает от пользователя визуальную составляющую и подходит для запуска на удаленных серверах.

Взятие кадра из потока. Для взятия одного кадра из видеопотока камеры используется функция VideoCapture из пакета OpenCV2. В ходе разработки была выявлена одна проблема данной функции - все кадры записываются в буфер и чтение происходит строго по порядку. Из за времени работы нейронной сети взятие кадра было медленнее появления нового кадра в буфере, в результате чего, наращивалось время отставания получаемого изображения от ожидаемого. Также, со временем буфер переполнялся и программа падала с критической ошибкой.

В результате анализа ошибки был написан класс WebcamVideoStream. При инициализации класса происходит подключение к камере по протоколу rtsp, используя функцию VideoCapture. В класс входят семь методов: __init__, start, update, check_connect, status, read, stop. Конструктор __init__ вызывается при вызове класса из управляющего потока, в нем происходит подключение к rtsp потоку камеры (Листинг 1). Атрибут self.mycam_rtsp берется из конфигурационного файла settings.ini. При неудачном подключении к потоку программа завершается с критической ошибкой, записывая эту ошибку в файл логирования. Также, на почту пользователя приходит письмо с описанием ошибки. Данная ошибка может возникнуть при попытке подключения с использованием переменной self.mycam_rtsp в которой есть ошибка формата. При удачном подключении проверяется открыт ли поток (Листинг 2), если метод self.stream.isOpened() вернет False, то выполнение программы завершится с ошибкой. Данная ошибка может возникнуть, если переменная self.mycam_rtsp не содержит ошибок формата, но присутствует ошибка в ip камеры или камеры нет в сети.

Листинг 1

Подключение к rtsp потоку камеры.

try:

self.stream = cv2.VideoCapture(self.mycam_rtsp)

except:

init_logger.critical("Error with cv2.VideoCapture")

init_logger.exception("Error!")

exc_type, exc_value, exc_traceback = sys.exc_info()

err_msg = str(''.join(traceback.format_exception(exc_type, exc_value, exc_traceback)))

UF.send_msg(msg=err_msg)

sys.exit(0)

Листинг 2

Проверка потока с камеры.

if self.stream.isOpened() is False:

err_msg = "Stream is close"

init_logger.critical(err_msg)

init_logger.info("Check rtsp in settings file")

UF.send_msg(msg=err_msg)

sys.exit(0)

else:

init_logger.info("Process get rtsp stream.")

Метод update() в бесконечном цикле берет кадры из rtsp потока, также, в данном методе рассчитывается время взятия 25 кадров. Если время превышает одну секунду, то разница записывается в файл логирования на уровень debug. Метод start() (Листинг 3)запускает метод update() как параллельный подпроцесс, работающий в фоновом режиме. В строке 6 листинга 3 процесс запускается как демон, данный параметр необходим, чтобы процесс завершился при завершении родительского процесса.

Метод check_connect() служит для проверки состояния rtsp потока, при удачном подключении метод возвращает True, иначе - False.

Листинг 3

Метод start().

def start(self):

self.stopped = False

start_logger = logging.getLogger("Main.%s.start"%(self.name))

start_logger.info("Process starting")

self.t = Thread(target=self.update, name=self.name, args=())

self.t.daemon = True

self.t.start()

return self

Метод read() возвращает текущий кадр, из-за того, что кадры берутся постоянно, то обращаясь к данному методу мы всегда получим актуальный кадр. Метод stop() служит для остановки процесса взятия кадра.

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

Класс Tensor содержит 11 методов: __init__, start, update, set_image, read, read_boxes, read_scores, read_classes, status, get_tps и stop. При инициализации объявляются все используемые переменные и подгружается обученная модель. В листинге 4 определяются пути до обученной модели и до файла, хранящего все id объектов и их названия (строки 1-4). В строках 6-12 создается граф, используя обученную модель. Метод set_image(image) позволяет передать в класс изображение для анализа. По аналогии с классом WebcamVideoStream работает метод start().

Листинг 4

Подгрузка обученной модели и создание графов.

pwd = UF.get_pwd("detection_models")

self.model_name = model_name

PATH_TO_FROZEN_GRAPH = pwd + '/' + self.model_name + '.pb'

PATH_TO_LABELS = pwd + '/mscoco_label_map.pbtxt'

self.detection_graph = tf.Graph()

with self.detection_graph.as_default():

od_graph_def = tf.GraphDef()

with tf.gfile.GFile(PATH_TO_FROZEN_GRAPH, 'rb') as fid:

serialized_graph = fid.read()

od_graph_def.ParseFromString(serialized_graph)

tf.import_graph_def(od_graph_def, name='')

В методе update() запускается бесконечный цикл. В каждой итерации цикла проверяется существование кадра и происходит сравнение с предыдущим обработанным кадром. Если кадр отличается от предыдущего, то запускается анализ изображения (Листинг 5 строки 3-4). Также в методе происходит запись времени выполнения, это время служит для проверки системы на производительность. Эталонное время обработки одного кадра на cpu - менее 0.1 секунды. В листинге 6 представлена часть кода, отвечающая за рисование ограничивающей рамки найденных объектов. Данная часть кода будет запущена если в конфигурационном файле переменной visible будет присвоено значение `Yes'.

В метод visualize_boxes_and_labels_on_image_array() передается изображение, координаты найденных объектов, id найденных объектов, проценты предсказания, массив возможных объектов, флаг координат и толщина линий. Отключение метода визуализации уменьшает время анализа одного кадра.

Метод read() возвращает последний обработанный кадр, при запуске программы метод возвращает None. Read_boxes() возвращает массив координат всех найденных объектов, read_scores() возвращает массив точности предсказания каждого объекта, read_classes возвращает массив id каждого объекта. Все массивы имеют 100 элементов и id человека и id пустых элементов по умолчанию совпадают и равны 1. Для решения этой проблемы все значения предсказаний выше порогового значения (45%) приравниваются единице, после чего матрица, хранящая id объектов, умножается на полученную. В результате получается матрица, где элемент со значением одни - человек.

Листинг 5

Вызов функции анализа изображения.

try:

(self.boxes, self.scores, self.classes, self.num_detections) = sess.run(

[boxes, scores, classes, num_detections],

feed_dict={self.image_tensor: image_np_expanded})

except:

update_logger.critical("Error with run tensor")

update_logger.exception("Error!")

exc_type, exc_value, exc_traceback = sys.exc_info()

err_msg = str(''.join(traceback.format_exception(exc_type, exc_value, exc_traceback)))

UF.send_msg(msg=err_msg)

Листинг 6

Вызов функции визуализации найденных объектов.

if (self.visible == 'Yes'):

vis_util.visualize_boxes_and_labels_on_image_array(

image,

np.squeeze(self.boxes),

np.squeeze(self.classes).astype(np.int32),

np.squeeze(self.scores),

self.category_index,

use_normalized_coordinates=True,

line_thickness=8)

Метод status() возвращает True, если фоновый процесс обработки запущен и False, если фоновый процесс завершился с ошибкой или не был запущен. Get_tps() возвращает количество обработанных кадров в секунду. Метод stop() служит для остановки процесса обработки кадра.

Движение камеры. Для реализации движения камеры был написан класс Move. Данный класс включает 9 методов: __init__, start, update, status, set_box, set_speed_coef, goto_home, get_zoom, stop. В конструкторе происходит подключение к камере по протоколу ONVIF (Листинг 7). В функцию библиотеки python-onvif ONVIFCamera передаются пять параметров: ip камеры, порт, логин, пароль и путь к файлу wsdl. Все параметры, за исключением последнего, записаны в конфигурационном файле. После успешного подключения, создаются новые сервисы (Листинг 8). В программе создаются пять сервисов:

1) ContinuousMove (служит для управления камерой с помощью векторов);

2) GotoHomePosition (служит для перехода к начальной позиции камеры, заданной оператором до съемки или программно при инициализации);

3) SetHomePosition (добавляет возможность програмно установить начальную позицию камеры);

4) GetConfigurationOptions (служит для вывода основных настроек камеры);

5) GetStatus (с помощью данного сервера можно получить значение зума камеры).

Листинг 7

Подключение к камере по протоколу ONVIF.

try:

mycam = ONVIFCamera(self.mycam_ip, self.mycam_port, self.mycam_login, self.mycam_password, self.mycam_wsdl_path)

init_logger.info("Successful conection ONVIFCamera")

except:

err_msg = "Error with conect ONVIFCamera..."

init_logger.critical(err_msg)

init_logger.info("Check the correctness of the entered data in the setings.ini (ip,port,login, password or wsdl_path)")

UF.send_msg(msg=err_msg)

sys.exit(0)

Листинг 8

Создание сервисов.

media = mycam.create_media_service()

profile = media.GetProfiles()[0]

self.ptz = mycam.create_ptz_service()

self.request = {k: self.ptz.create_type(k) for k in ['ContinuousMove', 'GotoHomePosition', 'SetHomePosition','GetConfigurationOptions', 'GetStatus']}

for _, r in self.request.items(): r.ProfileToken = profile._token

В каждой итерации цикла метода update() массив новый массив координат сравнивается с предыдущим, если координаты не меняются, то дальнейший код не выполняется. В другом случае, строятся вектора от найденного человека до целевой позиции (Листинг 9). Целевой позицией является квадрат 80х80, при попадании координат человека в этот квадрат вектора становятся равными нулю. При отдалении человека от целевой позиции значение векторов увеличивается, соответственно скорость камеры тоже увеличивается. Когда человек двигается в малую часть кадра, то вектор скорости увеличивается в 2 раза.

Листинг 9

Построение векторов.

if (to_x < self.length/3 - 40 or to_x > self.length/3 + 40):

if to_x > self.length/3:

vec_x = float(to_x - self.length/3)/(self.length)

else:

vec_x = float(to_x - self.length/3)/(self.length)*2

else:

vec_x = 0

if (to_y < self.hight/5 - 40 or to_y > self.hight/5 + 40):

vec_y = float(self.hight/5 - to_y)/(self.hight)

else:

vec_y = 0

self.count_frame = 0

vec_x = vec_x*self.speed_coef

vec_y = vec_y*self.speed_coefВ первых версиях программы использовалась следующая логика, если есть человек в кадре, то камере передаются вектора движения, если человека нет, то камере передаются нули. При использовании такого подхода, движение камеры получалось прерывистым. Для решения этой проблемы была выбрана другая логика поведения камеры: при потере человека в кадре, камера продолжает свое движение в течении трех секунд (Листинг 10, строки 1-11). Это помогло избавиться от остановок камеры при движении за человеком при его кратковременной потере. Также во время тестирования была найдена проблема с потерей связи с камерой при попытке подключения к ней, используя другие программы. По этой причине, при неудачной отправке векторов, происходит переподключение и повторная отправка векторов (Листинг 10, строки 10-16).

Листинг 10

Продолжение движения и переотправка векторов.

elif box is None and old_box is not None:

self.request['ContinuousMove'].Velocity.PanTilt._x = vec_x

self.request['ContinuousMove'].Velocity.PanTilt._y = vec_y

if (self.count_frame == 30):

self.request['ContinuousMove'].Velocity.PanTilt._x = 0

self.request['ContinuousMove'].Velocity.PanTilt._y = 0

old_box = box

self.count_frame = 0

sleep (0.1)

try:

self.ptz.ContinuousMove(self.request['ContinuousMove'])

except:

update_logger.exception("Error!")

sleep(2)

try:

mycam = ONVIFCamera(self.mycam_ip, self.mycam_port, self.mycam_login, self.mycam_password, self.mycam_wsdl_path)

Метод set_box(box) устанавливает новое значение координат, метод set_speed_coef(coef) устанавливает новое значение коэффициента скорости. Goto_home() - перемещает камеру в исходную позицию, установленную оператором до съемки. Метод get_zoom() возвращает значение зума в интервале от нуля до единицы.

Класс Ping. Для обеспечения стабильности программы был написан класс Ping. Данный класс служит для проверки состояния камеры и имеет пять методов: __init__, start, update, read, stop. Методы start() и stop() работают по аналогии с другими классами. В методе update() (Листинг 11) запускается бесконечный цикл в котором пингуется ip камеры. При передачи пакета устанавливается время, по истечению которого отправка пакет прекращается, а в аргумент self.r записывается ошибка. В случае удачной отправки пакета переменная self.r становится равной нулю. Метод read() возвращает значение аргумента self.r.

Листинг 11

Метод update() класса Ping.

def update(self):

update_logger = logging.getLogger("Main.Ping.start")

update_logger.info("Process started")

while True:

if self.stopped:

return

self.r = os.system("timeout 0.4 ping -c 1 " + self.mycam_ip + " > /dev/null 2>&1")

sleep(1)

Вспомогательные функции. Для оповещения пользователя при возникновении ошибки была написана функция send_msg(msg, subject). В данную функцию передается два аргумента: текст письма и его название. В листинге 12 представлен код функции. В строке 2 из конфигурационного файла берется email пользователя, в строках 4-5 генерируется структура письма. В строке 7 происходит подключение к серверам gmail, при удачном подключении программа авторизируется (строка 13) и отправляется письмо.

Листинг 12

Функция отправки письма пользователю.

def send_msg(msg,SUBJECT="Error"):

email = get_setting("email")

send_msg_logger = logging.getLogger("Main.functions.send_msg")

FROM = "tensorflow21@gmail.com"

BODY = "\r\n".join(("From: %s" % FROM, "To: %s" % email, "Subject: %s" % SUBJECT , "", msg))

try:

server = smtplib.SMTP("smtp.gmail.com", 587)

except:

send_msg_logger.critical("Problem with internet connection.")

send_msg_logger.exception("Error!")

exit(0)

server.starttls()

server.login(FROM, base64.b64decode('VGVuc29yNTUyMQ=='))

server.sendmail(FROM, [email], BODY)

server.quit()

Для получения полного пути до различных директорий, находящихся в основном репозитории проекта, написана функция get_pwd(dir), где dir - путь начиная с основной папки проекта (Листинг 13). Так как основной скрипт программы запускается в папке models/research/object_detection, то выводится полный путь, убираются три последние директории и добавляется относительный путь.

Листинг 13

Функция отправки письма пользователю.

def get_pwd(dir=""):

pwd = os.getcwd()

if dir <> "":

lst = pwd.split('/')

count = len(lst)-3

string = ""

for i in range(count):

string = string + lst[i] + "/"

pwd = string + dir

return pwd

В листинге 14 приведена функция для получения значений из конфигурационного файла. В функцию передается один параметр - название искомой переменной. Если в конфигурационном файле отсутствует переданная переменная, то функция вернет пустую строку.

Листинг 14

Функция для получения значений из конфигурационного файла.

def get_setting(get_setting = ""):

get_setting_logger = logging.getLogger("Main.functions.get_setting")

if get_setting <> "":

config = configparser.ConfigParser()

pwd = get_pwd("conf")

config.read(pwd + "/settings.ini")

try:

setting = config.get("Settings",get_setting)

except:

get_setting_logger.warning("No option '%s' in section: 'Settings'" % (get_setting))

return ""

return setting

else:

return ""

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

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

2.3 Отказоустойчивость

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

При тестировании надежности программы, она была запущена на сервере в фоновом режиме. По результатам тестирования процесс был стабилен на протяжении 48 часов и был завершен вручную.

Рис.2. Технические характеристики CPU локальной машины.

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

Программа была запущена на локальной машине и двух серверах. Все расчеты для анализа изображения происходили на CPU. На рисунках 2 и 3 приведены технические характеристики процессора и доступная оперативная память устройства.

Рис.3. Доступная оперативная память локальной машины.

На рисунке 4 показано состояние запущенного процесса. Все восемь процессоров почти полностью загружены. При работе программы используется чуть менее 900 Мб оперативной памяти. Скорость обработки изображений в данных условиях достигает 7-8 кадров в секунду.

Рис.4. Состояние выполняемого процесса на локальной машине.

Рис.5. Технические характеристики CPU первого сервера.

На рисунках 5-7 показаны показаны технические характеристики первого сервера. При запуске программы на нем скорость обработки достигает трех кадров в секунду. Во время тестирования было выявлено, что такой производительности не достаточно для приемлемой работы трекинга, так как при движении человека влево (в направлении малой части кадра) сложно обработать данное действие.

Рис.6. Доступная оперативная память первого сервера.

Рис.7. Состояние выполняемого процесса на первом сервере.

На рисунках 8-10 показаны характеристики второго сервера. Скорость обработки на нем достигает 5 кадров в секунду. Использование оперативной памяти на трех машинах составляет 800-900 Мб, а для успешного запуска оперативная память машины должна быть больше 5 Гб. Также было установлено, что библиотека TensorFlow забирает максимальные ресурсы CPU.

Рис.8. Технические характеристики CPU второго сервера.

Рис.9. Доступная оперативная память второго сервера.

Рис.10. Состояние выполняемого процесса на втором сервере.

Выводы

Для решения описанной во введении проблемы, заключающейся в отсутствии на рынке программного обеспечения для ip ptz камер для автоматического слежения за выступающим, был реализован алгоритм на языке Python. С помощью написанного программного обеспечения можно проводить съемку лекций и выступлений без привлечения оператора.

Основываясь на приведенной во введении проблематике, заключающейся в сложности регулярных съемок всех выступлений студентов и лекций из-за высоких трудозатрат на проведения каждой из них, целью данной работы было поставлено написание программного обеспечения для ip ptz камер. Для работы программы слежения за человеком не должно требоваться дополнительных устройств и датчиков.

Был проведен анализ смежных с целью работы решений. К таким решениям можно отнести слежения за движением в охранной области и специализированные установки с функцией слежения для проведения видеоконференций. Цели в охранной области и при проведении видеоконференций отличаются от целей при проведении съемки лекций.

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

Список используемых источников

[1] Paul Viola, Michael Jones. Rapid Object Detection using a Boosted Cascade of Simple Features. ACCEPTED CONFERENCE ON COMPUTER VISION AND PATTERN RECOGNITION, 2001.

[2] Nikhil Yadav, Utkarsh Binay. Comparative Study of Object Detection Algorithms. International Research Journal of Engineering and Technology (IRJET) , 2017,

[3] Tsung-Yi Lin, Michael Maire, Serge Belongie, Lubomir Bourdev, Ross Girshick, James Hays, Pietro Perona, Deva Ramanan, C. Lawrence Zitnick, Piotr Dollar. Microsoft COCO: Common Objects in Context. arXiv:1405.0312v3 [cs.CV] 21 Feb 2015

Приложение

Листинг скрипта start_tracking.py

import smtplib

import traceback

################################

# 1. Starting the virtual environment

################################

activate_this_file = "venv/bin/activate_this.py"

execfile(activate_this_file, dict(__file__=activate_this_file))

import sys

import os

os.system('cp -f utility_function/mobilenet_v1.py models/research/slim/nets/')

os.system('cp -f utility_function/visualization_utils.py models/research/object_detection/utils/')

pwd = os.getcwd()

sys.path.append(pwd+'/classes')

os.chdir('models/research')

pwd = os.getcwd()

sys.path.append(pwd)

sys.path.append(pwd+'/slim')

os.chdir('object_detection')

################################

# 2. Loading the libraries

################################

import numpy as np

import math

import cv2

import six.moves.urllib as urllib

import tarfile

import time

import base64

import pyping

import logging

import tensorflow as tf

import configparser

from imutils.video import FPS

from onvif import ONVIFCamera

from time import sleep

from threading import Thread

from object_detection.utils import label_map_util

from object_detection.utils import visualization_utils as vis_util

import WebcamVideoStream as WVS

import Tensor as T

import Move as M

import Move2 as M2

import Utility_Functions as UF

import Ping as P

################################

# 3. Create log file

################################

pwd = UF.get_pwd("log")

logger = logging.getLogger("Main")

logger.setLevel(logging.INFO)

fh = logging.FileHandler(pwd+"/main.log")

pwd_images_to_recognize = UF.get_pwd("images_to_recognize")

pwd_recognition_queue = UF.get_pwd("recognition_queue")

formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

fh.setFormatter(formatter)

logger.addHandler(fh)

logger.info("__________________Program_started__________________")

################################

# 4. Get settings from settings

################################

ip = UF.get_setting("ip")

length = int(UF.get_setting("length"))

hight = int(UF.get_setting("hight"))

port = UF.get_setting("port")

login = UF.get_setting("login")

password = UF.get_setting("password")

wsdl_path = UF.get_pwd("wsdl/")

visible = UF.get_setting("visible")

speed_coef = float(UF.get_setting("speed_coef"))

init = UF.get_setting("init")

face_recognition_on = UF.get_setting("face_recognition_on")

stream = WVS.WebcamVideoStream()

tensor = T.Tensor(visible = visible,model_name = 'ssd_mobilenet_v2_body')

move = M2.Move(length = length, hight = hight, speed_coef = speed_coef, mycam_ip = ip, mycam_port = port, mycam_login = login, mycam_password = password, mycam_wsdl_path = wsdl_path)

stream.start()

tensor.start()

move.start()

ping = P.Ping(mycam_ip = ip)

ping.start()

if init == 'Yes':

speed_coef = UF.init_tracker(stream=stream, tensor=tensor, move=move, length=length, hight=hight, speed_coef=speed_coef)

print speed_coef

move.set_speed_coef(speed_coef)

next_time = 0

while True:

img = stream.read()

if ping.read() <> 0:

stream.stop()

logger.warning("Camera conection lost. Reconnect...")

while ping.read() <> 0 or not stream.check_connect() or stream.status():

sleep(1)

stream = WVS.WebcamVideoStream()

stream.start()

logger.info("Camera conection restored.")

img = stream.read()

if img is not None:

img = cv2.resize(img, (length,hight))

tensor.set_image(img)

img = tensor.read()

#print tensor.get_tps()

if img is not None:

scores = tensor.read_scores()

image_np = tensor.read()

classes = tensor.read_classes()

boxes = tensor.read_boxes()

if (scores is not None and image_np is not None and classes is not None and boxes is not None):

scores[scores > 0.45] = 1

classes = classes*scores

persons = np.where(classes == 1)[1]

print tensor.get_tps()

if (str(persons) <> '[]'):

# <>

if time.time() > next_time and face_recognition_on == 'Yes':

img_path = pwd_images_to_recognize + '/' + str(round(time.time())) + '.png'

cv2.imwrite(img_path, img)

with open(pwd_recognition_queue + '/recognition_queue.txt', 'a+') as file:

file.write(img_path)

next_time = time.time() + 3

# /<>

person = persons[0]

l_h = [hight,length,hight,length]

box = boxes[0][person]

box = l_h*box

move.set_box(box)

#print box

else:

move.set_box(None)

if (visible == 'Yes'):

cv2.imshow('frame', img)

if cv2.waitKey(20) & 0xFF == ord('q'):

move.set_box(None)

sleep(1)

logger.info("Done!")

break

Листинг скрипта WebcamVideoStream.py

import os

import sys

import cv2

import configparser

from threading import Thread

import traceback

import time

from time import sleep

import numpy as np

import Utility_Functions as UF

import logging

################################

# 1. The process of taking a frame from a stream

################################

class WebcamVideoStream:

# 1.1. Initialization

def __init__(self, name="WebcamVideoStream"):

try:

self.name = name

# 1.1.1. Determining the path to the configuration file

# add_try (count >= 3)

init_logger = logging.getLogger("Main.%s.init" % (self.name))

# 1.1.2. Read configuration file (rtsp)

# modify (receiving rtsp from camera)

self.mycam_rtsp = UF.get_setting("rtsp")

print self.mycam_rtsp

self.mycam_ip = UF.get_setting("ip")

# 1.1.3. Sturt function cv2.VideoCapture

try:

self.stream = cv2.VideoCapture(self.mycam_rtsp)

except:

init_logger.critical("Error with cv2.VideoCapture")

init_logger.exception("Error!")

exc_type, exc_value, exc_traceback = sys.exc_info()

err_msg = str(''.join(traceback.format_exception(exc_type, exc_value, exc_traceback)))

UF.send_msg(msg=err_msg)

sys.exit(0)

if self.stream.isOpened() is False:

err_msg = "Stream is close"

init_logger.critical(err_msg)

init_logger.info("Check rtsp in settings file")

UF.send_msg(msg=err_msg)

sys.exit(0)

else:

init_logger.info("Process get rtsp stream.")

# 3.1.4. Read frame

(self.grabbed, self.frame) = self.stream.read()

self.stopped = False

except:

init_logger.critical("Error in %s.__init__" % (self.name))

init_logger.exception("Error!")

exc_type, exc_value, exc_traceback = sys.exc_info()

err_msg = str(''.join(traceback.format_exception(exc_type, exc_value, exc_traceback)))

UF.send_msg(msg=err_msg)

sys.exit(0)

# 3.2. Start thread

def start(self):

self.stopped = False

start_logger = logging.getLogger("Main.%s.start" % (self.name))

start_logger.info("Process starting")

self.t = Thread(target=self.update, name=self.name, args=())

self.t.daemon = True

self.t.start()

return self

# 3.3. Infinite loop of receiving frames from a stream

def update(self):

try:

update_logger = logging.getLogger("Main.%s.update" % (self.name))

stream = self.stream

update_logger.info("Process started")

i = 0

time_1 = time.time()

err = 0

while True:

if self.stopped:

update_logger.info("%s stopped" % self.name)

return

(self.grabbed, self.frame) = stream.read()

#print self.frame

i = i + 1

if (i == 25):

time_2 = time.time()

err = err + time_2 - time_1 - 1

if err < 0:

err = 0

i = 0

time_1 = time.time()

update_logger.debug("Delay time: %f" % (err))

except:

update_logger.critical("Error in process")

update_logger.exception("Error!")

exc_type, exc_value, exc_traceback = sys.exc_info()

err_msg = str(''.join(traceback.format_exception(exc_type, exc_value, exc_traceback)))

print err_msg

sys.exit(0)

def check_connect(self):

try:

check_stream = cv2.VideoCapture(self.mycam_rtsp)

except:

return False

if check_stream.isOpened() is False:

check_stream.release()

return False

else:

check_stream.release()

return True

def status(self):

return self.t.isAlive()


Подобные документы

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.