Capture vidéo avec OpenCV


Version PDF de ce document : activite-qt-opencv.pdf


OpenCV

OpenCV (Open Computer Vision) est une bibliothèque libre d’analyse d’images et de vision par ordinateur en langage C/C++, initialement développée par Intel, spécialisée dans le traitement d’images en temps réel. Cette bibliothèque libre 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).

Installation (Ubuntu)

Lien : OpenCV sous Ubuntu

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

$ sudo apt-get install libopencv-dev

C’est la version 3.2 qui sera installée sur une Ubuntu 18.04 :

$ dpkg -l | grep opencv | tr -s ' '
ii libopencv-calib3d-dev:amd64 3.2.0+dfsg-4ubuntu0.1 amd64 development files for libopencv-calib3d3.2
ii libopencv-calib3d3.2:amd64 3.2.0+dfsg-4ubuntu0.1 amd64 computer vision Camera Calibration library
ii libopencv-contrib-dev:amd64 3.2.0+dfsg-4ubuntu0.1 amd64 development files for libopencv-contrib3.2
ii libopencv-contrib3.2:amd64 3.2.0+dfsg-4ubuntu0.1 amd64 computer vision contrlib library
ii libopencv-core-dev:amd64 3.2.0+dfsg-4ubuntu0.1 amd64 development files for libopencv-core3.2
ii libopencv-core3.2:amd64 3.2.0+dfsg-4ubuntu0.1 amd64 computer vision core library
ii libopencv-dev 3.2.0+dfsg-4ubuntu0.1 amd64 development files for opencv
...

Et la version 2.4 sur une Ubuntu 16.04 :

$ dpkg -l | grep opencv | tr -s ' '
ii libopencv-calib3d-dev:amd64 2.4.9.1+dfsg-1.5ubuntu1.1 amd64 development files for libopencv-calib3d
ii libopencv-calib3d2.4v5:amd64 2.4.9.1+dfsg-1.5ubuntu1.1 amd64 computer vision Camera Calibration library
ii libopencv-contrib-dev:amd64 2.4.9.1+dfsg-1.5ubuntu1.1 amd64 development files for libopencv-contrib
ii libopencv-contrib2.4v5:amd64 2.4.9.1+dfsg-1.5ubuntu1.1 amd64 computer vision contrib library
ii libopencv-core-dev:amd64 2.4.9.1+dfsg-1.5ubuntu1.1 amd64 development files for libopencv-core
ii libopencv-core2.4v5:amd64 2.4.9.1+dfsg-1.5ubuntu1.1 amd64 computer vision core library
ii libopencv-dev 2.4.9.1+dfsg-1.5ubuntu1.1 amd64 development files for opencv

Les options de compilation seront :

  • Ubuntu 18.04 :
$ pkg-config --cflags --libs opencv
-I/usr/include/opencv -lopencv_shape -lopencv_stitching -lopencv_superres -lopencv_videostab -lopencv_aruco -lopencv_bgsegm -lopencv_bioinspired -lopencv_ccalib -lopencv_datasets -lopencv_dpm -lopencv_face -lopencv_freetype -lopencv_fuzzy -lopencv_hdf -lopencv_line_descriptor -lopencv_optflow -lopencv_video -lopencv_plot -lopencv_reg -lopencv_saliency -lopencv_stereo -lopencv_structured_light -lopencv_phase_unwrapping -lopencv_rgbd -lopencv_viz -lopencv_surface_matching -lopencv_text -lopencv_ximgproc -lopencv_calib3d -lopencv_features2d -lopencv_flann -lopencv_xobjdetect -lopencv_objdetect -lopencv_ml -lopencv_xphoto -lopencv_highgui -lopencv_videoio -lopencv_imgcodecs -lopencv_photo -lopencv_imgproc -lopencv_core
  • Ubuntu 16.04 :
$ pkg-config --cflags --libs opencv
-I/usr/include/opencv -lopencv_calib3d -lopencv_contrib -lopencv_core -lopencv_features2d -lopencv_flann -lopencv_gpu -lopencv_highgui -lopencv_imgproc -lopencv_legacy -lopencv_ml -lopencv_objdetect -lopencv_ocl -lopencv_photo -lopencv_stitching -lopencv_superres -lopencv_ts  -lopencv_video  -lopencv_videostab

