Xor

 
<<< Назад

Датчик присутствия из ип камеры

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

Добрый день!

Описываю свой способ решения -
в двух помещениях, где интересно это детектировать - на кухне и веранде перед входной дверью - у меня установлены две ип-видеокамеры, подсоединенные к регистратору. Они пишут в режиме 24/7. В обеих настроена реакция на движ - отсылка письма со скриншотом на локальный сервер. Далее в дело вступает модуль smtpcatcher. По приходу писем от камер с адресами cam1@server.com/cam2@campan.ru он запускает скрипт FotoMail

//smtpcatcher выкладывает фото, если режим Охрана, отсылаем сразу в телеграм, иначе -- просто сохраняем как фото последнего движения
debmes('start FotoMail script!');
if($params['TEXT']){
 //debmes('text '.$params['TEXT']);
 $txt = $params['TEXT'];
}
if($params['TO']){
 //debmes('TO '.$params['TO']);
 $to = $params['TO'];
}
if($params['FROM']){
 //debmes('FROM '.$params['FROM']);
 $cam = explode('@',$params['FROM']);//тут посмотрим, от какой камеры пришло
 $camn =  $cam[0];
 if(!$camn) {debmes('FotoMail->no camera Exit');return;}
//у меня камеры по разному оповещают о движении((
 if($camn=='cam1'){
  $pos = strpos($txt, "alert");
  if($pos) {
     //исключим срабатывание во время вкл/выкл света
     if(time()-gg('noorelay1.updated')<5){
       return;
     }
  }
 }
 if($camn=='cam2'){
  $pos = strpos($txt, "движенияСтарт");
  if($pos){
     //исключим срабатывание во время вкл/выкл света
     if(time()-gg('noorelay3.updated')<5){
       return;
     }
  }
 } 
//registerEvent("LastCamEvent", $details = $camn.' '.$txt,$expire_in=1); //test
if($params['ATTACHEMENTS']) {
 $att = $params['ATTACHEMENTS'];
 //debmes('ATTACHEMENTS '.$params['ATTACHEMENTS']);
 $fn= DOC_ROOT.'/cms/cached/cam/'.$att;
 debmes('FotoMail->foto to detect '.$fn);

    if(gg('SecurityMode.active')){ 
     //можно отослать в телеграм
     include_once(DIR_MODULES.'telegram/telegram.class.php');
     $telegram_module = new telegram();
     $telegram_module->sendMessageToAdmin($txt);
     $telegram_module->sendImageToAll($fn, 'Движение обнаружено');
     //Say('Улыбайтесь, вас снимает скрытая камера!');
   }//TELEGRAM
///////////////////////////////////////// 

 $fileto = DOC_ROOT.'/cms/images/'.$camn.'.jpg';
 if(copy($fn,$fileto)){
   unlink($fn); 
   if(file_exists($fileto)){ 
    runScriptSafe('FotoDetect',array('cam'=>$camn,'file'=>$fileto));//отправим на детекцию
   }
 }

}//ATTACHEMENTS
}//FROM

Если есть снимок, отправляем его и имя камеры следующему скрипту FotoDetect

/////////////////////////////////////////// 
//вызов после снапшота с параметром камера
//image file
//распознает объекты
/////////////////////////////////////////// 

if($params['cam']){
  $cam = $params['cam'];
}else{
  debmes('FotoDetect -> no param cam...');
}
if($params['file']){
 $file = $params['file'];
}else{ 
  $file = gg($cam.'.snapshot');
  $file = str_replace('./cms/',SERVER_ROOT.'/htdocs/cms/',$file);
}
  debmes('FotoDetect - file='.$file);
  safe_exec('python '.SERVER_ROOT.'/apps/py/dlod.py --from "' . $cam . '" --image '.$file);

Вот сам питоновский скрипт распознавания dlod.py (по шапке видно, откуда я его спёр):
(настройка пакетов питона,cv2,настроенная сеть - всё оттуда - https://www.pyimagesearch.com/2017/09/11/object-de...)

# USAGE
# python deep_learning_object_detection.py --image images/example_01.jpg \
#   --prototxt MobileNetSSD_deploy.prototxt.txt --model MobileNetSSD_deploy.caffemodel

# import the necessary packages
import numpy as np
import argparse
import cv2
import urllib.request
# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True,
    help="path to input image")
