Site : tvaira.free.fr

Mise en oeuvre réseau de la caméra IP

La caméra IP Wanscam JW0008

La caméra IP Wanscam JW0008

Mise en oeuvre

Présentation

La caméra IP Wanscam est conçue pour être installée en intérieur. Elle peut être reliée via un câble réseau Ethernet RJ45 ou sans fil en WiFi B/G/N.

Ses caractèristiques principales sont :

Attention : ne jamais tourner la caméra à la main, cela pourrait endommager son mécanisme.

Retour au sommaire

Branchement de la caméra

Lors de son démarrage, la caméra s’est autoconfigurée avec une adresse IP fournie par un serveur DHCP présent sur votre réseau.

La caméra est utilisable et administrable à partir d’un navigateur web.

Remarque : Suivant les modèles, le port par défaut de la caméra est 99 (ou 81).

L’accès se fait via http://ip-de-la-camera:99/ avec le compte admin sans mot de passe.

Retour au sommaire

Tests

Il est conseillé de lire la documentation qui précise l’exploitation des programmes CGI.

CGI (Common Gateway Interface) est une interface utilisée par les serveurs HTTP. Elle a été normalisée par la RFC 3875. Au lieu d’envoyer le contenu d’un fichier (fichier HTML, image), le serveur HTTP exécute un programme, puis retourne le contenu généré. CGI est le standard industriel qui indique comment transmettre la requête du serveur HTTP au programme, et comment récupérer la réponse générée. Une des caractéristiques de l’interface CGI est d’être indépendante de tout langage de programmation, car elle utilise les flux standard et les variables d’environnement. Même si le langage Perl a historiquement été souvent utilisé pour en écrire, il est possible d’écrire un programme CGI en C, Python, PHP, script shell, en VB ou en tout autre langage de programmation.

Retour au sommaire

Informations

var alias="IPCAM"; 
var deviceid="JWEV-182544-CFCFF"; 
var sys_ver="67.2.2.158"; 
var now=1439042444; 
var alarm_status=0; 
var upnp_status=1; 
var dnsenable=0; 
var osdenable=0; 
var syswifi_mode=1; 
var mac="00:D1:13:11:36:ED"; 
var wifimac="00:D1:13:11:36:EE"; 
var dns_status=0; 
var authuser=0; 
var devicetype=21037151; 
var devicesubtype=0; 
var externwifi=1; 
var record_sd_status=0; 
var sdtotal=0; var sdfree=0; 
var resolution=0; 
var vbright=1; 
var vcontrast=128; 
var vhue=64; 
var vsaturation=80; 
var OSDEnable=0; 
var mode=0; 
var flip=0; 
var enc_framerate=30; 
var sub_enc_framerate=15; 
var speed=10; 
var enc_bitrate=2048; 
var ircut=1; 
var now1=1439042914; 
var tz=-28800; 
var ntp_enable=1; 
var ntp_svr="time.nist.gov"; 
var dhcpen=1; 
var ip="192.168.52.14"; 
var mask="255.255.255.0"; 
var gateway="192.168.52.1"; 
var dns1="8.8.8.8"; 
var dns2="192.168.52.1"; 
var port=99; 
var dev2_host="192.168.1.111"; 
var dev2_alias="IPCAM"; 
var dev2_user="ipc"; 
var dev2_pwd=""; 
var dev2_port=99; 
...
var user1_name=""; 
var user1_pwd=""; 
...
var wifi_enable=1; 
var wifi_ssid="wanscam_office"; 
var wifi_mode=0; 
var wifi_encrypt=0; 
var wifi_authtype=4; 
var wifi_defkey=0; 
var wifi_keyformat=0; 
var wifi_key1=""; 
var wifi_key2=""; 
var wifi_key3=""; 
var wifi_key4=""; 
var wifi_key1_bits=0; 
var wifi_key2_bits=0; 
var wifi_key3_bits=0; 
var wifi_key4_bits=0; 
var wifi_wpa_psk="88888888"; 
var wifi_channel=0; 
var pppoe_enable=0; 
var pppoe_user=""; 
var pppoe_pwd=""; 
var upnp_enable=1; 
var ddns_service=0; 
var ddns_proxy_svr="http://ipcpnp.com/upgengxin.asp"; 
var ddns_host=""; 
var ddns_user=""; 
var ddns_pwd=""; 
var ddns_proxy_port=80; 
var ddns_mode=1; 
var ddns_status=0; 
var mail_sender=""; 
var mail_receiver1=""; 
...
var mailssl=0; 
var mail_svr=""; 
var mail_user=""; 
var mail_pwd=""; 
var mail_port=0; 
var mail_inet_ip=0; 
var ftp_svr=""; 
var ftp_user=""; 
var ftp_pwd=""; 
var ftp_dir=""; 
var ftp_port=0; 
var ftp_mode=0; 
var ftp_upload_interval=0; 
var ftp_filename=7383708; 
var alarm_motion_armed=0; 
var alarm_motion_sensitivity=0; 
var alarm_input_armed=0; 
var alarm_ioin_level=0; 
var alarm_mail=0; 
var alarm_iolinkage=0; 
var alarm_ioout_level=0; 
var alarm_upload_interval=0; 
var alarm_presetsit=0; 
var alarm_snapshot=0; 
var alarm_record=0; 
var alarm_schedule_enable=0; 
var alarm_http=0; 
var alarm_http_url=""; 
var alarm_schedule_sun_0=0; 
var alarm_schedule_sun_1=0; 
var alarm_schedule_sun_2=0; 
var alarm_schedule_mon_0=0; 
var alarm_schedule_mon_1=0; 
var alarm_schedule_mon_2=0; 
var alarm_schedule_tue_0=0; 
var alarm_schedule_tue_1=0; 
var alarm_schedule_tue_2=0; 
var alarm_schedule_wed_0=0; 
var alarm_schedule_wed_1=0; 
var alarm_schedule_wed_2=0; 
var alarm_schedule_thu_0=0; 
var alarm_schedule_thu_1=0; 
var alarm_schedule_thu_2=0; 
var alarm_schedule_fri_0=0; 
var alarm_schedule_fri_1=0; 
var alarm_schedule_fri_2=0; 
var alarm_schedule_sat_0=0; 
var alarm_schedule_sat_1=0; 
var alarm_schedule_sat_2=0; 

