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

C++ Discussion :

[Format image YuYV] Image Verte lors du rendu


Sujet :

C++

  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Février 2008
    Messages
    43
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 43
    Points : 39
    Points
    39
    Par défaut [Format image YuYV] Image Verte lors du rendu
    Bonjour,
    Mon problème est que la librairie utilisé me renvoie un format d'image YUYV sur ma webcam. Des fonctions sont mises à disposition dans le code de celle-ci. Le rendu de l'image après conversion en RGB puis passage sous JAVA:

    Voici les faits:
    - j'ai une librairie "lti-civil" qui accède en C++ à la webcam et me transmet bien une image par appel et non un flux.
    - voici un lien expliquant le format sur lequel je travail : http://v4l2spec.bytesex.org/spec/r4339.htm
    - Voici le code permettant d'avoir un image malheureusement en vert :
    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
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
     
    //Ceci est une fonction qui permet de remettre une valeur correspondante dans tous les cas au RGB.
    //
    // YUV to RGB conversion:
    //
    unsigned char clip(int value)
    {    if (value <= 0)
            return 0;
        else if (value >= 255)
            return 255;
        else
            return (unsigned char) (value);
    }
     
    //Première méthode d'encodage je pense que le problème se situe ici
    //
    void yuv2rgb_buf(unsigned char *src, int width, int height, unsigned char *dst)
    {
        int u_offset = width * height;
        int v_offset = u_offset + width * height / 4;    // TODO: handle rows not divisible by 2.
        int uv_width = width / 2;
        int i;
        for ( i = 0; i < ( width * height ); i++ )
        {
            int px = i % width;
            int py = i / width;
            int uv_x = px / 2; // x in u/v planes
            int uv_y = py / 2; // y in u/v planes
            unsigned char y, u, v;
            unsigned char r, g, b;
            y = src[i];
     
            u = src[u_offset + uv_width * uv_y + uv_x];
            v = src[v_offset + uv_width * uv_y + uv_x];
            yuv2rgb(y, u, v, &r, &g, &b);
     
            *dst++ = b;
            *dst++ = g;
            *dst++ = r;
        }
     
    }
     
     
    // Le coeur de l'encodage
    //
    /**
     * Converts a yuv into RGV, using only integer (no double).
     */
    inline void yuv2rgb(unsigned char y, unsigned char u, unsigned char v, unsigned char *pr, unsigned char *pg, unsigned char *pb)
    {
        int C = 298 * (y - 16);
        int D = u - 128;
        int E = v - 128;
        int r = ( C           + 409 * E + 128) >> 8;
        if (r < 0)
            r = 0;
        else if (r > 255)
            r = 255;
        int g = ( C - 100 * D - 208 * E + 128) >> 8;
        if (g < 0)
            g = 0;
        else if (g > 255)
            g = 255;
        int b = ( C + 516 * D           + 128) >> 8;
        if (b < 0)
            b = 0;
        else if (b > 255)
            b = 255;
        *pr = r;
        *pg = g;
        *pb = b;
    }
    On peut voir que la dernière fonction correspond à une des très nombreuses formules présentent sur ce site: http://www.fourcc.org/fccyvrgb.php

    Après avoir modifié la deuxième fonction afin de correspondre aux autres formules j'obtiens soit un résultat rose, noir et blanc ou avec plus de moi à l'écran (cf image jointe on me voit 2 fois dessus)

    Merci beaucoup de votre réponse et de votre aide.
    HqSeO

  2. #2
    Nouveau membre du Club
    Homme Profil pro
    Université de Technologie de Compiègne
    Inscrit en
    Mai 2011
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Université de Technologie de Compiègne

    Informations forums :
    Inscription : Mai 2011
    Messages : 15
    Points : 38
    Points
    38
    Par défaut
    Salut,

    Attention, il existe de *très* nombreux formats et surtout de très grandes familles de formats. En fait, il existe plusieurs dérivées du format "YUV". Celui qui est retourné par ta caméra est un peu particulier si tu lis bien ce qui est donné dans la documentation de V4L2:

    "In this format each four bytes is two pixels. Each four bytes is two Y's, a Cb and a Cr. Each Y goes to one of the pixels, and the Cb and Cr belong to both pixels. As you can see, the Cr and Cb components have half the horizontal resolution of the Y component."
    Ce qui est assez différent, il me semble, du YUV dont tu fais mention. Il existe une bibliothèque qui s'appelle v4lconvert qui te permet de trouver les formules de pas mal de conversion de format. Tu pourras la trouver assez facilement je pense, néanmoins voici le code correspondant pour convertir du *YUV422* en RGB24.

    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
     
    #define CLIP(color) (unsigned char)(((color)>0xFF)?0xff:(((color)<0)?0:(color)))
    void v4lconvert_yuyv_to_rgb24(const unsigned char *src, unsigned char *dest,
      int width, int height)
    {
      int j;
     
      while (--height >= 0) {
        for (j = 0; j < width; j += 2) {
          int u = src[1];
          int v = src[3];
          int u1 = (((u - 128) << 7) +  (u - 128)) >> 6;
          int rg = (((u - 128) << 1) +  (u - 128) +
    		((v - 128) << 2) + ((v - 128) << 1)) >> 3;
          int v1 = (((v - 128) << 1) +  (v - 128)) >> 1;
     
          *dest++ = CLIP(src[0] + v1);
          *dest++ = CLIP(src[0] - rg);
          *dest++ = CLIP(src[0] + u1);
     
          *dest++ = CLIP(src[2] + v1);
          *dest++ = CLIP(src[2] - rg);
          *dest++ = CLIP(src[2] + u1);
          src += 4;
        }
      }
    }
    Essayes-ça, cela devrait techniquement fonctionner.

  3. #3
    Membre expérimenté Avatar de ctxnop
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juillet 2007
    Messages
    858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2007
    Messages : 858
    Points : 1 732
    Points
    1 732
    Par défaut
    Salut,
    Je ne suis pas du tout un spécialiste mais ton image n'est pas seulement verte, elle est "désalignée"
    Et quand je regarde ton code, je pense que c'est normal.
    Deux choses me chiffonnent :

    Tout d'abord, la spec du format YUYV que ton donne en lien dit que chaque groupe de 4 octet représente 2 pixels, les composante U et V sont commune aux deux pixels, par contre chacun des pixel a ses propre composante Y. Les octets sont alignés comme ceci : Y1 U Y2 V.
    Or, si j'ai rien loupé dans ton code, tu convertis 1 groupe de 4 octets "YUYV" en un seul pixel RGB.

    Ensuite, pour autant que je me souvienne, le RGB est aligné sur 4 octets. Soit c'est du RGB 24bit et le 4ieme est du bourrage, soit c'est du 32bits et le 4ième est un canal alpha (opacité). Mais bon, je suis vraiment pas certain de moi sur ce coup ^^'

    Toujours est-il que j'aurai plutôt codé ca comme ca (j'ai tout mis dans la même fonction pour que ce soit plus simple a lire) :
    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
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    void yuv2rgb_buf(unsigned char* src, int width, int height, unsigned char* dst)
    {
    	// Dans le format, 2 pixels = 4 octets organisé comme ceci Y1 U Y2 V
    	// Donc la source est un tableau de unsigned int
    	unsigned int* pixels = (unsigned int*)src;
    	int end = width * height; // La fin du tableau
    	int i = 0;
    	while(i < end)
    	{
    		unsigned int p = pixels[i]; // Copie la valeur de la source
    		// On récupère les composantes en appliquant les coeff de conversion constants, ca évite de le faire 15 fois
    		unsigned int y1 = (((0xFF000000 & p) >> 24) - 16) * 1.164;
    		unsigned int u  = ((0x00FF0000 & p) >> 16) - 128;
    		unsigned int y2 = (((0x0000FF00 & p) >> 8) - 16) * 1.164;
    		unsigned int v  = ((0x000000FF & p)) - 128;
     
    		// On convertit en RGB via les formules
    		unsigned int r1 = y1 + 1.596 * v;
    		unsigned int g1 = y1 - 0.813 * v - 0.391 * u;
    		unsigned int b1 = y1 + 2.018 * u;
     
    		// Le second pixel
    		unsigned int r2 = y2 + 1.596 * v;
    		unsigned int g2 = y2 - 0.813 * v - 0.391 * u;
    		unsigned int b2 = y2 + 2.018 * u;
     
    		// On s'assure des bornes, je ne pense pas que ca soit nécéssaire
    		// si on considère qu'il s'agit d'une formule sans perte, le résultat devrait forcément
    		// entrer dans les bornes, mais vu que tu as une fonction clip, je présume qu'il y
    		// a un risque que ce ne soit pas le cas.
    		r1 = r1 > 255 ? 255 : r1; r1 = r1 < 0 ? 0 : r1;
    		g1 = g1 > 255 ? 255 : g1; g1 = g1 < 0 ? 0 : g1;
    		b1 = b1 > 255 ? 255 : b1; b1 = b1 < 0 ? 0 : b1;
    		r2 = r2 > 255 ? 255 : r2; r2 = r2 < 0 ? 0 : r2;
    		g2 = g2 > 255 ? 255 : g2; g2 = g2 < 0 ? 0 : g2;
    		b2 = b2 > 255 ? 255 : b2; b2 = b2 < 0 ? 0 : b2;
     
    		// Ecrit les deux pixels dans la destination
    		*dst++ = b1;
    		*dst++ = g1;
    		*dst++ = r1;
    		*dst++ = 0xFF;
    		*dst++ = b2;
    		*dst++ = g2;
    		*dst++ = r2;
    		*dst++ = 0xFF;
     
    		// Passe au groupe suivant
    		i++;
    	}
    }
    EDIT : arff, me suis fait grillé

  4. #4
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Février 2008
    Messages
    43
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 43
    Points : 39
    Points
    39
    Par défaut
    Merci beaucoup de vos réponses je testerais ça tout à l'heure merci beaucoup je vous tiens au courant.

    Edit: Je viens de tester la solution 1, elle marche parfaitement, merci beaucoup, un petit rendu bleu lors du lancement de la webcam mais après quelques secondes tout redeviens normal.

    Pour la seconde méthode, un StackOverflow donc je cherche même pas vu que la 1er a été retenu par mes soins.

    Merci encore beaucoup pour votre aide.

  5. #5
    Membre expérimenté Avatar de ctxnop
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juillet 2007
    Messages
    858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2007
    Messages : 858
    Points : 1 732
    Points
    1 732
    Par défaut
    Je me doutais qu'elle passerai pas du premier coup ma méthode, mais stackoverflow je vois pas trop comment j'y arrive vu qu'il n'y a aucune récursion ni appel d'autres méthodes

    Enfin bon, si la première méthode fonctionne, pas de souci

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

Discussions similaires

  1. 1 image + 1 image = 1 image
    Par dleu dans le forum Delphi
    Réponses: 2
    Dernier message: 24/05/2006, 20h15
  2. Trouver le format d'une image
    Par blaiseac dans le forum Autres Logiciels
    Réponses: 4
    Dernier message: 27/09/2005, 22h17
  3. format video et image
    Par gerardTar dans le forum C++Builder
    Réponses: 5
    Dernier message: 06/09/2005, 10h16
  4. Image s'affiche que lors du redimensionnement
    Par gmonta dans le forum AWT/Swing
    Réponses: 3
    Dernier message: 17/05/2005, 13h28
  5. [VisualC++] Changer le format d'une image
    Par dananchet dans le forum MFC
    Réponses: 1
    Dernier message: 06/05/2005, 15h05

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