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 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.
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.
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.
http://ip-de-la-camera:99/get_status.cgi?user=admin&pwd=
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;
http://ip-de-la-camera:99/get_camera_params.cgi?user=admin&pwd=
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;
http://ip-de-la-camera:99/get_params.cgi?user=admin&pwd=
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;
http://ip-de-la-camera:99/get_log.cgi?user=admin&pwd=
Photo : http://ip-de-la-camera:99/snapshot.cgi
Vidéo : http://ip-de-la-camera:99/videostream.cgi?user=admin&pwd=&resolution=32&rate=0
Monter : http://adresse-ip-camera:99/decoder_control.cgi?command=0&onestep=1&user=admin&pwd=
Descendre : http://adresse-ip-camera:99/decoder_control.cgi?command=2&onestep=1&user=admin&pwd=
Gauche : http://adresse-ip-camera:99/decoder_control.cgi?command=4&onestep=1&user=admin&pwd=
Droite : http://adresse-ip-camera:99/decoder_control.cgi?command=6&onestep=1&user=admin&pwd=
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).
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
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 :
int cvGrabFrame(CvCapture* capture)
qui réalise l’acquisition de la prochaine image (frame) du fichier vidéo ou de la caméra et renvoie vrai (non nul) en cas de succès.IplImage* cvRetrieveFrame(CvCapture* capture, int streamIdx=0)
qui décode et renvoie l’image (frame) précedemment acquise (grab). Si il n’y a aucune image (caméra déconnectée, ou plus d’images dans le fichier vidéo), la fonction retourne un pointeur NULL
.IplImage* cvQueryFrame(CvCapture* capture)
qui regroupe les 2 fonctions précédentes (cvGrabFrame()
et cvRetrieveFrame()
) en un seul appel ce qui la rend plus pratique.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.
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 :
bool VideoCapture::grab()
qui réalise l’acquisition de la prochaine image (frame) du fichier vidéo ou de la caméra et renvoie vrai (true
) en cas de succès.bool VideoCapture::retrieve(Mat& image, int channel=0)
qui décode et renvoie l’image (frame) précedemment acquise (grab). Si il n’y a aucune image (caméra déconnectée, ou plus d’images dans le fichier vidéo), la fonction retourne faux (false
).bool VideoCapture::read(Mat& image)
qui regroupe les 2 fonctions précédentes (cvGrabFrame()
et cvRetrieveFrame()
) en un seul appel ce qui la rend plus pratique. L’opérateur >>
peut aussi être utilisé.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++.
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.