IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Bibliothèques Discussion :

Intégration de fenêtre OpenCV dans une interface Qt [Autres]


Sujet :

Bibliothèques

  1. #1
    Membre émérite

    Profil pro
    Inscrit en
    Mai 2007
    Messages
    774
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Finistère (Bretagne)

    Informations forums :
    Inscription : Mai 2007
    Messages : 774
    Par défaut Intégration de fenêtre OpenCV dans une interface Qt
    Bonjour à tous,

    openCV est une librairie qui permet, entre autres, de récupérer le flux vidéo d'une webcam et de l'afficher de façon optimisée.

    Le rendu se fait dans une fenêtre identifiée par son nom, et on peut récupérer son handler, dans mon cas(windows) un HWND* .

    J'ai testé de différentes façons "d'inclure" cette fenêtre dans un QWidget, mais sans succès.

    Essai 1 : QWidget::find() :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    videoW = new QWidget();
    cvNamedWindow("cvWin");
    HWND* cvHWND = (HWND*)cvGetWindowHandle("cvWin");
    videoW = QWidget::find((WId)*cvHWND);
    Résultat : Echec, cvHWND est toujours nul;

    Essai 2 : setParent(HWND,HWND) de windows.h :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    videoW = new QWidget();
    cvNamedWindow("cvWin");
    HWND* cvHWND = (HWND*)cvGetWindowHandle("cvWin");
    setParent(*cvHWND,(HWND)videoW.WId());
    Résultat : Echec, bien que l'include <windows.h> se fasse correctement, le compilateur ne le reconnaît pas, et fait touours appel à QWidget::setParent().

    Si vous avez une solution pour le deuxième essai, et/ou si vous savez comment mettre une fenêtre HWND dans un QWidget, merci de me renseigner.

    Joyeux Noel,

    G.

  2. #2
    Membre émérite

    Profil pro
    Inscrit en
    Mai 2007
    Messages
    774
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Finistère (Bretagne)

    Informations forums :
    Inscription : Mai 2007
    Messages : 774
    Par défaut
    Après re-lecture et re-réflexion, je me suis rendu compte d'une bêtise.

    Pour la méthode 2, la fonction de windows.h est SetParent(HWND,HWND) et non setParent(HWND,HWND).

    Ce n'est pas pour autant que ça marche, j'ai toujours ce HWND de ma fenêtre opencv égal à NULL.

    Ce post n'a donc plus vraiment de légitimité ici. Je le complèterai si je trouve une solution.

    Merci,

    G.

  3. #3
    Membre émérite

    Profil pro
    Inscrit en
    Mai 2007
    Messages
    774
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Finistère (Bretagne)

    Informations forums :
    Inscription : Mai 2007
    Messages : 774
    Par défaut La solution
    Ca y est, j'ai réussi à inclure la l'image dans mon interface.

    La solution est :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    videoW = new QWidget(this);
    cvNamedWindow("cvWin", CV_WINDOW_AUTOSIZE);
    SetParent((HWND)cvGetWindowHandle("cvWin"),(HWND)videoW->winId());
    Je n'ai pas réussi à le faire marcher avec QWidget::find();

    Cependant, il reste 2 problèmes :
    1) même si l'image s'affiche bien dans le fanêtre Qt, la fenêtre openCV d'origine est grisée, et reste présente.
    2) la fermeture de la fenêtre openCV d'origine stoppe le rafraîchissment de la vidéo. Je n'ai fait que déplacer l'image finalement.

    Je vais peut être m'orienter vers une méthode par repaint() du widget, directement avec les IplImages fournies par opencv. La conversion IplImage/QImage n'étant pas très optimisée.

    G.

  4. #4
    Membre émérite

    Profil pro
    Inscrit en
    Mai 2007
    Messages
    774
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Finistère (Bretagne)

    Informations forums :
    Inscription : Mai 2007
    Messages : 774
    Par défaut
    Salut, bonne année à tout le forum !

    Bon, reprenons .

    La solution de base, qui marche convenablement, est :
    1) récupérer l'image de la webcam grâce à openCV (type IplImage)
    2) conversion en QImage (accès pixel à pixel et conversion grâce à qRgb())
    2) Création QPixmap à partir de cette QImage, puis affichage dans un QLabel.

    Dans le forum de la faq Qt, Msieur Mongaulois a dit :
    A vue de nez, je dirais que d'hériter d'un QLabel n'est pas la meilleur soultion.
    J'aurais plutôt fait une QWidget en redéfinissant le paintEvent.
    Après plusieurs essais, j'ai l'impression que cela se confirme. Est ce que quelqu'un aurait un article ou un truc du genre donnant des explications là dessus ?

    Concernant la redéfinition du paintEvent, quelle est la meilleure solution ?

    1) convertir chaque pixel grâce à qRgb() puis le dessiner grâce à un QPainter::drawLine(x,y,x,y)
    2) convertir toute l'IplImage en QImage, et utiliser QPainter::drawImage()

    Si vous avez des informations en terme de performance sur une des choses citées dans ce thread, je serais ravi de pouvoir les lire !

    Merci d'avance,

    G.

  5. #5
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 035
    Par défaut
    Citation Envoyé par Gulish Voir le message
    Après plusieurs essais, j'ai l'impression que cela se confirme. Est ce que quelqu'un aurait un article ou un truc du genre donnant des explications là dessus ?
    Regarde le code de QLabel

    Concernant la redéfinition du paintEvent, quelle est la meilleure solution ?
    certainement faire un drawImage.

    En faite, le plus rapide pour l'affichage est le QPixmap car il est prévue pour
    http://qt.developpez.com/doc/4.4/qpixmap/#details
    Sous windows QPixmap == QImage.

    Le mieux à mon avis est d'utiliser Une QImage que tu remplie et tu applique drawImage dans le paintEvent
    Une conversion vers QPixmap est certainement une perte de temps pour de la vidéo.
    Par contre je viens de trouver cela (qui dit peut être le contraire) :
    http://qt-quarterly.developpez.com/qq-12/qpixmapcache/
    mais je n'ai pas encore lu

  6. #6
    Membre émérite

    Profil pro
    Inscrit en
    Mai 2007
    Messages
    774
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Finistère (Bretagne)

    Informations forums :
    Inscription : Mai 2007
    Messages : 774
    Par défaut
    J'ai donc fini par faire ça avec un drawImage. J'ai enlevé les flags qui ajustent la taille de l'image à celle du widget car c'est une opération assez lourde, et le rendu de l'image est bien supérieur quand l'image est affichée à sa taille d'origine. J'ai en fait même fini par ajuster la taille de ma fenêtre à celle de l'image.

    Concernant le QPixmapCache, comme son nom l'indique, c'est un outil permettant d'optimiser l'affichage d'image qui s'affiche régulièrement (le principe d'un cache en fait). Celui de Qt à l'air relativement bien optimisé, et s'avère être utile même quand la redondance des images est très limitée. Cependant, dans mon cas, l'ensemble de l'image varie de façon continue, donc ça ne m'est pas utile.

    Regarde le code de QLabel
    Je n'ai eu (pris) le temps de le faire, mais il est clair que mon rendu et ma fluidité ont grandement été améliorés grâce à la redéfinition du repaint. (Ca soulage de ce dire qu'on a pas fait ça pour rien)

    Merci encore, notamment à Mongaulois, pour la résolution de ce problème.

    G.

  7. #7
    Membre à l'essai
    Profil pro
    Inscrit en
    Février 2010
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2010
    Messages : 5
    Par défaut
    Salut,

    Je me permet de faire un petit up sur ce topic (qui a plus d'un an maintenant) parce que je suis confronté au même problème.
    Gulish, tu dis être parvenu à faire un affichage de ton flux vidéo opencv direct en modifiant le drawImage.
    Je serais ravi de voir le code que tu as fait pour y parvenir.

    Ou alors si quelqu'un à des idées pour éviter de passer par un QLabel et une fonction IplImage -> QImage qui n'est pas optimisé je suis preneur.

  8. #8
    Membre averti
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    33
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Mars 2004
    Messages : 33
    Par défaut
    Hello

    Citation Envoyé par caubios Voir le message
    si quelqu'un à des idées pour éviter de passer par un QLabel et une fonction IplImage -> QImage qui n'est pas optimisé je suis preneur.
    Mapper ton IplImage->imageData sur comme une texture l'appiquer sur un quad. Ensuite, utiliser un QGLWidget pour l'affichage.

    La perf sera directement dépendant de la carte graphique mais cette méthode a un bon potentiel.


    ++

    Frantz

  9. #9
    Membre à l'essai
    Profil pro
    Inscrit en
    Février 2010
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2010
    Messages : 5
    Par défaut
    Citation Envoyé par trop_wizz Voir le message
    Mapper ton IplImage->imageData sur comme une texture l'appiquer sur un quad. Ensuite, utiliser un QGLWidget pour l'affichage.
    J'ai encore jamais fais d'openGL mais je vais tester ça et si j'arrive a quelque chose je mettrai du code dans le post.

    Au passage IplImage est deprecated dans openCv 2.0, j'utilise des Mat

    Merci pour le conseil, je reste à l'écoute si quelqu'un a réussi a faire quelque chose d'autre de bien.

  10. #10
    Membre émérite

    Profil pro
    Inscrit en
    Mai 2007
    Messages
    774
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Finistère (Bretagne)

    Informations forums :
    Inscription : Mai 2007
    Messages : 774
    Par défaut
    Salut,

    Bon, ça fait un moment que je suis plus là dessus. Voici le bout de code que j'utilisais pour afficher mon flux vidéo. Ce n'est sans doute pas le plus optimisé, mais les performances me satisfaisaient pleinement.

    Voici la classe qui affiche l'image :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    class VideoWin : public QWidget
    {
    public:
    	VideoWin ( QWidget * parent = 0, Qt::WindowFlags f = 0 ) : QWidget  (parent,f){};
     
    	void setImage(QImage newImage)
    	{
    	currentImage=newImage;
    	this->repaint();
    	}
     
    	void paintEvent ( QPaintEvent * event )
    	{
    	QPainter painter(this);
    	painter.drawImage(this->pos(),currentImage);
    	}
     
    	QImage currentImage;
    };
    La méthode de conversion IplImage -> QImage :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    QImage VideoThread::Ipl2QImage(const IplImage *newImage) //fct recuperer sur le net, converti un IplImage en QImage
    {
    	QImage qtemp;
    	if (newImage && cvGetSize(newImage).width>0)
    	{
    		int x;
    		int y;
    		char* data = newImage->imageData;
     
    		qtemp= QImage(newImage->width, newImage->height,QImage::Format_RGB32 );
    		for( y = 0; y < newImage->height; y++, data +=newImage->widthStep )
    			for( x = 0; x < newImage->width; x++)
    			{
    				uint *p = (uint*)qtemp.scanLine (y) + x;
    				*p = qRgb(data[x * newImage->nChannels+2],data[x * newImage->nChannels+1],data[x * newImage->nChannels]);
    			}
    	}
    	return qtemp;	
    }
    L'autre méthode, qui permettait de ne pas passer par la conversion Ipl -> QImage, revenait à rediriger le hwnd de la cvNamedWindow vers celui d'un QWidget. Par contre, j'avais des problèmes de mises à jour lorsqu'on déplaçait la fenêtre.

    G.

  11. #11
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 035
    Par défaut
    Salut
    sort
    de la boucle
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    for( x = 0; x < newImage->width; x++)
    tu sera plus rapide. Car cette appel vérifie si il doit copier ou non l'image avant la modif, a cause du COW.

  12. #12
    Membre à l'essai
    Profil pro
    Inscrit en
    Février 2010
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2010
    Messages : 5
    Par défaut
    Impec.

    Merci, je vais tester tout ca

  13. #13
    Invité de passage
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    1
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 1
    Par défaut
    Salut,

    Je cherche à faire exactement la même chose que ce que Gulish a fait.

    J'ai une fenêtre de dialogue, une groupbox dedans et dans cette groupbox je veux afficher une vidéo en utilisant opencv.

    J'aimerai savoir si j'ai bien compris ce qu'il faut faire:

    1. Créer un widget VideoWin (celui qui va être ajouté à ma groupBox et qui diffusera les images)

    2. Lecture et affichage de la vidéo (comme sur les tuto OpenCV)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    IplImage* img;
    CvCapture* capture = cvCreateFileCapture("C:/dev/Svng/Dsvng/resources/real.avi");
    if( !capture ) 
          return ;
    cvNamedWindow("cvWin", CV_WINDOW_AUTOSIZE);
    char key = ' ';
     
    if(!cvGrabFrame( capture ))
            return ;
     
    while(key != 'q')
    {
         img = cvRetrieveFrame( capture );
    }
    3. Dans la boucle while, quand on a récupéré l'image Ipl, on la convertit en QImage et on fait un setImage sur l'objet VideoWin.

    Est ce que cela va faire défiler la vidéo ou est ce que j'oublie des choses ?
    (J'espère avoir été claire :p)

    Merci d'avance

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 2
    Dernier message: 04/07/2013, 18h55
  2. Intégration d'OpenGL dans une interface Qt
    Par Architekth dans le forum Qt
    Réponses: 5
    Dernier message: 21/09/2010, 16h03
  3. exploitation de fenêtre "open file" dans une interface
    Par Adem84 dans le forum Interfaces Graphiques
    Réponses: 6
    Dernier message: 09/02/2010, 15h02
  4. Réponses: 0
    Dernier message: 18/02/2008, 10h51
  5. Tableau dans une interface idl
    Par Polochon2001 dans le forum CORBA
    Réponses: 2
    Dernier message: 14/05/2004, 09h44

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo