Système de vidéo-surveillance abordable avec des Raspberry Pi

Aujourd’hui nous allons voir comment créer un système de télé-surveillance grâce à un Raspberry Pi et divers types de caméras.

IMG_6646

Ce système a pour vocation d’être utilisé dans le cardre d’une télé-surveillance domestique. Il doit permettre de garder un oeil en temps réel sur sa maison, et sauvegarder un historique des images en cas de besoin.

La capture d’écran ci-dessous vous donne un aperçu du résultat final du système qui est actuellement installé chez moi. J’ai volontairement flouté les images pour conserver l’intimité de mon « chez moi ». Je dispose de quatre caméras (une webcam, une caméra IP et deux module Raspberry Pi Caméra dont un NoIR pour la vision nocturne) :

video_surveillance_monitorin_safe

Nous verrons comment utiliser trois différents types de caméras pour vous permettre de construire votre système avec le matériel dont vous disposez déjà :

Si vous souhaitez vous équiper, je vous conseille fortement d’opter pour le module Raspberry Pi Caméra, très petit, qui offre un rapport qualité/prix imbatable. En outre le modèle NoIR vous permettra de voir la nuit grâce un projecteur infra rouge :)

Note : Je ne reviens pas ici sur l’installation et l’utilisation de ces caméras. Il existe de nombreux tutos sur le net, que ce soit pour les webcam, les caméras IP ou le module Raspberry Pi Camera. Cet article se concentre sur la création du système de télé-surveillance.

Le principe global du système

Le système se compose d’un ou plusieurs Raspberry Pi équipés chacun d’une caméra (quelque soit son type) et d’un Raspberry Pi de « contrôle » qui centralise les images. Les Raspberry Pi se contentent de prendre une photo à intervalles réguliers et de les envoyer en WiFi ou Ethernet au Raspberry Pi de « contrôle ». Chaque image est taguée avec le nom de la caméra dont elle provient, et la date à laquelle elle a été prise afin de pouvoir la situer dans le temps.

Le Raspberry Pi de « contrôle » archive toutes les images qu’il recoit et peut effectuer des traitements dessus pour détecter des mouvements par exemple. Il est également équipé d’une interface Web permettant de consulter les images à distance depuis n’importe quel device ou navigateur web.

rasperry_pi_camera_surveillance_systeme

Photo ou vidéo ?

Quand on parle de « vidéo surveillance », on s’imagine un flux « vidéo ». Or, dans la pratique, ce n’est pas forcément le cas. D’une part parce que ce n’est pas forcément utile, et d’autre part parce que c’est problématique d’un point de vu « bande passante » pour un usage domestique.

Problème réseau

Le problème se pose si l’on souhaite regarder les images prises par une caméra à distance. Il faut faire transiter ces images entre la caméra, et le poste de visionnage. Or, un flux vidéo nécessite une bande passante conséquente pour afficher les images en continue et de manière fluide. Surtout lorsqu’on utilise des résolutions importantes de plusieurs méga-pixels.

Pour résoudre ce problème, on peut soit baisser la qualité de l’image, soit baisser le nombre d’images prises par seconde (rappelons qu’une vidéo n’est autre qu’un enchainement de photos).

Dans la pratique il faudra faire les deux, surtout si vous souhaitez pouvoir visonner les images en passant par un mobile en 3G.

L’utilité de la vidéo par rapport aux photos

Un système de vidéo surveillance, ou de télé-surveillance, domestique doit selon moi, permettre deux choses :

  • voir en directe ce qui se passe à la maison à distance (Est ce que tout se passe bien à la maison ? Ai-je oublié d’éteindre mes lumières ?). Une photo prise régulièrement suffit.
  • avoir une trace d’un évènement qui s’est déroulé (Avoir des preuves d’un cambriolage ou d’un incendie, et pouvoir les utiliser pour l’enquête). Cela nécessite de stocker les images pendant un certain temps.

L’important, c’est d’avoir les images en temps réel, de pouvoir les stocker et les visonner facilement, sur place ou a distance. Dans ces conditions, nous pouvons nous satisfaire d’une photo par seconde, voire moins :) C’est exactement le principe du MJPEG qui est largement utilisé dans de nombreuses caméras IP. Le célèbre logiciel de détection de mouvement Motion, fonctionne également sur ce principe :)

Le gros avantage de la photo par rapport à la vidéo pour la télésurveillance