Les fichiers d’en-têtes sont installées dans les répertoires /usr/include/opencv et /usr/include/opencv2 :

$ ls -l /usr/include/opencv
total 44
-rw-r--r-- 1 root root 2523 mai   12  2017 cvaux.h
-rw-r--r-- 1 root root 2374 mai   12  2017 cvaux.hpp
-rw-r--r-- 1 root root 3153 mai   12  2017 cv.h
-rw-r--r-- 1 root root 2649 mai   12  2017 cv.hpp
-rw-r--r-- 1 root root 2176 mai   12  2017 cvwimage.h
-rw-r--r-- 1 root root 2424 mai   12  2017 cxcore.h
-rw-r--r-- 1 root root 2443 mai   12  2017 cxcore.hpp
-rw-r--r-- 1 root root 2257 mai   12  2017 cxeigen.hpp
-rw-r--r-- 1 root root  129 mai   12  2017 cxmisc.h
-rw-r--r-- 1 root root 2226 mai   12  2017 highgui.h
-rw-r--r-- 1 root root 2145 mai   12  2017 ml.h

$ ls -l /usr/include/opencv2
...

On ajoutera l’installation de Video4Linux pour la prise en charge des périphériques caméras :

$ sudo apt-get install libv4l-dev v4l-utils

L’utilitaire v4l2-ctl permet de contrôler les périphériques Video4Linux :

$ v4l2-ctl --list-device
USB 2.0 Camera: HD USB Camera (usb-0000:00:14.0-2):
    /dev/video0

$ v4l2-ctl --all
...

$ v4l2-ctl -d 0 --list-formats-ext
ioctl: VIDIOC_ENUM_FMT
    Index       : 0
    Type        : Video Capture
    Pixel Format: 'MJPG' (compressed)
    Name        : Motion-JPEG
        Size: Discrete 1600x1200
            Interval: Discrete 0.067s (15.000 fps)
        Size: Discrete 2592x1944
            Interval: Discrete 0.067s (15.000 fps)
        Size: Discrete 2048x1536
            Interval: Discrete 0.067s (15.000 fps)
        Size: Discrete 1920x1080
            Interval: Discrete 0.033s (30.000 fps)
        Size: Discrete 1280x1024
            Interval: Discrete 0.067s (15.000 fps)
        Size: Discrete 1280x720
            Interval: Discrete 0.033s (30.000 fps)
        Size: Discrete 1024x768
            Interval: Discrete 0.033s (30.000 fps)
        Size: Discrete 800x600
            Interval: Discrete 0.033s (30.000 fps)
        Size: Discrete 640x480
            Interval: Discrete 0.033s (30.000 fps)
        Size: Discrete 1600x1200
            Interval: Discrete 0.067s (15.000 fps)

    Index       : 1
    Type        : Video Capture
    Pixel Format: 'YUYV'
    Name        : YUYV 4:2:2
        Size: Discrete 1600x1200
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 2592x1944
            Interval: Discrete 0.333s (3.000 fps)
        Size: Discrete 2048x1536
            Interval: Discrete 0.250s (4.000 fps)
        Size: Discrete 1920x1080
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 1280x1024
            Interval: Discrete 0.111s (9.000 fps)
        Size: Discrete 1280x720
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 1024x768
            Interval: Discrete 0.100s (10.000 fps)
        Size: Discrete 800x600
            Interval: Discrete 0.050s (20.000 fps)
        Size: Discrete 640x480
            Interval: Discrete 0.033s (30.000 fps)
        Size: Discrete 1600x1200
            Interval: Discrete 0.200s (5.000 fps)

$ v4l2-ctl -d 0 --list-formats-ext | grep -E "Size" | tr -s ' ' | cut -d ' ' -f 3 | sort | uniq | sed 's/^\s*//'
1024x768
1280x1024
1280x720
1600x1200
1920x1080
2048x1536
2592x1944
640x480
800x600

