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

Qt Discussion :

Taille d'une QImage


Sujet :

Qt

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    60
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 60
    Par défaut Taille d'une QImage
    Bonsoir,

    j'essaie d'intégrer des méthodes de la librairie opencv dans qt4 afin de faire via une gui, du traitement d'images sur le flux vidéo de ma webcam. Mon problème actuel se situe par rapport à l'affichage en niveau de gris du flux vidéo initialement en couleur.

    Le code en C suivant marche très bien. La transformation du flux en niveau de gris se fait grâce à la méthode cvCvtColor(img2,img3,CV_BGR2GRAY); où img2 est l'image en couleur et im3 celle en niveau de gris. Voici le code :

    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
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
     
    #include <stdlib.h>
    #include <stdio.h>
    #include <math.h>
    #include <cv.h>
    #include <highgui.h>
     
     
    int main(int argc, char *argv[])
    {
      IplImage *img = 0, *img2 = 0, *img3 = 0; 
      int height,width,step,channels;
      uchar *data;
      int i,j,k;
      CvScalar scalaire, scalaire2, scalaire3;
     
     
      cvNamedWindow("Fenetre_test", CV_WINDOW_AUTOSIZE); 
      cvMoveWindow("Fenetre_test", 100, 100);
     
      // Initialise la capture  
      CvCapture* capture = cvCaptureFromCAM(0);
        while(cvWaitKey(20)!='q')
        {
     
         	  img2 = cvQueryFrame(capture);
    	  img3 = cvCreateImage(cvGetSize(img2), 8, 1);
    	  cvCvtColor(img2,img3,CV_BGR2GRAY);
             cvShowImage("Fenetre_test", img3 );
     
        }
     
      // release the image
      cvReleaseImage(&img2 );
      cvReleaseImage(&img3 );
      cvReleaseCapture(&capture);
      return 0;
    }
    Maintenant, voici le code c++ qui est censé faire la même chose que ci-dessus mais en passant par les QImages.

    Tout d'abord le constructeur :

    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
     
    IplImageWidget::IplImageWidget()
    {
    capture = cvCaptureFromCAM(0);
     
    im1 = cvQueryFrame( capture );
     
    m_i = QImage(QSize(im1->width,im1->height),QImage::Format_RGB32);
    this->setMinimumSize(im1->width,im1->height);
    this->setMaximumSize(im1->width,im1->height);
     
    m_timer = new QTimer(this);
    connect(m_timer,SIGNAL(timeout()),this,SLOT(queryFrame()));
    m_timer->start(50);    
    }
    et la méthode queryFrame() :

    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
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
     
    void IplImageWidget::queryFrame() {
     
     
    IplImage* frame = cvQueryFrame( capture );
     
    im2 = cvCreateImage(cvGetSize(frame),8,1);  
     
    cvCvtColor(frame,im2,CV_BGR2GRAY);
     
    // conversion de IplImage en Qimage
     
    const int pixels = im2->width * im2->height;
    uchar *imageData = new unsigned char[4*pixels];
    for(int i = 0; i < pixels;i++)
    { imageData[i*4+3] = 0xFF; }
    uchar* src = (uchar*)(im2->imageData);
    uchar* srcEnd = src + (3*pixels);
    uchar* dest = imageData; 
    do { memcpy(dest, src, 3);
     dest += 4; src += 3;
       }
    while(src < srcEnd);
     
    QImage m_i_new(imageData,im2->width,im2->height, QImage::Format_RGB32);
     
    m_i=m_i_new.copy();
     
    this->repaint();
    }
    avec

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
     
    void IplImageWidget::paintEvent(QPaintEvent*)
    {
     
        QPainter painter(this); 
        painter.drawImage(QRect(0,0,im1->width,im1->height),m_i);
    }
    Tout compile bien mais à l'exécution, j'obtiens un résultat étrange qui est visible en pièce jointe (cf "es.jpg"). On voit qu'il y a 3 fenetres du flux plus une autre partie étrange. Comme vous l'avez vu dans le code c++, je convertis par l'intermédiaire de memcpy une IplImage en QImage. Le problème est qu'une IplImage est codée sur 3 octets et une QImage sur 4, je fixe donc le quatrième octet à une valeur fixe pour tous les pixels :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    (uchar *imageData = new unsigned char[4*pixels];
    for(int i = 0; i < pixels;i++)
    { imageData[i*4+3] = 0xFF; }
    Ensuite j'invoque
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    QImage m_i_new(imageData,im2->width,im2->height, QImage::Format_RGB32);
    m_i=m_i_new.copy();
    pour obtenir ma QImage que l'essaie d'afficher par :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
        QPainter painter(this); 
        painter.drawImage(QRect(0,0,im1->width,im1->height),m_i);
    Mais voilà visiblement, il y a un probleme de taille du flux affiché comme on le voit sur l'image en pièce jointe. je peux obtenir une taille correcte en multipliant par 3 "im2->width" et "im2->height" mais c'est du bricolage et puis même, la résolution n'est pas bonne. D'ou vient ce facteur 3 ?

    Vous auriez une piste ?

    Merci par avance.
    Images attachées Images attachées  

  2. #2
    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
    si ton image est en niveau de gris, elle est à coup sur sur 1 octet par pixel et non trois


    ca c'est OUTCH
    uchar *imageData = new unsigned char[4*pixels];
    for(int i = 0; i < pixels;i++)
    { imageData[i*4+3] = 0xFF; }
    uchar* src = (uchar*)(im2->imageData);
    uchar* srcEnd = src + (3*pixels);
    uchar* dest = imageData;
    do { memcpy(dest, src, 3);
    dest += 4; src += 3;
    }
    while(src < srcEnd);

    QImage m_i_new(imageData,im2->width,im2->height, QImage::Format_RGB32);

    m_i=m_i_new.copy();
    Le m_i_new.copy() ne sert à rien et pourquoi le memcpy?

    Perso, j'aurais fait un truc comme (devrais être correcte pour le format RGB32 et ARGB seulement) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    const int pixels = im2->width * im2->height;
    QRgb*imageData = reinterpret_cast<QRgb*> (mi.data());
    for(int i = 0; i < pixels;++i)
    {
     imageData[i] = qRgb (im2->imageData[i],im2->imageData[i],im2->imageData[i]);
     }
    1- QRgb est un typedef sur un int32 qui correspond au RGB32 ou ARGB de QImage.
    http://qt.developpez.com/doc/4.6-sna.../#qrgb-typedef

    2- qRgb() créé un QRgb à partir des 3 composante en octet. Comme tu en as surement qu'une (niveau de gris), il suffit de mettre la même valeur en R,G et B
    http://qt.developpez.com/doc/4.6-snapshot/qcolor/#qrgb

    3-Pour la vidéo, il faut éviter au maximum les recopies inutile.

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    60
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 60
    Par défaut
    Il y a un probleme dans la solution que tu m'as donné, dans la ligne

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    QRgb*imageData = reinterpret_cast<QRgb*> (mi.data());
    je pense que tu as voulu écrire m_i.data(). Mais la Qimage m_i ne dispose pas de méthode . En plus, celle-ci n'est pas remplie avant cet appel, elle ne contient donc pas de données.

    Je ne peux pas aussi dans la fonction paintEvent(QPaintEvent*) mettre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    painter.drawImage(QRect(0,0,im1->width,im1->height),imageData);
    Il faut que je mette une Qimage comme dernier argument.

    Merci pour vos éclaircissements.

  4. #4
    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 fab13 Voir le message
    Il y a un probleme dans la solution que tu m'as donné
    C'est une ébauche, faut la corriger

    Mais la Qimage m_i ne dispose pas de méthode .
    c'est bits en faite
    http://qt.developpez.com/doc/4.6-snapshot/qimage/#bits

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    const int pixels = im2->width * im2->height;
    QRgb*imageData = reinterpret_cast<QRgb*> (m_i.bits ());
    for(int i = 0; i < pixels;++i)
    {
          imageData[i] = qRgb (im2->imageData[i],im2->imageData[i],im2->imageData[i]);
    }
    En plus, celle-ci n'est pas remplie avant cet appel, elle ne contient donc pas de données.
    quand tu fait
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    m_i = QImage(QSize(im1->width,im1->height),QImage::Format_RGB32);
    QImage as déjà une mémoire.


    Je ne peux pas aussi dans la fonction paintEvent(QPaintEvent*) mettre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    painter.drawImage(QRect(0,0,im1->width,im1->height),imageData);
    Il faut que je mette une Qimage comme dernier argument.

    j'ai pas compris cette remarque

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    60
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 60
    Par défaut
    Merci beaucoup, ça marche !

    Par contre, j'aimerais comprendre comment, après avoir déclaré :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    m_i = QImage(QSize(im1->width,im1->height),QImage::Format_RGB32);
    on peut changer le contenu de la QImage m_i avec :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    QRgb*imageData = reinterpret_cast<QRgb*> (m_i.bits ());
    En effet, il y a une affectation du contenu de m_i au pointeur imageData. Autrement dit, en modifiant imageData après la déclaration de la QImage m_i, je modifie en "live" le contenu de m_i. Est ce que ceci est du au fait que l'on utilise un pointeur , c'est à dire que l'on travaille directement sur les adresses des objets ?
    Intuitivement, on pourrait plutôt s'attendre à avoir une affectation dans le sens inverse (m_i.bits()= cast (imageData)). Excusez moi si ma question peut paraître idiote.

    Merci par avance.

  6. #6
    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
    ce sont deux choses différentes.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    m_i = QImage(QSize(im1->width,im1->height),QImage::Format_RGB32);
    créer une image de taille width*heigh avec des pixel de type RGB32. QImage a donc un buffer de taille width*heigh*4.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    QRgb*imageData = reinterpret_cast<QRgb*> (m_i.bits ());
    m_i.bits() retourne un pointeur par octet sur le buffer mémoire du QImage.
    le reinterpret_cast spécifie que cette mémoire est constitué de QRgb (int) et va permettre de l'exploiter sous cette forme.
    On va donc modifier le buffer mémoire de m_i 4octets par 4octects (sizeof(QRgb) = 4).


    Ps: pour info , QImage utilise une mémoire où la taille mémoire d'une ligne est aligné sur 32bits = 4 octets. Comme ton pixel fait 4 octets, on se préoccupe pas de ce problème.
    Comme tes pixels d'entrée sont sur un octet, si width est un multiple de 4, tu pourrais évité la copie et passer im2->imageData (sous frme d'un pinteur constant) directement au QImage.

Discussions similaires

  1. Comment calculer la taille d'une base de données ?
    Par say dans le forum Décisions SGBD
    Réponses: 8
    Dernier message: 01/04/2011, 16h48
  2. Réponses: 10
    Dernier message: 22/05/2004, 13h51
  3. [SQL SERVEUR]taille d'une base de donnée
    Par hirochirak dans le forum Autres SGBD
    Réponses: 2
    Dernier message: 08/01/2004, 12h07
  4. : Adapter la taille d'une grille
    Par SteelBox dans le forum C++Builder
    Réponses: 3
    Dernier message: 31/07/2003, 07h08
  5. Taille d'une console sous linux
    Par Shinjuku dans le forum C
    Réponses: 7
    Dernier message: 13/06/2003, 12h44

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