#ap.add_argument("-p", "--prototxt", required=True,
#   help="path to Caffe 'deploy' prototxt file")
#ap.add_argument("-m", "--model", required=True,
#   help="path to Caffe pre-trained model")
ap.add_argument("-c", "--confidence", type=float, default=0.35,
    help="minimum probability to filter weak detections")
ap.add_argument("-f", "--from", required=True,
    help="from which camera")
args = vars(ap.parse_args())

# initialize the list of class labels MobileNet SSD was trained to
# detect, then generate a set of bounding box colors for each class
CLASSES = ["background", "aeroplane", "bicycle", "bird", "boat",
    "bottle", "bus", "car", "cat", "chair", "cow", "diningtable",
    "dog", "horse", "motorbike", "person", "pottedplant", "sheep",
    "sofa", "train", "tvmonitor"]
COLORS = np.random.uniform(0, 255, size=(len(CLASSES), 3))

# load our serialized model from disk
print("[INFO] loading model...")
net = cv2.dnn.readNetFromCaffe("c:/_majordomo/apps/py/MobileNetSSD_deploy.prototxt.txt", "c:/_majordomo/apps/py/MobileNetSSD_deploy.caffemodel")

# load the input image and construct an input blob for the image
# by resizing to a fixed 300x300 pixels and then normalizing it
# (note: normalization is done via the authors of the MobileNet SSD
# implementation)
image = cv2.imread(args["image"])
(h, w) = image.shape[:2]
blob = cv2.dnn.blobFromImage(cv2.resize(image, (300, 300)), 0.007843, (300, 300), 127.5)

# pass the blob through the network and obtain the detections and
# predictions
print("[INFO] computing object detections...")
net.setInput(blob)
detections = net.forward()

# loop over the detections
for i in np.arange(0, detections.shape[2]):
    # extract the confidence (i.e., probability) associated with the
    # prediction
    confidence = detections[0, 0, i, 2]

    # filter out weak detections by ensuring the `confidence` is
    # greater than the minimum confidence
    if confidence > args["confidence"]:
        # extract the index of the class label from the `detections`,
        # then compute the (x, y)-coordinates of the bounding box for
        # the object
        idx = int(detections[0, 0, i, 1])
        box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
        (startX, startY, endX, endY) = box.astype("int")

        # display the prediction
        label = "{}: {:.2f}%".format(CLASSES[idx], confidence * 100)
        print("[INFO] {}".format(label))
        sss = str(CLASSES[idx])
        if sss == "person":
            link="http://192.168.1.7/objects/?op=set&object=test_event&p=value&v=" + sss + "/" + args["from"]
            f=urllib.request.urlopen(link)
        if sss == "dog":
            link="http://192.168.1.7/objects/?op=set&object=test_event&p=value&v=" + sss + "/" + args["from"]
            f=urllib.request.urlopen(link)
        if sss == "cat":
            link="http://192.168.1.7/objects/?op=set&object=test_event&p=value&v=" + sss + "/" + args["from"]
            f=urllib.request.urlopen(link)
        #cv2.rectangle(image, (startX, startY), (endX, endY),
        #   COLORS[idx], 2)
        #y = startY - 15 if startY - 15 > 15 else startY + 15
        #cv2.putText(image, label, (startX, y),
        #   cv2.FONT_HERSHEY_SIMPLEX, 0.5, COLORS[idx], 2)

# show the output image
#cv2.imshow("Output", image)
#cv2.waitKey(0)

последние закомменченные строки -- рисуют красивые квадраты вокруг распознанных объектов,
а в конце - вывод с разметкой для отладки для посмотреть, если нужно сохранить файл - добавьте строчку в самом конце со своим путем и именем файла:

cv2.imwrite('images/detect/example_01.jpg',image)

результаты работы скрипта - в случае удачи свойству value объкта test_event присваивается значение детектированный_объект/камера.

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