API 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().

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.

Quelques activités sur OpenCV : Mise en oeuvre d’OpenCV ou aussi

API 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 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.

Quelques activités sur OpenCV : Mise en oeuvre d’OpenCV ou aussi

OpenCV et Qt5

Acquisition

Ici, il faut assurer l’acquisition périodique d’images dans une application GUI. L’acquisition nécessite de faire une boucle pour capturer les images ce qui bloquerait le thread principal GUI.

Une approche simpliste serait d’appeler processEvents() dans la boucle d’acquisition pour continuer à traiter les événements au niveau de la GUI.

Une meilleure solution serait de réaliser la partie acquisition d’images dans un thread séparé.

On va créer une classe TAcquisitionVideo qui héritera de la classe QThread :

class TAcquisitionVideo : public QThread
{
   Q_OBJECT
   public:
      TAcquisitionVideo();
      ~TAcquisitionVideo();

      void run();
      
      void getProprietes(const VideoCapture &camera) const;
      void setProprietes(VideoCapture &camera);
      void setResolution(int resolution);
      void setBrightness(double brightness);
      void setContrast(double contrast);
      void setSaturation(double saturation);

   private:
      int resolution;
      double brightness;
      double contrast;
      double saturation;
      bool change;

   signals:
      void nouvelleFrame(Mat frame);
      void nouvelleImage(QImage image);
      void nouvelleImage(QPixmap pixmap);
      void nouveauMessage(QString message);

   public slots:
      
};

La classe VideoCapture d’OpenCV fournit des méthodes get() et set() permettant successivement d’obtenir ou de régler certains paramétres de la caméra (résolution, luminosité, contraste, saturation, …).

On ajoute aussi des signaux qui permettront de communiquer avec l’IHM. L’“image” capturée par OpenCV est fournie sous la forme d’un type Mat. Il faudra pour l’afficher la convertir en type Qt : QImage et QPixmap. Le choix dépendra de l’usage qui sera fait de l’“image” capturée (affichage, traitement, …).

Pour utiliser le type Mat dans le mécanisme signal/slot de Qt, il faudra le déclarer comme un nouveau type META de la manière suivante :

// Dans le fichier d'en-tête .h
Q_DECLARE_METATYPE(Mat);

// Dans le fichier de définition .cpp
qRegisterMetaType<Mat>();

Le code du thread se trouvera dans la méthode run() :

#include "tacquisitionvideo.h"

TAcquisitionVideo::TAcquisitionVideo() : resolution(RES_1024_768), brightness(0.5), contrast(0.5), saturation(0.5), change(false)
{
    qDebug() << Q_FUNC_INFO;
}

TAcquisitionVideo::~TAcquisitionVideo()
{
    qDebug() << Q_FUNC_INFO;
}

// Le code du thread
void TAcquisitionVideo::run()
{
    qDebug() << Q_FUNC_INFO << "start";
    this->setPriority(QThread::NormalPriority);

    try
    {
        VideoCapture camera(0); // 0 -> la première caméra détectée soit /dev/video0
        Mat frame; // une image

        setProprietes(camera); // paramétrage  des propriétés de la caméra (résolution, ...)

    // boucle d'acquisition des frames
        while(camera.isOpened() && !isInterruptionRequested())
        {
            // capture une image
            camera >> frame;
            if(frame.empty())
                continue;
            // ou :
            /*bool bSuccess = camera.read(frame);            
            if (!bSuccess)
                continue;*/

        // ici on l'envoie sous forme d'un Mat :
            emit nouvelleFrame(frame);

        // ou :
            //QImage image(frame.data, frame.cols, frame.rows, frame.step, QImage::Format_RGB888);
            //emit nouvelleImage(image);
            //QPixmap pixmap = QPixmap::fromImage(QImage(frame.data, frame.cols, frame.rows, frame.step, QImage::Format_RGB888).rgbSwapped());
            //emit nouvelleImage(pixmap);

        // une propriété doit être modifiée ?
            if(change)
                setProprietes(camera);
        }
    }
    catch (...)
    {
      // faire quelque chose avec les exceptions
    }

    qDebug() << Q_FUNC_INFO << "stop";
}