Retour au sommaire

Photo et vidéo

Retour au sommaire

Commandes de déplacement

Retour au sommaire

OpenCV

Présentation

OpenCV (Open Computer Vision) est une bibliothèque graphique libre, initialement développée par Intel, spécialisée dans le traitement d’images en temps réel. Cette bibliothèque est distribuée sous licence BSD.

La bibliothèque OpenCV met à disposition de nombreuses fonctionnalités très diversifiées permettant de créer des programmes partant des données brutes pour aller jusqu’à la création d’interfaces graphiques basiques. Elle propose la plupart des opérations classiques en traitement bas niveau des images et des vidéos. Cette bibliothèque s’est imposée comme un standard dans le domaine de la recherche parce qu’elle propose un nombre important d’outils issus de l’état de l’art en vision des ordinateurs.

La documentation d’OpenCV (cf. OpenCV API Reference).

Retour au sommaire

Installation (Ubuntu 12.04)

Pour installer les bibliothèques de développement d’OpenCV, il faudra faire :

$ sudo apt-get install libopencv-dev

Les options de compilation seront :

$ pkg-config --cflags --libs opencv
-I/usr/include/opencv  -lopencv_core -lopencv_imgproc -lopencv_highgui -lopencv_ml -lopencv_video 
-lopencv_features2d -lopencv_calib3d -lopencv_objdetect -lopencv_contrib -lopencv_legacy -lopencv_flann

Retour au sommaire

Exemple en C

OpenCV fournit une API C pour l’acquisition vidéo en provenance d’une caméra ou d’un fichier. En C, on utilisera donc les appels cvCaptureFromCAM() ou cvCaptureFromFile() qui retournent un pointeur sur une structure CvCapture. En fin de programme, il ne faudra pas oublier de le libérer en appelant cvReleaseCapture().

Dans notre cas, la caméra n’étant raccordée physiquement à l’ordinateur, on ne pourra pas utiliser l’appel cvCaptureFromCAM(). En effet, on accéde au flux vidéo via un script CGI par le réseau. On doit donc utiliser l’appel cvCaptureFromFile(). OpenCV détecte le type des données image par l’extension du fichier. La documentation de la caméra nous informe que le format des données vidéos est du type MJPEG. Au final, il faudra donc passer en paramètre de l’appel cvCaptureFromFile() : l’adresse (adresse-ip-camera:99) qui pointe vers le script CGI (c’est-à-dire videostream.cgi) fournissant les données vidéos ET l’extension .mjpg, soit :

"http://adresse-ip-camera:99/videostream.cgi?user=admin&pwd=&resolution=32&rate=0&.mjpg"

Pour réaliser une ‘capture’, l’API C met à notre disposition 3 fonctions :

