Raspberry Pi: видеокамера с детектором движения

В процессе экспериментов с малышкой RPi на просторах инета мне попался скрипт motion.py, который ведет непрерывную видеозапись с камеры и сохраняет в выходном видео только движущиеся изображения. Это очень удобно как с точки зрения экономии места на флешке, так и для просмотра: очень быстро надоест проматывать запись с автомобильной стоянки за всю ночь, когда нужна буквально пара — другая информационных кадров. Если быть точным, то это не совсем видео в современном смысле, а скорее видео в классическом: RPi беспрерывно делает фотографии, которые склеиваются в формат motion jpeg.

Детектор движения у нас есть, сделаем полноценную систему видеонаблюдения того, что происходит за окном. И не только за окном: ночью в магазине, офисе, на складе, дома когда вы в отъезде — применений просто огромное количество. Устроено все очень просто: Raspberry Pi с видеокамерой и WiFi донглом для доступа в интернет, и пара скриптов: motion.py и conv.sh.

Скрипт motion.py: детектор движения

Питоновский скрипт motion.py я немного доработал под систему:

Скрипт работает так. В цикле через утилиту raspistill, которая работает с камерой, непрерывно делаются фотоснимки, после чего сравнивается каждый текущий и предыдущий кадр. Сравнение выполняется в модуле Imagemagic. Если кадры различаются начиная с некоторого уровня порога, значит в зоне наблюдения присутствует движение и снимки начинают записываться в директорию cache SD — карты RPi в формате jpeg, причем название файла образовано от отметки текущего времени.

Скрипт motion.py стартует с загрузкой RPi и работает непрерывно. Частота появления файлов в директории cache будет зависеть от движения в кадре: если картинка сильно меняется то снимки будут появляться постоянно; если движения нет — то новых файлов не будет.

Далее, с определенной периодичностью, нужно смонтировать полученные кадры в видеоролик и отправить его в сеть. Эту задачу выполняет скрипт conv.sh.

Скрипт conv.sh: формирование видеороликов и выкладка их на файловый сервер

Задача второго скрипта — conv.sh — периодически запускать на обработку полученные снимки. Для этого он выполняет следующую последовательность действий:

  • собирает снимки, накопленные к данному времени скриптом motion.py;
  • вставляет в снимки титры с указанием даты и времени снимка;
  • переименовывает снимки для того, чтобы к ним можно было применить групповую операцию;
  • преобразует последовательность снимков в видеоролик;
  • стирает обработанные снимки;
  • выкладывает видеоролик  на файловый сервер типа box.net или Яндекс.

Скрипт conv.sh содержит следующую последовательность команд:

Первым делом, составляется список всех снимков накопленных в директории cache и каждый снимок из списка пропускается через утилиту convert, которая вставляет в снимок отметку времени. Сразу замечу, что это накладная процедура, поэтому лучше обходиться без нее. В этом случае надо просто закомментировать вызов convert и раскомментировать вызов команды mv. И в том и другом случае файл снимка получает новое имя  — возрастающее число. Это необходимо сделать для того, чтобы конвертор ffmpeg мог выполнить групповую операцию над файлами с маской %06d.jpg.

Поскольку ffmpeg из пакетов RPi имеет ограниченную функциональность, я компилировал утилиту из исходников и разместил полную версию в каталоге /home/pi/bin. После монтажа снимков в видеоролик, который будет временно располагаться в директории /tmp/*.avi, другая команда — curl отправляет ролик на файловый сервер.  В нашем случае это сервер dav.box.com.

После этого подчищаются обработанные файлы и сам отправленный ролик.

Скрипт conv.sh запускается каждые 15 минут по cron. За это время не должно быть переполнения файловой системы; ну и сам размер клипа должен быть вменяемым для передачи через сеть.

В результате, мы можем залогиниться на box.net и посмотреть нарезку роликов, которые будут появляться каждые 15 минут. Само собой, это время можно изменить в настройках cron. Косвенно, размер каждого ролика определяет активность в кадре: чем больше движений тем длиннее ролик,  а если ничего не происходит и картинка статичная, длина ролика будет вплоть до нулевой.

Во всей этой истории есть слабое место, а именно сборка клипа с помощью ffmpeg. Поскольку он не использует аппаратное ускорение, то загрузка ARM идет под 100%, и это весьма печально; хуже всего что при интенсивном движении в кадре и как следствие большом количестве файлов сборка может не завершиться к тому моменту когда conv.sh должен быть запущен в очередной раз. С этим приходилось мириться, пока я не нашел это решение, заточенное под GPU.

RPi style: как малышка Raspberry Pi уделает Intel при монтаже клипа

Как мы знаем, несмотря на свою миниатюрность, RPi обладает мощным ресурсом: это GPU, Graphic Processig Unit, в котором реализована аппаратная поддержка такого известного кодека как H.264. На программном уровне с GPU работает программная прослойка OpenMax, а в свою очередь реализация мультимедийной утилиты gstreamer на RPi использует OpenMax и соответственно ресурсы GPU.

Не буду описывать установку дополнительных пакетов, как это описано по ссылке: я поставил их без проблем. Что нам нужно сделать — это теперь выкинуть из скрипта conv.sh утилиту ffmpeg и заменить ее следующей строкой:

Теперь все стало любо — дорого: выходной ролик вместо mjpeg получил навороченный формат h.264, а время монтажа сократилось с минут до нескольких секунд! Вот она, мощь рациональной архитектуры по сравнению с много-много CPU GHz.

В сети можно найти сравнительные тесты обработки видео в Raspberry Pi с использованием аппаратного ускорения и с использованием платформы Intel. Посмотрите, не поленитесь, результаты вас удивят.

2 комментария Raspberry Pi: видеокамера с детектором движения

  • Решила тоже прикупить себе Raspberry Pi, но для дачи, так как постоянная запись там не нужна, а такая маленькая палочка выручалочка всегда пригодиться, так как страшно оставлять вещи без присмотра. Спасибо, ваши скрипты очень помогли, все работает)

Ответить

Вы можете использовать эти HTML теги

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">