Demander à une caméra de prendre une photo à intervalles réguliers plutôt qu’une vidéo a également de nombreux avantages et permet grande souplesse d’utilisation :

  • entre chaque photo, votre caméra ou votre Raspberry Pi est disponible pour faire autre chose
  • une photo peu être prise et stockée en haute résolution puis facilement réduite pour être affichée à distance. On peut ainsi garder un historique des photos ou évènements en haute définition 1080p, et consulter avec son mobile en 3G une miniature de ces photos.
  • une photo prise, peut être immédiatement envoyée sur un serveur distant pour y être sauvegardée et archivée. Un voleur pourra saboter votre caméra, mais toutes les photos prises auront déjà été sauvegardée :)
  • il est très facile de détecter un mouvement en comparant deux photos :)
  • il est très facile de créer une vidéo à partir d’images qui se suivent :)

Nous allons maintenant voir comment créer notre système de télé-surveillance en commençant par son noeud central, le Raspberry Pi de « Contrôle » :)

Le Contrôleur

Pour réaliser ce « contrôleur« , vous pouvez utiliser n’importe quel Raspberry Pi (ou n’importe quel ordinateur d’ailleurs ;) ) relié à votre réseau, en WiFi ou Ethernet. Vous choisirez une carte mémoire en fonction du nombre de caméras dont vous disposez, de la qualité des images, et du nombre d’images que vous souhaitez conserver.

La première étape consiste à installer et configurer un serveur web Apache et PHP5. Je vous propose de suivre la procédure décrite dans cette article : PiHomeDashScreen – Installation et configuration. Ce serveur web servira à récupérer les images envoyées en HTTP POST et à diffuser l’interface web de visionnage.

Script de réception des images

Le principe est simple, les images seront envoyées en HTTP POST par les Raspberry Pi équipé d’une caméra, il nous suffit donc de créer un petit script en PHP pour les réceptionner.

collect.php :

<?php

$token    = 'azerty'; // token qui sert de mot de passe
$dst_dir  = 'camera'; // nom du dossier dans lequel seront stockées les images

if(isset($_REQUEST['token']) && $_REQUEST['token'] == $token){

  if(isset($_REQUEST['camera_name'])){

    $camera_name = $_REQUEST['camera_name'];  // nom de la caméra envoyé en même temps que l'image
    $img_name    = 'cam_'.$camera_name.'_'.time().'.jpg';   // nom du fichier image à stocker : prefixe, nom de la camera et timestamp

    if(!is_dir($dst_dir)){mkdir($dst_dir, 0777, true);}  // créé le répertoire de stockage s'il n'existe pas
    if(!is_dir($dst_dir.'/'.$camera_name)){mkdir($dst_dir.'/'.$camera_name, 0777, true);}  // créé un sous répertoire pour chaque caméra s'il n'existe pas

    if (is_uploaded_file($_FILES["camera_image"]["tmp_name"])) {
      move_uploaded_file($_FILES["camera_image"]["tmp_name"], $dst_dir.'/'.$camera_name.'/'.$img_name); // enregistre l'image réceptionnée dans le bon répertoire
    }
  }
}

?>

Pour visionner les images nous allons créer une page index.php qui affiche la dernière image de chaque caméra. Une fonction JavaScript se charge de raffraichir les images à intervalles réguliers :)

<?php

  header('Content-type: text/html; charset=utf-8');

  // nom du dossier dans lequel sont stockées les images
  $dst_dir  = 'camera';

  // liste des caméras à afficher
  $cameras = array('visioncam', 'egeon', 'carpo', 'triton');

  // taille d'affichage des images
  $width  = '640';
  $height = '480';

  // fonction qui renvoie la dernière image d'une caméra
  function showLastImage ($cam_name) {
    global $dst_dir;
    header('Content-type: image/jpeg');
    $dir  = $dst_dir."/".$cam_name."/cam_".$cam_name."_*";
    $imgs = glob($dir);
    echo new Imagick(end($imgs));
  }

  if(isset($_REQUEST['get_cam_img'])){
    echo showLastImage($_REQUEST['get_cam_img']);
  }
  else{

?>

  <!DOCTYPE html>
  <html>
    <head>
      <title>Cameras</title>
      <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
      <style>
        body { text-align : center; background-color : #000;}
        div.camera { display : inline-block; text-align : center; margin : 5px }
        img.camera { width : <?php echo $width; ?>px; height : <?php echo $height; ?>px; }
      </style>
    </head>
    <body>

      <?php foreach($cameras as $camera){ ?>
        <div class="camera" id="<?php echo $camera; ?>">
          <img class="camera" id="img_<?php echo $camera; ?>" src="">
        </div>
      <?php } ?>

      <script type="text/javascript" src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
      <script>
        var refresh = 3000;

        $( document ).ready(function() {
          setInterval(function() {
            var now = new Date().getTime();
            $("div.camera").each(function( index ) {
              var camera_name = $( this ).attr("id");
              console.log( "refresh "+camera_name+"..." );
              var url = 'index.php?get_cam_img='+camera_name;
              var img_tmp  = $("<img />").attr("src", url+"&"+now);
              $("#img_"+camera_name).attr("src", url+"&"+now);
            });
          }, refresh);
        });
      </script>

    </body>
  </html>

<?php } ?>

ATTENTION : De même que dans l’article « Contrôle de l’éclairage avec le module Z-Wave Razberry », le code source ci-dessus est créer dans le cadre d’un exemple simple, il peut et doit être optimisé et sécurisé :)