$v = explode("/", $params['NEW_VALUE']); //разберём входные данные
$linked_room = gg($v[1].'.LinkedRoom'); //по камере найдём помещение
if($v[0] == 'person'){
  //sg($linked_room.'.SomebodyHere',1);
  registerEvent('inhouseMovement', $details=gg($linked_room.'.title').'/'.$v[1].'/detect',$expire_in=1);
  if( $linked_room == 'Kitchen'){
     sg('motiondetect3.value',1);
     setTimeOut('md3_clean',"sg('motiondetect3.value',0);",3*60); //тут реагируем только на человека
  }
   if( $linked_room == 'Outside'){
     sg('motiondetect6.value',1);
     setTimeOut('md6_clean',"sg('motiondetect6.value',0);",3*60); //тут реагируем только на человека
  }
}
if($v[0] == 'dog'){ 
   if( $linked_room == 'Outside'){ //эксперимент - тут можно добавить сообщение, что собакен вернулся с прогулки
     sg('motiondetect6.value',1);
     setTimeOut('md6_clean',"sg('motiondetect6.value',0);",3*60); 
  }
}
  debmes($linked_room.'- '.$v[0] . ' detected');

у двух виртуальных ДД motiondetect3 и motiondetect6 при переходе в 1 начинается анализ скриншотов каждые 3 минуты, если человека не обнаруживается, ДД сбрасывается в 0.
(тут у меня заморочка - скрипт ниже запускается по-любому каждые 3 минуты Кроном, но реакция быстрее по письму от камеры)

cm('cam1.takeSnapshot');
SetTimeOut('takeSnap','getURL("192.168.1.7/api/script/FotoDetect?cam=cam1",0);',5);
SetTimeOut('md3_clean',"sg('motiondetect3.value',0);",2.5*60);

cm('cam2.takeSnapshot');
SetTimeOut('takeSnap2','getURL("192.168.1.7/api/script/FotoDetect?cam=cam2",0);',5);
SetTimeOut('md6_clean',"sg('motiondetect6.value',0);",2.5*60);

Вот такая фигня получилась.

Примечание - от smtpcatcher можно отказаться, смысл - получить сигнал о движении от камеры и скриншот.
Распознавание картинки у меня меньше секунды, но сетка используется самая глупая. Я думаю, что этот способ не годится для спальни, где человек лежит под одеялом почти весь. Но не проверял. Человек, сидящий за столом (видно только бюст) определяется верно.
Детекция лиц не производится, получается только инфа о количестве человек в помещении!

Обсуждение (16) (14)

Смотрите так же:
12.02.2024 Китайская панель в подрозетник с экраном 480*480
29.10.2023 MQTT в МДМ - способ обработки топика через метод
03.04.2023 Todoer: обмен данными с Яндекс календарём
31.03.2023 Todoer: календарь на год
30.03.2023 Todoer: анонс + программное создание задачи
08.05.2022 Глобальный поиск - добавление своих сущностей. Upd Внедрено
05.01.2022 Яндекс Лампочка в Yandex Devices - добавление сцен
18.04.2021 Переезд на мастер спустя год
24.03.2021 Ещё о старте/остановке МДМ в Винде
18.02.2021 Модуль Todoer
06.01.2021 Для виндузятников - перенос бд на рам-диск
22.11.2020 Календарь-планировщик
01.08.2020 Irbis как терминал
18.05.2020 Китайская камера rtsp + vlc как перекодировщик для html
12.05.2020 Опыт интеграции МДМ с Я.Алисой ещё одним способом - без белого адреса, москита, ПУ.(дополнено)
07.05.2020 Поправим формат даты в Панели управления
11.04.2020 Баловство с шаблонами
26.03.2020 Простые правила - вариант модуля. ч. 2
25.03.2020 Простые правила - вариант модуля
20.12.2019 расширение средств работы с events updated
20.11.2019 По следам наших выступлений - сколько мы наэкономили?
04.11.2019 Группа как объект - экономим на коде - 2
26.10.2019 Прикручиваем Grafana к Мажордому
11.10.2019 Группа как объект - экономим на коде
25.09.2019 Если у вас нет телеги...
30.07.2019 Win-платформа-замена ffmpeg для получения скриншотов из rstp - потока
24.06.2019 Форматированный отчет в телеграм - имитация таблицы
30.04.2019 Используем зомбо-ящик в Мажордомо
24.03.2019 О среднем в Мажордомо
31.10.2018 Об "обделённых" пользователях Win-систем -- с точки зрения кэширования winTTS сообщений
16.09.2018 Перезагрузка Мажордомо в Win-системах

Домодедово, Россия

На форуме: xor