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

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

Смотрите так же:
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