Si vous souhaitez avoir accès à cette application web depuis l’extérieur de votre réseau local, je vous conseille fortement de mettre en place un contrôle d’accès afin d’éviter que n’importe qui ne puisse visionner vos caméras et espionner votre maison :)

Dans un prochain article, je décortiquerai une installation complète et sécurisé à double authentification : certificat client et mot de passe.

En attendant, vous pouvez sécuriser l’accès à votre système en demandant un login/mot de passe grâce à un fichier .htacces comme expliqué dans ce tuto : http://www.commentcamarche.net/contents/7-apache-les-fichiers-htaccess

Voyons maintenant comment prendre des photos à intervalles réguliers et les envoyer au « contrôleur » :)

Prendre des photos et les envoyer au contrôleur

Sur chaque Raspberry Pi équipé d’une caméra, vous devrez exécuter le script camera_shot.sh suivant :

#!/bin/bash

camera_name="egeon"
dst_url="http://ip_controleur/collect.php"
refresh=5 # delais entre chaque photo

while true ; do
  img_tag=$camera_name" - "`date "+%Y-%m-%d %A %B %H:%M:%S"`
  img_name="cam_img.jpg"

  ##################################################################
  # POUR LES MODULES RASPBERRY PI CAMERA
  ##################################################################
  raspistill -t 1 -w 640 -h 480 -q 50 -o $img_name

  ##################################################################
  # POUR LES WEBCAMS USB
  ##################################################################
  streamer -c /dev/video0 -f jpeg -s 640x480 -j 50 -o $img_name".jpeg" && mv $img_name".jpeg" $img_name

  ##################################################################
  # POUR LES CAMERAS IP 
  # (le nom du script snapshot.cgi peut dependre du modele de camera)
  ##################################################################
  curl -o $img_name".jpeg" http://adresse_ip_camera/snapshot.cgi && mv $img_name".jpeg" $img_name

  ##################################################################

  if [ -f $img_name ] ; then
    convert -pointsize 15 -undercolor black -fill white -draw 'text 0,12 "'"$img_tag"'"' $img_name $img_name
    curl --form camera_image=@$img_name --form camera_name=$camera_name --form token=azerty $dst_url
    rm $img_name
  fi
  sleep $refresh
done

Vider l’historique des images sur le contrôleur

Si vous utilisez le système dans l’état les images vont s’entasser sur le contrôleur indéfiniment. A titre d’exemple, si vous prenez des photos en 640×480 px toutes les 5 secondes avec une moyenne de 30Ko par photo, cela représente environ 500Mo de données par jour et par caméra ! Avec mes quatre caméras, je génère donc près de 2Go de photo toutes les 24 heures :)

Il convient donc de supprimer les photos au bout d’un certain temps. Pour ma part je conserve un historique de 2 jours seulement.

Pour supprimer automatiquement les photos de plus de 2 jours, vous pouvez appeler ce script clean_cam.sh dans une CRON task :

#!/bin/bash

for i in `find /var/www/camera/* -type d` ; do
  find $i -type f -mtime +2 -exec rm -f {} \;
done

Vision de nuit

Si comme moi vous souhaitez profiter de la vision nocture que permet le module Raspberry Pi Camera NoIR, vous pouvez facilement construire un petit projecteur infrarouge grâce à quelques LED de ce type : LED IR 5mm 53Sf4Bt Kingbright

J’ai réalisé un petit montage qui se branche directement sur la broche 5V du GPIO du Pi :

IMG_6537Cela fonctionne bien mais sur une très courte distance (< 3 mètres). Il faudrait des LEDs beaucoup plus puissantes pour éclairer une grande pièce. Dans tous les cas, vous devrez choisir des LEDs infra rouge ayant une longueur d’onde autour des 880nm.