// Exemple de lecture de paramétres de la caméra
void TAcquisitionVideo::getProprietes(const VideoCapture &camera)
{
    QString message = "FRAME_WIDTH = " + QString::number(camera.get(CV_CAP_PROP_FRAME_WIDTH)) + "\n";
    message += "FRAME_WIDTH = " + QString::number(camera.get(CV_CAP_PROP_FRAME_HEIGHT)) + "\n";
    message += "FPS = " + QString::number(camera.get(CV_CAP_PROP_FPS)) + "\n";
    message += "BRIGHTNESS = " + QString::number(camera.get(CV_CAP_PROP_BRIGHTNESS)) + "\n";
    message += "CONTRAST = " + QString::number(camera.get(CV_CAP_PROP_CONTRAST)) + "\n";
    message += "SATURATION = " + QString::number(camera.get(CV_CAP_PROP_SATURATION));
    nouveauMessage(message);
}

// Exemple de paramétrage de la caméra
void TAcquisitionVideo::setProprietes(VideoCapture &camera)
{
    switch(resolution)
    {
    //...
    case RES_1024_768 :
        camera.set(CV_CAP_PROP_FRAME_WIDTH, 1024);
        camera.set(CV_CAP_PROP_FRAME_HEIGHT, 768);
        break;
    case RES_800_600 :
        camera.set(CV_CAP_PROP_FRAME_WIDTH, 800);
        camera.set(CV_CAP_PROP_FRAME_HEIGHT, 600);
        break;
    case RES_640_480 :
        camera.set(CV_CAP_PROP_FRAME_WIDTH, 640);
        camera.set(CV_CAP_PROP_FRAME_HEIGHT, 480);
        break;
    case RES_320_240 :
        camera.set(CV_CAP_PROP_FRAME_WIDTH, 320);
        camera.set(CV_CAP_PROP_FRAME_HEIGHT, 240);
        break;
    }

    camera.set(CV_CAP_PROP_BRIGHTNESS, brightness);
    camera.set(CV_CAP_PROP_CONTRAST, contrast);
    camera.set(CV_CAP_PROP_SATURATION, saturation);
    change = false;
    getProprietes(camera);
}

void TAcquisitionVideo::setResolution(int resolution)
{
    this->resolution = resolution;
    change = true;
}

void TAcquisitionVideo::setBrightness(double brightness)
{
    this->brightness = brightness;
    change = true;
}

void TAcquisitionVideo::setContrast(double contrast)
{
    this->contrast = contrast;
    change = true;
}

void TAcquisitionVideo::setSaturation(double saturation)
{
    this->saturation = saturation;
    change = true;
}

Pour créer et démarrer un thread d’acquisition, il suffit de faire :

TAcquisitionVideo   *acquisition;

acquisition = new TAcquisitionVideo();
connect(acquisition, SIGNAL(nouvelleFrame(Mat)), this, SLOT(afficherFrame(Mat)));
// ou :
//connect(acquisition, SIGNAL(nouvelleImage(QImage)), this, SLOT(afficherImage(QImage)));
//connect(acquisition, SIGNAL(nouvelleImage(QPixmap)), this, SLOT(afficherImage(QPixmap)));
connect(acquisition, SIGNAL(nouveauMessage(QString)), this, SLOT(afficherMessage(QString)));
acquisition->start();

On appelera la méthode start() pour démarrer le thread. C’est la méthode start() qui se charge d’exécuter la méthode run() de la classe TAcquisitionVideo.

Pour arrêter le thread d’acquisition, il suffit d’appeler la méthode requestInterruption() puis d’attendre l’arrêt effectif avec wait() :

disconnect(acquisition, SIGNAL(nouvelleFrame(Mat)), this, SLOT(afficherFrame(Mat)));
// ou :
//disconnect(acquisition, SIGNAL(nouvelleImage(QImage)), this, SLOT(afficherImage(QImage)));
//disconnect(acquisition, SIGNAL(nouvelleImage(QPixmap)), this, SLOT(afficherImage(QPixmap)));
acquisition->requestInterruption();
acquisition->wait();
disconnect(acquisition, SIGNAL(nouveauMessage(QString)), this, SLOT(afficherMessage(QString)));
delete acquisition;
acquisition = NULL; // ou nullptr