Pour l’affichage, on utilisera l’appel cvNamedWindow() pour créer une fenêtre et cvShowImage() pour visualiser l’image (frame). Opencv fournit aussi des fonctions pour sauvegarder les images comme cvSaveImage().

cf. la documentation de l’API sur docs.opencv.org.

#include <stdio.h>
#include <cv.h> // contient les déclarations des structures et fonctions de manipulation d'images
#include <highgui.h> // contient déclarations des fonctions d'affichage des images

#define DEBUG

// gcc -O2 -Wall -o opencv-0 opencv-0.c `pkg-config --cflags --libs opencv`

int main(int argc, char *argv[])
{
    // cf. http://docs.opencv.org/modules/highgui/doc/reading_and_writing_images_and_video.html#videocapture
    CvCapture *capture = cvCaptureFromFile("http://192.168.52.14:99/videostream.cgi?user=admin&pwd=&resolution=32&rate=0&.mjpg");
    if(!capture)
    {
        printf("Erreur d'initialisation !\n");
        exit(1);
    }

    //cvNamedWindow("Wanscam");
    cvNamedWindow("Wanscam", CV_WINDOW_AUTOSIZE);

    while(1)
    {    
        #ifdef DEBUG
        double t1 = (double)cvGetTickCount();
        #endif

        // Méthode 1 :
        /*if(!cvGrabFrame(capture))
        {
            printf("Erreur d'acquisition !\n");
            exit(1);
        }
        IplImage *img = cvRetrieveFrame(capture);*/

        // Méthode 2 :
        IplImage *img = cvQueryFrame(capture);
        if(img == NULL)
        {
            printf("Erreur de lecture !\n");
            exit(1);
        }

        #ifdef DEBUG
        printf("%dx%d pixels (%d canaux couleurs)\n", img->width, img->height, img->nChannels); 
        double t2 = (double)cvGetTickCount();
        printf("time: %gms  fps: %.2g\n", (t2-t1)/(cvGetTickFrequency()*1000.), 1000./((t2-t1)/(cvGetTickFrequency()*1000.)));
        #endif    

        cvShowImage("Wanscam", img);

        // Si on veut sauvegarder l'image
        //cvSaveImage("foo.jpg", img);

        //cvReleaseImage(&img);

        // Appuyez sur une touche pour sortir
        if(cvWaitKey(0) >= 0) break;
    }    

    cvReleaseCapture(&capture);

    return 0;
}

Le source de l’exemple C.

Retour au sommaire

Exemple en C++

En C++, OpenCV fournit une classe VideoCapture pour l’acquisition vidéo en provenance d’une caméra ou d’un fichier. On utilisera la méthode open() pour ouvrir le flux vidéo de la caméra.

Pour rappel, on accéde au flux vidéo via un script CGI par le réseau. OpenCV détecte le type des données image par l’extension du fichier. La documentation de la caméra nous informe que le format des données vidéos est du type MJPEG. Au final, il faudra donc passer en paramètre de l’appel open() : l’adresse (adresse-ip-camera:99) qui pointe vers le script CGI (c’est-à-dire videostream.cgi) fournissant les données vidéos ET l’extension .mjpg, soit :

"http://adresse-ip-camera:99/videostream.cgi?user=admin&pwd=&resolution=32&rate=0&.mjpg"

Pour réaliser une ‘capture’, l’API C++ met à notre disposition 3 méthodes :

Pour manipuler des images, OpenCV utilise une classe Mat (cf. cv::Mat).

Pour l’affichage des images, on utilisera la méthode cv::imshow(). Opencv fournit aussi des méthodes pour lire des images comme imread() et pour les sa uvegarder avec imwrite().

cf. la documentation de l’API sur docs.opencv.org.

#include <iostream>
#include <cv.h> // contient les déclarations des classes de manipulation d'images
#include <highgui.h> // contient déclarations des fonctions d'affichage des images

#define DEBUG

using namespace cv;
using namespace std;

// g++ -o opencv-1 opencv-1.cpp `pkg-config --cflags --libs opencv`