Pour les grandes pièces, ou la carrément éclairer votre jardin, vous pouvez utilisez un projecteur infra rouge spécialement prévu pour cet usage. J’ai pu en voir plusieur, et mon choix s’est arrêté sur celui ci :

IMG_6542Vous pourrez le trouvez ici : http://www.selectronic.fr/projecteur-infrarouge-50m.html

D’une grande qualité de fabrication, et équipé d’un détecteur de luminosité, ce projecteur étanche et alimenté en 12V éclairera sans problème votre jardin ou votre séjour :)

Avec le module Raspberry Pi Camera NoIR dans l’obscurité la plus totale, on y voit comme en plein jour :)

Très prochainement je publierai un article expliquant comment créer la caméra IP ultime à partir d’un Raspberry Pi. A suivre…

31 réflexions au sujet de « Système de vidéo-surveillance abordable avec des Raspberry Pi »

  1. Ping : Système de vidéo-surveillance abo...

  2. Damien Théraulaz

    Bonjour, merci bcp pour le tuto. Très sympa et intéressant. Je débute sur linux et c’est sympa. Malheureusement malgré les explications qui sont très bien, je n’arrive pas à répéter le tuto. Mon RPI-caméra prend bien les photos, mais le contrôleur ne reçoit rien du tout… je peine…. à l’aide.
    Dans collect.php y a t’il une subtilité dans

    dst_url= »http://ip_controleur/collect.php »

    c’est bien du style

    dst_url= »http://192.168.1.53/collect.php »

    merci de m’aider…

    Damien

    Répondre
    1. Olivier Auteur de l’article

      Hello,
      Merci pour tes encouragements :)
      Oui c’est bien cela qu’il faut faire au niveau de l’adresse IP.
      Est ce que tu arrive à atteindre le collect.php à partir d’un navigateur ?

      Répondre
  3. Damien Théraulaz

    Re bonjour, j’avance avec le tuto. Je peux prendre les photos sur la camera et envoyer sur collect php. J’ai dû modifier le dossier de réception
    $dst_dir = ‘camera';
    en
    $dst_dir = ‘/var/www/camera';
    je reçoit correctement les fichiers dans un dossier « egeon » dans « camera ». (j’ai laissé les mêmes noms pour l’instant).
    Mon énorme problème est le script de index.php. lorsque je rentre l’adresse ip sur mon navigateur, je tombe sur la page index avec les emplacements des photos mais rien ne se passe.
    j’ai bien installé apache et php comme dans l’autre tutorial. mais rien à faire…
    j’y ai passé des heures et rien ne marche, à l’aide!

    Damien

    Répondre
    1. Olivier Auteur de l’article

      Hello,
      Si tu as laisser la conf Apache par défaut, le script index.php doit se placer dans le répertoire /var/www/default/.
      Est ce bien le cas ?

      Répondre
  4. Romain

    Bonjour,

    Super tuto! J’aime bien cette vision cerveau/capteurs et prendre des photos plutôt que du film.

    Cependant j’ai un petit soucis :
    Tout fonctionne sauf l’affichage des images. J’ai bien ma page mais elle est noire avec une icône d’image absente.
    Il ne rentre pas dans la fonction :
    $( document ).ready(function() {
    setInterval(function() {
    var now = new Date().getTime();
    $(« div.camera »).each(function( index ) {
    var camera_name = $( this ).attr(« id »);
    console.log( « refresh « +camera_name+ »… » );
    var url = ‘index.php?get_cam_img=’+camera_name;
    var img_tmp = $(«  »).attr(« src », url+ »& »+now);
    $(« #img_ »+camera_name).attr(« src », url+ »& »+now);
    });
    }, refresh);
    });

    J’ai pourtant testé pas mal de trucs, j’ai mis des points d’arrêts un peu partout pour voir mais rien a faire il rentre pas dans cette partie du javascript.
    J’ai aussi essayer un :

    en créant le fichier jquery-1.11.0.min.js à partir de la source.

    Une idée?
    Cordialement.

    Romain.

    Répondre
    1. Olivier Auteur de l’article

      Hello,
      Est ce que tu arrives à afficher directement les images dans une balise HTML sans passer par la fonction JavaScript ?

      Répondre
        1. Olivier Auteur de l’article

          You may install the FireBug plugin for you web browser in order to get further information in the javascript console debug

          Répondre
      1. Alex

        Ok fixed it! :-)

        The class= »camera » was missing in the index.php script!
        old: <div id=" »>
        new: <div class="camera" id=" »>

        Répondre
  5. Alex

    For the Imagick class you need to do the following:

    apt-get install php5-imagick
    edit php.ini and add extension=imagick.so

    However I can’t get the Jquery refresh to work…

    Any help is appreciated.

    Répondre
    1. Olivier Auteur de l’article

      Exactly, you need to install the php5-imagick package in order to get things run correctly :)

      What is your issue with the JQuery refresh ? You may install the FireBug plugin for you web browser in order to get console debug information :)

      Répondre
  6. Ping : Surveillance | Pearltrees

  7. Bob

    Hello.Will you be producing any scripts to enable « Motion » detection and email / telephone warnings. As you have in other projects? Thanks for the information already posted. I’m enjoying getting things to work.

    Répondre
    1. Olivier Auteur de l’article

      Hi Bob,
      I may publish a new article for these functionnalities soon :)

      Répondre
  8. Cédric

    Bon article (comme les autres)
    C’est intéressant car ca consommera moins qu’un motion sur le Raspberry juste pour avoir accès à la camera. En plus personnellement vu que les RPi font tourner squeezelite aussi, motion consomme pas mal de cpu et bande passante par moment. Là c’est l’idéal l’envoi en central des photos pour traitement centralisé.

    As-tu des pistes sur ce qui serait utilisable pour faire la reconnaissance de mouvement en central avec peut être une sauvegarde dans un autre répertoire ? OpenCV ?

    Répondre
    1. Olivier Auteur de l’article

      Hello,
      Oui OpenCV est une bonne solution, mais un peu « usine à gaz » à mon goût :P Et puis je préfère toujours faire les choses par moi même lorsque c’est possible, pour que cela colle parfaitement avec ce que j’attends :P Je pense donc utiliser la fonction compre de ImageMagick pour commencer :)

      Répondre
  9. marc78

    Sympa ce tuto, merci Olivier!
    J’ai un soucis avec camera_shot.sh. Le fichier image est totalement noir et la console me renvoie l’erreur « convert : commande introuvable ».
    J’ai l’installation de base de Raspbian. Olivier pourrais-tu ajouter à ce tuto les installations complémentaires à réaliser afin de les faire toutes en même temps et non au fil des erreurs. Cela aiderait bien les newbiz comme moi!
    Merci

    Répondre
  10. marc78

    Bonsoir,
    J’ai enfin réussi à faire fonctionner la commande convert. Visiblement ma première installation ne c’était pas bien passée.
    Les photos sont prises mais je ne comprends pas, elles sont totalement noir avec le nom de la camera, la date et l’heure mais noir.
    Là, je séche si quelqu’un peut me donner un coupe de main. (il n’y a rien devant la camera et il y a de la lumiére ;o) )
    Merci

    Répondre
  11. marcel6566

    Bonsoir
    J’ai suivi ton tuto. Pas de problème.
    Cependant je ne comprends pas comment tu relies la camera IP Haden.
    Est ce qu’elle est reliée directement au RPi (traitement par motion), ou est ce que tu passes par la liaison wifi/IP ? Dans le dernier cas comment récupérer les images ?
    Merci par avance.

    Répondre
    1. Olivier Auteur de l’article

      Hello,
      La caméra Heden est une caméra IP, il convient donc d’utiliser la partie du script qui correspond à ce type de caméra :

      ##################################################################
      # POUR LES CAMERAS IP
      # (le nom du script snapshot.cgi peut dependre du modele de camera)
      ##################################################################
      curl -o $img_name".jpeg" http://adresse_ip_camera/snapshot.cgi && mv $img_name".jpeg" $img_name

      Répondre
  12. chassotce

    Hello,
    J’ai un souci, j’ai la camera noir (pi). Cependant il me met toujours l’erreur :
    mmal: mmal_vc_component_enable: failed to enable component: ENOSPC
    mmal: camera component couldn’t be enabled
    mmal: main: Failed to create camera component
    mmal: Failed to run camera app. Please check for firmware updates

    Aucune solution trouvée sur le net n’a régler mon soucis, as-tu été confronter à ce soucis ?

    Merci pour le tuto dans tout les cas =)

    Répondre
  13. Ping : Video | mes-notes

  14. Micsec

    bonjour
    solution vraiment intéressante.
    Une petite question : j’ai l’intention de ne mettre qu’une seule caméra.
    Puis-je mettre dans le même Raspberry la fonction caméra et la fonction Controle ?
    Ou bien est-il nécessaire d’appliquer la méthode décrite : 1 x RPi Caméra ET 1 x RPi Controle ?
    Merci

    Répondre

Laisser un commentaire