Le thread réalise l’acquisition d’image et les transmet par signal Qt à la GUI. Il faut donc un slot dans celle-ci pour, par exemple, afficher les images capturées.

Affichage

Sous Qt, on utilisera un objet QLabel pour assurer l’affichage des frames dans l’IHM.

À partir d’une frame de type Mat ou IplImage, il faut pouvoir la convertir dans un type Qt (ici QImage ).

Pour cela, on peut :

  • 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());
  • plus simplement :
QImage image(frame.data, frame.cols, frame.rows, frame.step, QImage::Format_RGB888);
imageLabel->setPixmap(QPixmap::fromImage(image.rgbSwapped()));
imageLabel->resize(imageLabel->pixmap()->size());

L’espace colorimétrique d’OpenCV par défaut est BGR (Bleu-Vert-Rouge), il faudra alors permuter les canaux rouge et bleu pour obtenir une image RGB standard. On utilisera au départ le Format_RGB888 puis on permutera les canaux bleu et rouge dans le QImage avec rgbSwapped().

Le code ci-dessus sera à placer dans un slot de la GUI.

L’enregistrement d’une image dans un fichier sera réalisé avec la fonction imwrite() fournie par OpenCV :

if(capturePhoto)
{
    QString nom = "photo-" + QString::number(numeroPhoto) + ".jpg";
    imwrite(nom.toStdString().c_str(), frame);
    numeroPhoto++;
    capturePhoto = false;
}

Incrustation

OpenCV fournit une fonction putText() qui permet d’insérer un texte dans une image Mat :

// Insertion d'un texte en blanc
QString texte = "Un texte !";
putText(frame, texte->text().toStdString().c_str(), Point(0, 60),  FONT_HERSHEY_PLAIN, 5, Scalar(255,255,255), 3, LINE_AA);

OpenCV fournit un ensemble de fonctions pour dessiner dans une image.

Par exemple pour dessiner une cible rouge au centre de l’image :

line(frame, Point(frame.cols/2,(frame.rows/2)-40), Point(frame.cols/2,(frame.rows/2)+40), Scalar(0,0,255), 2);
line(frame, Point((frame.cols/2)-40),frame.rows/2), Point((frame.cols/2)+40),frame.rows/2), Scalar(0,0,255), 2);
circle(frame, Point(frame.cols/2,frame.rows/2), 30, Scalar(0,0,255), 2);

Un peu de traitement d’image

OpenCV est une bibliothèque dédiée au traitement d’image qui comprend plusieurs centaines d’algorithmes.

OpenCV a une structure modulaire, dont les modules suivants :

  • imgproc : un module de traitement d’image qui comprend le filtrage d’images linéaire et non linéaire, les transformations d’images géométriques (redimensionnement, déformation affine et perspective, …), conversion d’espace colorimétrique, les histogrammes, etc.
  • vidéo : un module d’analyse vidéo qui comprend des algorithmes d’estimation de mouvement, de soustraction d’arrière-plan et de suivi d’objets.
  • objdetect : détection d’objets et d’instances des classes prédéfinies (par exemple, visages, yeux, tasses, personnes, voitures, etc.).

Exemple : détection de contours

Le filtre de Canny (ou détecteur de Canny) est utilisé en traitement d’images pour la détection des contours. L’algorithme a été conçu par John Canny en 1986.

Il faut tout d’abord convertir l’image en niveau de gris.

Mat gray, edge;

cvtColor(frame, gray, CV_BGR2GRAY);

Ensuite, on réduit le bruit de l’image originale :

blur(gray, edge, Size(3,3));

On peut aussi utiliser un filtre gaussien :

GaussianBlur(gray, edge, Size(5, 5), 1.5);

