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



Описание итогового решения


Проанализировав свой опыт использования системы видеонаблюдения и рекомендации к предыдущему посту (отдельное спасибо Varkus), в результате выбрал для себя реализацию с использованием PIR-датчика (далее датчик) для определения перемещений/движений. Алгоритм решения реализовал на Python.

Ранее я не хотел использовать дополнительный аппаратный компонент в своем решении, но подход с использованием датчика оказался очень простым и лаконичным. Тем более, что датчик оказался недорогим, если заказать его на aliexpress.

Аппаратная часть


Из «железа» использовал:

— Raspberry Pi3;
— USB-камеру Logitech;
— датчик движения SR501P1.
Для работы в ночное время дополнительно необходимо приобрести инфракрасный излучатель (лампу).

Датчик подключил с помощью 30-и сантиметровых коннекторов, внешний вид привожу ниже.



Да, предварительно выбрал необходимую чувствительность, настроив его с помощью потенциометра.

Программная часть


Для автоматизации процесса видеонаблюдения ограничился одним Python-скриптом, который выполняет всю работу, а именно — мониторит перемещения с помощью датчика и, если оно выявлено:

— делает несколько снимков помещения, используя для этого библиотеку Python OpenCV;
— сохраняет снимки в Яндекс.Диске;
— по достижении определенного порога перемещений, в моем случае – десять выявленных перемещений, прекращает съемку и отправляет последний из сохраненных снимков в Telegram.

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

В конечном варианте я отказался от использования алгоритма по определению лиц на фото.
Код скрипта, без алгоритма по определению лиц, приведен ниже.

from gpiozero import MotionSensor
import cv2
import telepot
import time

def Telegram_send(input_file):
 import glob
 import os
 file=max(glob.iglob(input_file+'*.jpg'),key=os.path.getctime)
 bot = telepot.Bot('*************************************')
 bot.sendMessage(*********, 'Motion detected!')
 bot.sendPhoto(*********, open(file,'rb'))

def main():
 file='/home/pi/alarms/'
 counter=1
 threshold=10
 time.sleep(10)
 pir=MotionSensor(4)
 try:
  camera=cv2.VideoCapture(0)
  while counter<=threshold:
   #if pir.motion_detected:
    #pir.wait_for_motion()
    pir.when_motion
    print("Motion detected at "+str(time.strftime("%Y%m%d-%H%M%S")))
    if not camera.isOpened():
     camera.open(0)
     result,image=camera.read()
    else:
     result,image=camera.read()
    cv2.imwrite(file+str(time.strftime("%Y%m%d-%H%M%S"))+'.jpg',image)
    counter+=1
    #pir.wait_for_no_motion()
    pir.when_no_motion
    camera.release()
  if counter >=threshold: Telegram_send(file)
 except Exception as e:
  print('Something is wrong.',e)
  camera.release()
 finally:
  camera.release()

if __name__=="__main__":
 main()

«Плюсы» и «минусы» решения с использованием датчика


Плюсы использования датчика:

1. Простой итоговый код в виде ОДНОГО скрипта на Python, реализующего весь алгоритм работы.
2. Относительная дешевизна датчика.

Из минусов вижу пока только возможность выхода из строя датчика при длительной его эксплуатации. Но, возможно, этот девайс (датчик) будет стабильно и долго работать, несмотря на то, что это не «промышленный» вариант.

Дополнительные возможности


Так же я попробовал подключать вторую камеру. Raspberry справился с обработкой видеопотока с двух камер без проблем.

Заключение


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

Надеюсь, что предложенный вариант окажется полезной альтернативой реализации системы видеонаблюдения, которую можно легко выполнить «своими руками».
Поделиться с друзьями
-->

