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

OpenCV Discussion :

Récupérer le gradient, l'amplitude et l'angle depuis Canny()


Sujet :

OpenCV

  1. #1
    Membre régulier
    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2008
    Messages
    138
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Communication - Médias

    Informations forums :
    Inscription : Janvier 2008
    Messages : 138
    Points : 70
    Points
    70
    Par défaut Récupérer le gradient, l'amplitude et l'angle depuis Canny()
    Bonjour,

    Aujourd'hui j'essaie de constuire l'edge oriented histogram (EOH) d'une image. Pour cela je voudrais appliquer les formules de calcul de magnitude de gradient et de direction ci-dessous :

    m( x,y ) = sqrt( Gx( x, y )² + Gy( x, y )² )
    teta( x,y ) = arctan( Gy( x,y ) / Gx( x,y ) )
    Il me faut donc les gradients horizontaux et verticaux Gx et Gy à chaque pixel p(x, y).
    Et c'est là que je bloque. Je sais que la fonction Canny fait cela en interne et sort en output une matrice contenant les contours. Mais je ne sais pas comment lire cette matrice pour récupérer ces informations.
    Comment suis-je censé m'y prendre ?

    Merci d'avance et désolé si cette question vous semble absurde, mais je n'ai pas trouvé de doc sur comment récupérer ces infos.

  2. #2
    Membre éprouvé
    Homme Profil pro
    Ingénieur 3D
    Inscrit en
    Avril 2008
    Messages
    400
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Ingénieur 3D

    Informations forums :
    Inscription : Avril 2008
    Messages : 400
    Points : 968
    Points
    968
    Par défaut
    L'aide d'OpenCV laisse sous entendre que leur opérateur Canny ne fait quasiment qu'appeler l’opérateur Sobel. Passes directement par Sobel et tu auras tes Gx et Gy. Apres, pour retrouver Canny a partir de ça, il faut faire un seuillage sur la magnitude du gradient (si gradient fort, alors il y a un edge).

  3. #3
    Membre régulier
    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2008
    Messages
    138
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Communication - Médias

    Informations forums :
    Inscription : Janvier 2008
    Messages : 138
    Points : 70
    Points
    70
    Par défaut
    Ah d'accord très bien. Je vais regarder du côté de Sobel dans ce cas-là.

    Merci!

  4. #4
    Membre régulier
    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2008
    Messages
    138
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Communication - Médias

    Informations forums :
    Inscription : Janvier 2008
    Messages : 138
    Points : 70
    Points
    70
    Par défaut
    Bonjour,

    J'ai un souci pour accéder aux gradients récupérés via Sobel.
    Voici l'appel à Sobel et la récupération des gradients

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    /// Generate grad_x and grad_y
        Mat grad_x, grad_y;
        Mat abs_grad_x, abs_grad_y;
     
        /// Gradient X
        Sobel( src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT );
        convertScaleAbs( grad_x, abs_grad_x );
     
     
        /// Gradient Y
        Sobel( src_gray, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT );
        convertScaleAbs( grad_y, abs_grad_y );
    Le code suivant m'affiche de jolis gradients positifs et négatifs comme on les aime

    En revanchhe, si j'essaie d'y accéder pixel par pixel, les nombres affichés sont différents et tous compris entre 0 et 255 :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
     for( int i = 0; i < grad_x.rows; i++ )
        {
            for ( int j = 0; j < grad_x.cols; j++ )
            {
                cout << "Gx(x, y) = " << (float)(grad_x.data[i*grad_x.step + j]) << endl;
            }
        }
    Je sais que c'est un problème d'accès aux données et de typage. Mais je ne parviens pas à trouver le bon typage. J'ai aussi tenté via la méthode at(), mais quel type mettre dans le template at<T> ? Il ne s'agit pas là d'une matrice à plusieurs channels donc je suis un peu perturbé ( en tant normal, je travaille sur 3 channels de couleurs, donc j'utilise <Vec3b> )

  5. #5
    Membre éprouvé
    Homme Profil pro
    Ingénieur 3D
    Inscrit en
    Avril 2008
    Messages
    400
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Ingénieur 3D

    Informations forums :
    Inscription : Avril 2008
    Messages : 400
    Points : 968
    Points
    968
    Par défaut
    Le type est probablement cv::Vec<float,2> ou quelque chose comme ça. Sinon, si tu as 3 dimensions (hauteur, largeur, channels), il me semble que l’opérateur at a une surcharge qui prend 3 entiers en paramètre (et dans ce cas la, le type est simplement float). Mais dans ton cas, je pense que le cv::Vec est le plus "logique" vu que ton image contient bien des vecteurs 2D.

  6. #6
    Membre régulier
    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2008
    Messages
    138
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Communication - Médias

    Informations forums :
    Inscription : Janvier 2008
    Messages : 138
    Points : 70
    Points
    70
    Par défaut
    Merci pour vos réponses.

    J'ai tenté ces deux typages :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
                cout << "Gx = " << (float)(((Vec<float, 2>)(grad_x.at< Vec<float, 2> >(i, j)))[0]) << endl;
                cout << "Gx = " << (float)(grad_x.at<float>(i, j)) << endl;
                cout << "Gx = " << (float)(((Vec2f)(grad_x.at<Vec2f>(i, j)))[0]) << endl;
    et ça ne convient pas. J'obtiens même des "not a number" (NaN).
    Pour info, voici les valeurs des attributs du headers de grad_x. A ce sujet, je suis confus sur la valeur de depth. Estc-e que ça signifie que la valeur est codée sur 3 bits ou sur 3 octets ( d'après ce que j'avais noté, cela correspond à 3 bits )

    channels = 1
    step = 800
    depth = 3

  7. #7
    Membre éprouvé
    Homme Profil pro
    Ingénieur 3D
    Inscrit en
    Avril 2008
    Messages
    400
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Ingénieur 3D

    Informations forums :
    Inscription : Avril 2008
    Messages : 400
    Points : 968
    Points
    968
    Par défaut
    Apres un petit tour dans la doc, je me rends compte que leur opérateur ne marche pas exactement comme je le pensais. Je pensais qu'il marchait que sur des images en gris et qu'il retournait le gradient x et y dans une image a 2 channels. En fait, au lieu d'utiliser un cv::Vec, je crois qu'il faut tout simplement un char (ou un float si ton image de base était en floats)...
    Ton problème initial venait probablement du fait qu'OpenCV stocke ses valeurs en unsigned char (donc toujours positif). Si tu passes en char, tu te retrouveras avec des valeurs transposées sur l'intervalle -127,127.
    Pour la valeur de depth, il se peut que ce soit juste le code de l'enum correspondant a "rgb unsigned char" ou "greyscale unsigned char", quelque chose de ce genre.

  8. #8
    Membre régulier
    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2008
    Messages
    138
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Communication - Médias

    Informations forums :
    Inscription : Janvier 2008
    Messages : 138
    Points : 70
    Points
    70
    Par défaut
    Ca avance

    Désormais, je parviens à afficher les bonnes valeurs (en utilisant le typage char), mais entre chaque valeur est lue une autre valeur ( toujours 0 ).

    Par exemple, si grad_x contient [ 0, 2, 10, 26, 52, 64, 56, 44 ]

    et bien le code ci dessus me donne [ 0, 0, 2, 0, 10, 0, 26, 0, 52, 0, 64, 0, 56, 0, 44 ]

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    for( int i = 0; i < grad_x.rows; i++ )
        {
            for ( int j = 0; j < grad_x.cols; j++ )
            {
                cout << "Gx = " << (float)(char)(grad_x.at<char>(i, j)) << endl;
            }
        }
    C'est bizarre que je lise une case qui vaut 0 entre chaque bonne valeur.

  9. #9
    Membre éprouvé
    Homme Profil pro
    Ingénieur 3D
    Inscrit en
    Avril 2008
    Messages
    400
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Ingénieur 3D

    Informations forums :
    Inscription : Avril 2008
    Messages : 400
    Points : 968
    Points
    968
    Par défaut
    Apres un petit tour dans le code source d'OpenCV j'ai pu voir que le depth=3 veut en fait dire "CV_16S", et donc "16 bits signed", ce qui devrait correspondre au type short et non char.

  10. #10
    Membre régulier
    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2008
    Messages
    138
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Communication - Médias

    Informations forums :
    Inscription : Janvier 2008
    Messages : 138
    Points : 70
    Points
    70
    Par défaut
    Oui effectivement c'est bien cela !

    Merci beaucoup. Je galère toujours avec la correspondance des types dans les Mat. Pourriez-vous me donner l'endroit dans le code d'OpenCv où trouver l'information ?

    Encore merci pour votre aide toujours instructive.

    Ps ; la solution finale pour accéder au gradient horizontal est donc :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
        Sobel( src_gray, grad_x, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT );
        for( int i = 0; i < grad_x.rows; i++ )
        {
            for ( int j = 0; j < grad_x.cols; j++ )
            {
                cout << "Gx = " << ((short)(grad_x.at<short>(i, j))) << endl;
            }
        }

  11. #11
    Membre éprouvé
    Homme Profil pro
    Ingénieur 3D
    Inscrit en
    Avril 2008
    Messages
    400
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Ingénieur 3D

    Informations forums :
    Inscription : Avril 2008
    Messages : 400
    Points : 968
    Points
    968
    Par défaut
    Dans types_c.h, a la ligne 551 (et ligne 563 pour la macro de création de types multi channels).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    #define CV_8U   0
    #define CV_8S   1
    #define CV_16U  2
    #define CV_16S  3
    #define CV_32S  4
    #define CV_32F  5
    #define CV_64F  6
    Je pense pas qu'il soit très important de connaitre la valeur associée aux types (a part peut être dans le cas d'un debug), mais savoir ou trouver le nom est quand même utile (et je les oublie souvent, ceux la). A ne pas oublier: pour le multi channel, il faut rajouter C et le nombre de channels dans le nom du type => CV_8UC3 pour du rgb sur 24 bits.

    Sinon, pas besoin de caster ton résultat en short, la fonction at<short>() retourne déjà en short.

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

Discussions similaires

  1. Déterminer des angles depuis des vecteurs
    Par fjxokt dans le forum Mathématiques
    Réponses: 8
    Dernier message: 13/06/2009, 12h14
  2. Comment récupérer la classe window d'une application wpf depuis une application ext
    Par rsiwpf dans le forum Windows Presentation Foundation
    Réponses: 10
    Dernier message: 14/10/2008, 15h10
  3. Réponses: 2
    Dernier message: 27/06/2008, 16h57
  4. Réponses: 2
    Dernier message: 24/04/2008, 17h31
  5. Réponses: 11
    Dernier message: 16/10/2004, 18h14

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