Après le filtrage, on applique un gradient qui retourne l’intensité des contours. La différenciation des contours sur la carte générée se fait par seuillage à hystérésis. Cela nécessite deux seuils, un haut et un bas; qui seront comparés à l’intensité du gradient de chaque point.

Canny(gray, edge, 100, 200, 3);

On peut essayer de calculer les valeurs des seuils automatiquement, par exemple :

double seuil = threshold(edge, img, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
double seuilHaut  = seuil;
double seuilBas = seuil * 0.5;
Canny(gray, edge, seuilBas, seuilHaut, 3);

Pour finir, il faut convertir l’image (attention le format a changé puisqu’on est passé en niveau de gris) :

edge.convertTo(frame, CV_8U);
format = QImage::Format_Grayscale8;

QImage image(frame.data, frame.cols, frame.rows, frame.step, format);
imageLabel->setPixmap(QPixmap::fromImage(image.rgbSwapped()));

Caractéristiques de la caméra

OpenCV fournit les méthodes get() et set() pour manipuler les propriétés de la caméra :

qDebug() << camera.get(CV_CAP_PROP_FRAME_WIDTH);
qDebug() << camera.get(CV_CAP_PROP_FRAME_HEIGHT);
qDebug() << camera.get(CV_CAP_PROP_FPS);
//...

camera.set(CV_CAP_PROP_FRAME_WIDTH, 1024);
camera.set(CV_CAP_PROP_FRAME_HEIGHT, 768);

Mais OpenCV ne fournit aucune fonction pour connaitre la liste des formats, résolutions, … supportés par la caméra.

Pour cela, on peut utiliser le support multimédia dans Qt5. Il est fourni par le module Qt Multimedia. L’API multimédia Qt (C++ et QML) fournit un certain nombre de classes pour gérer des caméras et ainsi accéder aux images et aux vidéos de ces périphériques.

Le module multimédia regroupent quatre composants principaux : l’audio, la vidéo, la radio et la caméra.

Pour utiliser les classes de QtMultimedia, il faut donc ajouter au fichier de projet .pro :

QT += multimedia

D’autre part, il faudra aussi disposer du module multimedia pour le développement (et des plugins pour les codecs) :

$ sudo apt-get install qtmultimedia5-dev qtmultimedia5-examples qtmultimedia5-doc qml-module-qtmultimedia

La classe QCameraInfo permet de déterminer le nombre de caméras détectées et accèder à quelques informations :

int nbCameras = QCameraInfo::availableCameras().count();
qDebug() << "Caméra(s) disponible(s)" << QCameraInfo::availableCameras().count();
if (nbCameras > 0)
{
   QList<QCameraInfo> cameras = QCameraInfo::availableCameras();
   foreach (const QCameraInfo &cameraInfo, cameras)
   {
       listeCameras->addItem(cameraInfo.deviceName());
       qDebug() << "Device" << cameraInfo.deviceName();
       qDebug() << "Description" << cameraInfo.description();
       if (cameraInfo.position() == QCamera::FrontFace)
           qDebug() << "Position : FrontFace";
       else if (cameraInfo.position() == QCamera::BackFace)
           qDebug() << "Position : BackFace";
   }
}

L’utilisation d’un objet QMediaRecorder associé à un objet de type QCamera permet d’accèder aux caractéristiques d’une caméra :

QCamera *camera = new QCamera("/dev/video0");
QCameraInfo *cameraInfo = new QCameraInfo(*camera);
qDebug() << cameraInfo->description() << cameraInfo->deviceName();
camera->load();
QMediaRecorder *captureVideo = new QMediaRecorder(camera, this);
qDebug() << "Capture Video available" << captureVideo->isAvailable();
qDebug() << "Capture Video codecs" << captureVideo->supportedVideoCodecs();
qDebug() << "Capture Video containers" << captureVideo->supportedContainers();
qDebug() << "Capture Video resolution(s)" << captureVideo->supportedResolutions();
qDebug() << "Capture Video frame rate(s)" << captureVideo->supportedFrameRates();
delete cameraInfo;
delete camera;

Voir aussi : Mise en oeuvre d’une caméra USB sous Qt

Code source

Voir aussi

Retour au sommaire