AlexanderKamynin / motion-detection

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

motion-detection

Описание практического задания:

Технологии и ограничения:

  • Языки программирования: Java, Python, C++;
  • Дополнительные библиотеки: OpenCV;

Постановка задачи:

  1. Реализовать программный модуль опроса видеокамеры. Для теста можно использовать видеокамеру Axis 214 192.168.217.103. При этом допускается использование библиотеки Opencv.

  2. Разработать два варианта детектора движения для выделения объектов переднего плана:

  • детектор движения с использование функционала библиотеки opencv;
  • детектор движения без использования сторонних библиотек;
  1. С помощью оптического потока разработать модуль сопровождения (трекинга) объекта, выделенного при реализации п.2. При этом отобразить сглаженную траекторию движения объекта.

Зависимости

Проект реализован на языке Python с использованием следующих библиотек:

  • numpy (Ссылка на страницу с инструкцией по установке и документацией): хранение массивов и некоторые модули для работы с несколькими массивами (операция свертки numpy.convolve2d(), поиск среднего значения numpy.mean())
    Установить библиотеку можно с использованием pip3 следующей командой: pip3 install numpy
  • opencv-python (Ссылка на страницу с инструкцией по установке): считывание видео и кадров, использование функционала для детекции движения, трекинга выделенного объекта алгоритмом оптического потока.
    Установить библиотеку можно с использованием pip3 следующей командой: pip3 install opencv-python

Инструкция по запуску

Перед запуском необходимо скачать проект. Это можно сделать с помощью команды https://github.com/AlexanderKamynin/motion-detection.git.
Запуск можно выполнить из корневой папки проекта с использованием команды python3 main.py.

Описание решения


Детекция движения с использованием библиотеки OpenCV.


Для детекции движения с использованием функционала библиотеки OpenCV реализован модуль detectionCV.py с классом MotionDetectionCV. В классе определен метод detect(), принимающий на вход два соседних по времени черно-белых изображения, а на выход выдающий словарь, в котором ключ - id выделенного объекта, значение - список с двумя кортежами, характеризующими левый верхний и правый нижний углы прямоугольника, описанного вокруг объекта.

В самом начале вычисляется разница между двумя кадрами с помощью cv2.absdiff(), после чего к данной разности применяется фильтр Гаусса cv2.GaussianBlur(), размывающий изображение, что позволяет уменьшить шум.

Размытое изображение передается в метод cv2.threshold(), который все пиксели, значение которых в черно-белом изображении меньше заданного значение порога threshold, устанавливает в значение 0 (черный цвет), иначе в 255 (белый цвет). К полученному результату применяется операция дилатации cv2.dilate(): расширение белых пикселей на изображении, благодаря чему контуры становятся более явными.

Обработанное по итогу работы дилатации черно-белое изображение содержит в себе движимые объекты из белых пикселей, и фон черного цвета. Для того, чтобы убрать шум, который из-за дилатации мог увеличиться в размере, рассматриваются последние N (max_frames в коде модуля) результатов дилатации и усредняются между собой с помощью np.mean(). Полученное значение передается в метод cv2.findContours(), выдающим краевые точки обнаруженного контура объекта.

Методом cv2.contourArea() вычисляется площадь выделенных объектов. Те контуры, площадь которых меньше заданного порога min_area, убираются из рассмотрения. Далее удаляются все контуры, которые полностью оказались внутри любых других контуров.

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


Детекция движения без использования библиотеки OpenCV.


Для детекции движения реализован модуль detectionCustom.py с классом MotionDetectionCustom. В классе определен метод detect(), принимающий на вход два соседних по времени черно-белых изображения, а на выход выдающий словарь, в котором ключ - id выделенного объекта, значение - список с двумя кортежами, характеризующими левый верхний и правый нижний углы прямоугольника, описанного вокруг объекта.

В самом начале вычисляется разница между двумя кадрами по модулю, после чего к данной разности применяется фильтр Гаусса, размывающий изображение, что позволяет уменьшить шум. Работа фильтра Гаусса заключается в последовательном перемножении ядра на окрестность пикселей изображения. Формула для вычисления ядра Гаусса размера N x N (N - нечетное) выглядит следующим образом: $$G(x,y) = \frac{1}{2 \pi \sigma^2} \exp( - \frac{x^2 + y^2}{2 \sigma^2} )$$ где x и y - координаты пикселя в ядре, принимающие значения от $- \frac{N-1}{2}$ до $\frac{N-1}{2}$, а $\sigma$ - стандартное отклонение функции Гаусса, характеризующей размер размытия. Полученное ядро нормализуется (все значения делятся на сумму элементов), что обеспечивает сохранение яркости изображения после применения фильтра. Так как Python - медленный язык, то честный перебор всех пикселей и получение всех окон изображения - затратно. Поэтому используется метод convolve2d() из библиотеки scipy.signal.

Для размытого изображения все пиксели, значение которых меньше заданного значения порога threshold, устанавливаются в значение 0, иначе в 255. К полученному результату применяется операция дилатации: расширение белых пикселей на изображении, благодаря чему контуры становятся более явными (проход по всему изображению и присваивание пикселю максимального значения в рамках задаваемого размера окна). Так как в задаче необходимо получить координаты объектов (описанных вокруг них прямоугольников), то для сокращения числа операций при операции дилатации изображение уменьшается в задаваемое число раз.

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

Для поиска контуров применяется BFS, расматривающий окрестность Фон Неймана для первого найденного непосещенного белого пикселя (из-за усреднения вводится дополнительный порог bounding_threshold, с высоким значением, например, 200, значения больше которого считаются контуром) и обновляющий информацию об крайних точках контура (слева, справа, снизу и сверху). Полученные крайние точки являются описанным вокруг движимого объекта прямоугольником. Если площадь этого прямоугольника меньше значения min_area, то данный контур не рассматривается. Так как при операции дилатации изображения могло быть уменьшено, то для для восстановления координат контура в исходном кадре они домножаются на коэффициент уменьшения.

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


Модуль сопровождения (трекинга) объекта


Для трекинга движения реализован модуль tracker.py с классом Tracker. В классе определен метод track(), принимающий на вход два соседних по времени черно-белых изображения, а также словарь, в котором ключ - id выделенного объекта, значение - список с двумя кортежами, характеризующими левый верхний и правый нижний углы прямоугольника, описанного вокруг объекта. Метод возвращает маску (изображение) с линиями смещения центров объектов из одного кадра в другой.

Для трекинга используется метод cv2.calcOpticalFlowPyrLK(), в котором реализован пирамидальный алгоритм Лукаса-Канаде вычисления оптического потока (описание алгоритма). Метод возвращает новые координаты центров, обнаруженных на следующем кадре. Все центры объектов сохраняются в словаре, где ключ - id объекта, а значение - список координат центров объектов на изображении в разный момент времени. Новые линии из предыдущего центра объекта в новый отрсовываюстя на маске. Если число точек для какого-либо объекта превышает заданный порог max_point, то удаляются самые ранние.

Пример работы проекта

Результат работы с реализацией OpenCV:

cv_result.mp4

Результат работы без использования реализации OpenCV:

custom_result.mp4

About


Languages

Language:Python 100.0%