int main(int, char**) 
{
    VideoCapture capture;
    Mat img;

    const string adresseFluxVideo = "http://192.168.52.14:99/videostream.cgi?user=admin&pwd=&resolution=32&rate=0&.mjpg"; 

    if(!capture.open(adresseFluxVideo)) 
    {
        cout << "Erreur d'initialisation !" << endl;
        return 1;
    }

    #ifdef DEBUG
    double dWidth = capture.get(CV_CAP_PROP_FRAME_WIDTH);
    double dHeight = capture.get(CV_CAP_PROP_FRAME_HEIGHT);
    cout << dWidth << " x " << dHeight << endl;
    #endif    

    //namedWindow("Wanscam");
    namedWindow("Wanscam", CV_WINDOW_AUTOSIZE);

    while(1)
    {            
        // Méthode 1 :
        /*if(!capture.grab())
        {
            cout << "Erreur d'acquisition !" << endl;            
            exit(1);
        }
        if(!capture.retrieve(img))
        {
            cout << "Erreur de récupération !" << endl;            
            exit(1);
        }*/

        // Méthode 2 :
        if(!capture.read(img)) 
        {
            cout << "Erreur de lecture !" << endl;
            return 1;
        }

        imshow("Wanscam", img);

        // Si on veut sauvegarder l'image
        //imwrite("foo.jpg", img);

        // Appuyez sur une touche pour sortir
        if(cv::waitKey(0) >= 0) break;
    }       

    return 0;
}

OpenCV fournit de très nombreuses fonctionnalités. Voici un exemple de deux transformations possibles sur des objets image de type Mat :

// ...

namedWindow("Flip", CV_WINDOW_AUTOSIZE);
namedWindow("Negative", CV_WINDOW_AUTOSIZE);

while(1)
{
    // ...
    flip(img, img, 1);
    imshow("Flip", img);

    Mat gray, edge, draw;
    cvtColor(img, gray, CV_BGR2GRAY); 
    Canny(gray, edge, 50, 150, 3); 
    edge.convertTo(draw, CV_8U);
    imshow("Negative", draw);        

    // ...
}

// ...

Le source de l’exemple C++.

Retour au sommaire

Exemple en Qt

Sous Qt, on utilisera un objet QLabel et un objet QImage pour assurer l’affichage des frames dans l’IHM. Le principe est le suivant :

QLabel *imageLabel = new QLabel;
imageLabel->setBackgroundRole(QPalette::Base);

QImage image("vide.png");
imageLabel->setPixmap(QPixmap::fromImage(image));
imageLabel->resize(imageLabel->pixmap()->size());

On utilise le code C++ ci-dessus (voir Exemple en C++) que l’on adapte à Qt pour la capture. À partir d’une frame de type Mat ou IplImage, il faut pouvoir la convertir dans un type Qt (ici QImage ). Pour cela, on va se servir de la méthode Ipl2QImage() qui permet de convertir une image OpenCV de type IplImage vers une image Qt de type QImage.

Mat frame;

// capture de la frame (voir plus haut) ... puis :
IplImage *img = new IplImage(frame);

QImage image = Ipl2QImage(img);
imageLabel->setPixmap(QPixmap::fromImage(image));
imageLabel->resize(imageLabel->pixmap()->size());

Pour la gestion de la caméra, on peut prendre un objet QNetworkAccessManager et sa méthode get() pour accéder aux scripts CGI de la caméra. Voici le principe pour la commande flip :

class X : public QWidget
{
    Q_OBJECT

public:
    X( QWidget *parent = 0 );
    ~X();

private:
    QNetworkAccessManager *manager;
    QNetworkReply         *reply;    
    //...
    QTextEdit             *journal;

public slots:    
    void flip();
    void replyFinished(QNetworkReply *reply);    
    //...
};

X::X( QWidget *parent ) : QWidget( parent )
{
    // ...
    manager = new QNetworkAccessManager(this);
    connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
}

void X::flip()
{
    //QString URL = "http://" + adresseIP + ":" + QString::number(port) + "/camera_control.cgi?param=5&value=1" + "&user=" + user + "&pwd=" + pwd;
    QString URL = "http://192.168.52.14:99/camera_control.cgi?param=5&value=1&user=admin&pwd=";
    manager->get(QNetworkRequest(QUrl(URL)));
}

void X::noflip()
{
    //QString URL = "http://" + adresseIP + ":" + QString::number(port) + "/camera_control.cgi?param=5&value=0" + "&user=" + user + "&pwd=" + pwd;
    QString URL = "http://192.168.52.14:99/camera_control.cgi?param=5&value=0&user=admin&pwd=";
    manager->get(QNetworkRequest(QUrl(URL)));
}

void X::replyFinished(QNetworkReply *reply)
{
    QByteArray datas = reply->readAll();
    qDebug() << QString::fromUtf8("<X::replyFinished()> reply : ") << datas;

    QString infos(datas);
    journal->append(infos);
}    

Le source de l’exemple Qt.

Retour au sommaire