Комментарии (30)


  1. Zonzen
    25.01.2017 21:30
    +1

    Отлично, коротко и понятно.


    1. Tkachev_KV
      25.01.2017 23:14

      Спасибо.


    1. Tkachev_KV
      25.01.2017 23:20

      Спасибо.


  1. risotto
    25.01.2017 21:32

    Интересно было бы взглянуть на фото с камеры во время проникновения.


  1. musuk
    25.01.2017 21:35

    Чем плох motion? Он может и видео по движению записывать, и картинки сохранять и датчика не требует.
    http://www.lavrsen.dk/foswiki/bin/view/Motion/WebHome


    1. Tkachev_KV
      25.01.2017 21:39

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


      1. musuk
        25.01.2017 22:55

        Motion может не сохранять видео, и там есть External Commands http://www.lavrsen.dk/foswiki/bin/view/Motion/ExternalCommands

        Почем не вышло их использовать?


        1. Tkachev_KV
          25.01.2017 23:22

          Ниже комментарий из моего предыдущего поста.
          Добавлю так же что motion это, на мой взгляд, еще не зрелое решение и что будет с его развитием — не понятно. Для меня он остался «черным ящиком». Мое же решение очень простое и открытое.
          — Попытался использовать user scripts в motion. Оказалось, что это не очень просто.
          Вроде все корректно настроил — в motion.conf указал необходимые настройки.
          Изменил пользователя для файлов скриптов, дал права на исполнение скриптов (пробовал как python, так и shell-скрипты).
          Пока ничего не получилось. При этом сохранение отдельных файлов и видео при обнаружении движения работает. Все сохраняется в target_dir.
          Замечу, что не у одного меня возникли с этим проблемы. Ниже приведен перечень вопросов/проблем, с которыми сталкиваются пользователи motion.
          Многие вопросы остаются нерешенными… Возможно, продукт еще достаточно «молодой» и много изменений, связанных с его развитием.
          Все рекомендации, указанные в ответах на вопросы ниже я попробовал (в т.ч. анализ логов motion). Пока безрезультатно.
          Даже echo с выводом в файл, расположенный в target_dir, не работает. motion в target_dir успешно пишет файлы и видео.

          http://stackoverflow.com/questions/35469118/how-can-i-use-the-on-motion-detected-method-on-raspberry-pi-motion
          http://raspberrypi.stackexchange.com/questions/8273/running-script-in-motion
          http://unix.stackexchange.com/questions/59091/problems-running-python-script-from-motion
          https://www.raspberrypi.org/forums/viewtopic.php?t=86534&p=610482
          https://sourceforge.net/p/motion/mailman/message/33153769/


          1. hobbyte
            27.01.2017 08:00

            У меня рассылка уведомления от motion работала так:

            $ cat cam-dcs-932l-1.conf
            netcam_url http://10.255.255.2/mjpeg.cgi
            netcam_userpass motion:motion
            target_dir /srv/motion/cam-ip
            webcam_port 6998
            text_left  DoorCam
            #on_motion_detected /usr/local/bin/motion_mail.sh "%d-%m-%Y %H:%M:%S" DoorCam
            on_event_start /usr/local/bin/motion_mail.sh "%d-%m-%Y %H:%M:%S" DoorCam
            jpeg_filename doorcam_%H%M%S_%d%m%Y-%v-%q
            movie_filename doorcam_%H%M%S_%d%m%Y-%v
            

            $ cat /usr/local/bin/motion_mail.sh | grep -v '#'
            
            TO="user@gmail.com"
            SUBJECT="Motion detected"
            WHERE="${2}"
            WHEN="${1}"
            SENDER="bot.motion"
            PASSW="passw"
            
            /bin/echo "{\"to\": \"${TO}\",\"subject\": \"${SUBJECT}\",\"body\": \"${WHERE} ${WHEN}\"}" > /tmp/gtalk-fifo
            

            Файлы сами по-себе сохранялись, сообщение шло в G-talk.
            Альтернативный вариант был с выгрузкой картинки в пикасу и смс-кой с модема.


  1. igor_suhorukov
    25.01.2017 23:30

    Подскажите, а датчик движения работает в режиме прерывания или опрашиваете изменение в цикле?

    Недавно публиковал похожее по функционалу решение «Сигнализация для холодильника. Не жизнь, а «малина» c RaspberryPi 3», но использовал геркон и camel компоненты для публикации…


  1. Tkachev_KV
    25.01.2017 23:44

    Добрый день.
    Датчик работает так: если обнаружено движение, то на информационный выход подается сигнал. Это я могу контролировать в коде.
    Чтобы постоянно мониторить сигнал можно было использовать «вечный» цикл, например, While True:…
    Но я решил ограничиться 10-ю срабатываниями датчика.
    Надеюсь, что ответил на Ваш вопрос.


    1. igor_suhorukov
      26.01.2017 00:32

      Вопрос был немного глубже — но видимо это надо смотреть в документацию и исходники библиотеки gpiozero как работает MotionSensor.motion_detected. Я не пишу на Python, но судя по исходным кодам в вашей статье этот вызов неблокирующий и вы опрашиваете датчик в цикле. Если так, то это неэффективно и лучше использовать обработчики pir.when_motion и pir.when_no_motion.


      1. Tkachev_KV
        26.01.2017 19:44

        Насчет неэффективности я бы поспорил, но не хочется устраивать холивар.
        Я использовал различные методы класса MotionSensor:
        0. motion_detected. Возвращает True, если есть активный сигнал.
        1. when_motion/when_no_motion. Эти методы контролирую переход из состояния активный/неактивный;
        2. wait_for_motion/wait_for_no_motion. Эти методы делают паузу до тех пор пока есть сигнал активный/неактивный.

        В любом случае эти методы нужно вызывать в цикле. Никакой разницы в их использовании я не заметил, поэтому решил использовать первый протестированный метод — motion_detected.


        1. igor_suhorukov
          27.01.2017 11:09

          Я повторяюсь, я не специалист в питоне и тем более библиотеке для этого сенсора. Могу лишь судить по всем иным платформам… Но одно дело реакция на аппаратное прерывание, а другое — чтение статуса GPIO в цикле… Так можно пропустить изменение уровня сигнала, если процесс «подвиснет» на доли секунды в многозадачной ОС. К тому же опрос в цикле — бесполезная трата ресурсов процессора и электроэнергии.


          1. Tkachev_KV
            27.01.2017 11:18
            +1

            Да, вероятно, сейчас вопрос понял.
            Лучше использовать функцию pir.wait_for_motion()/pir.wait_for_no_motion() в таком виде:
            While...:
            pir.wait_for_motion()

            pir.wait_for_no_motion()
            pass


            1. igor_suhorukov
              27.01.2017 11:22

              Спасибо!


              1. Tkachev_KV
                27.01.2017 11:25
                +1

                Вам спасибо.
                Я подправил текст скрипта в публикации.


              1. Tkachev_KV
                28.01.2017 11:59

                Игорь, в итоге, после тестирования, остановился на варианте when_motion/when_no_motion.
                Спасибо еще раз за совет.
                Обновил скрипт в публикации.


  1. ls1
    26.01.2017 07:00
    +1

    Скрипт вне всякого сомнения прекрасен, люблю python за такие возможности, но лично для своей берлоги предпочитаю сливать h264 на удаленный ZoneMinder сервер, такая вот диаграмка, писать не писать ради неё статью (хотя бы на GT) всё ни как не решу


    1. Areso
      26.01.2017 07:26
      +2

      Почему бы и не написать? Еще не видел здесь статей с этим ПО, а тема интересная.


      1. ls1
        26.01.2017 07:34

        Еще не видел здесь статей с этим ПО
        С zoneminder-то? Да много их было, как минимум на GT, но там всё как-то больше про apt-get install и список опций настройки, я если и буду писать то скорее про особенности применения


        1. ls1
          26.01.2017 07:57

          Хотя не, судя по тегам не очень много, но упоминают часто


  1. dinisoft
    26.01.2017 10:36

    Большое спасибо автору за статью, конечно интересно и познавательно, но всё же попробуйте разобраться в motion. На github'е есть правленные под реали малинки. От себя лишь скажу, что у меня он пишет с двух hd камер на celeron 900MHz и не захлебывается. Т.е. запись по детекту движения в кадре.


    1. Tkachev_KV
      26.01.2017 18:54

      Да, пожалуйста.
      Думаю, что с motion разбираться не буду, т.к. моя задача решена более простым средством, которое к тому же открытое и может модифицироваться без «кучи» настроек.


  1. vasiliysenin
    26.01.2017 18:54

    А я купил датчики движения для улицы и там (в инструкции) написано что они срабатывают только при движении поперёк лучей поэтому надо устанавливать одновременно несколько датчиков.
    Есть ли такая же проблема у вашего комнатного датчика?


    1. Tkachev_KV
      26.01.2017 19:00

      Нет. Такой проблемы нет, пока тестировал датчик «ловил» все движения. Относительно направления движений я не задумывался, возможно, что во всех перемещениях были «микро-поперечные» движения)
      Датчик по паспорту работает на расстоянии 6-7 м, угол мониторинга 120 градусов. Вроде так оно и есть.

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


  1. lvv1227
    26.01.2017 19:00

    Классно.

    Я решил для этой цели использовать старый телефон на Андройд и веб камеру. Телефон ее опрашивает по http и анализирует картинку, при наличии движения (ищется последовательным сравнением картинок по некоторому алгоритму, чтобы шумы убрать) шлет мейл. Можно также всегда картинку запросить самому как через почту (телефон ее регулярно опрашивает), так и по смс. Можно также не почту опрашивать для ожидания команд, а какой нибудь vds по tcp соединению (для минимизации трафика), а сервер уже почту опрашивает.

    Написано правда не на питоне, а на чистом Java + Android.


    1. Tkachev_KV
      26.01.2017 19:01

      Да, кстати, у меня тоже была такая же идея — использовать телефон. Но она, на мой взгляд, с точки зрения реализации немного сложнее.


  1. Varkus
    30.01.2017 09:33

    Спасибо автору за упоминание ;)

    В следующей версии гаджета попробуйте эту штуку Panasonic Grid-EYE Infrared Array Sensor
    На терре цена около 2700р, но матрица 8х8 температурных пикселей -20 до +80 градусов думаю того стоит.
    Затратив прилично времени можно:
    настроить тревогу превышения температуры на каждый «пиксель»
    откалибровать полупрозрачное наложение температурной матрицы на снимок с камеры
    далее отправка такого снимка на телеграм

    Т.е. можно настроить тревогу не только на движение в принципе, но и разделить её на зоны.
    Вариантов применения масса.


    1. Tkachev_KV
      30.01.2017 11:05

      Спасибо.