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

Langage C++ Discussion :

Suite du sujet matrice de booleen / traitement vidéo en temps réel


Sujet :

Langage C++

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 16
    Par défaut Suite du sujet matrice de booleen / traitement vidéo en temps réel
    suite de ce sujet qui a du être fermé à cause de sa dérive sur les macros/ fonctions inlines

    Je n'ai ni besoin ni de l'un ni de l'autres car j'appelle la fonction d'accès à la matrice à un seul endroit de l'objet, donc pas besoin de macro: j'ai écrit explicitement le code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    bool Critere::estPeau(int i, int j, int k) {
    	return (bool)(estPeauTable[i][j][k>>5] & (1<<(k & 31)));
    }
     
    void Critere::setEstPeauTable(int i, int j, int k, bool b) {
    	if (b) { 
    		estPeauTable[i][j][k>>5] |= (1 << (k & 31)); 
    	} else { 
    		estPeauTable[i][j][k>>5] &= ~(1 << (k & 31));
    	}
    }
    Mmmm.... Donc, en résumé, sur les 16 millions de couleurs possibles dans ce système, tu as fais une partition entre "couleur de peau" et "autres", c'est bien ça ?
    Oui c'est bien ca!

    Ta matrice est-elle initialisée statiquement (ex : calcul de la plage couleur de la peau en HSV ou Yuv et conversion RGB, calculé sur des images d'étalonnage), ou dynamiquement (tu dis "cette zone est de la peau" sur une frame de la vidéo, et il stocke les valeurs dans la matrice) ?
    Elle est allouée statiquement et peut être améliorée dans la partie réglage du programme, par conte elle ne bouge plus pour la partie en temps réel.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Au final, quel est (approximativement, bien sûr !) le pourcentage de "nombre de couleurs FALSE" et de "nombre de couleurs TRUE" ?
     
    En fonction de ces éléments, il sera peut-être possible d'améliorer encore plus cette partie...
    Je viens de faire le calcul et j'ai du 14% de TRUE (la zone 3d étant en plus connexe)
    (pour le stockage d'un fichier sauvegarde, il y aura bien sur une optimisation des longues chaines de 1 et de 0, mais pour le temps réel, je doute que ca soit bon de réaliser une compression des données)

    En fait je part d'un critere de peau mathématique trouvé dans la littérature sur le sujet:

    R, G et B correspondent au valeurs RGB du pixel considéré.

    Le reste, c'est des constantes float à déterminer au cas pas cas (dépend de la cam, de l'environnement... J'ai pu faire un programme qui s'en occupe)

    La zone de l'espace de peau ainsi modélisée correspond à un cône dans l'espace RGB

    L'idée est donc de faire les calculs pour les 16 millions de pixels une fois pour toute et de pouvoir peaufiner encore ce critere.

    N'empêche que la vitesse d'execution est quasiment la même lorsque je lui donne le systeme précédent que lorsque je lui demande d'accéder au résultat déja calculé dans la matrice 3d.

    Ca doit être lié au parcourt de l'image sous opencv qui peut être n'est pas assez performant pour un traitement pixel par pixel...

    (Pour info le simple traitement du flux webcam avec cet accès à la matrice me donne du 5images par seconde sur un bon PC Windows, du 0.75 image par seconde sur un eeePC windows 600Mhz et environ 10 images par seconde lorsque le programme est compilé sous mac au lieu de Visual Studio)

    Il faudra peut être que je prenne autre chose que le compilateur de Visual Studio pour les performances...
    Images attachées Images attachées  

  2. #2
    Membre chevronné
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    309
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 309
    Par défaut
    On peut voir la boucle de parcours de la matrice ?

  3. #3
    Membre Expert
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Par défaut
    (pour le stockage d'un fichier sauvegarde, il y aura bien sur une optimisation des longues chaines de 1 et de 0, mais pour le temps réel, je doute que ca soit bon de réaliser une compression des données)
    En fait, si. Là, ta matrice est trop grosse pour tenir dans le cache processeur (surtout avec 1 booléen sur 8 bits). Donc tu te prends des page faults à tour de bras (d'autant plus qu'il y a de couleurs sur l'image), ce qui plombe probablement tes perfs.

  4. #4
    Membre chevronné
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    309
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 309
    Par défaut
    Citation Envoyé par white_tentacle Voir le message
    En fait, si. Là, ta matrice est trop grosse pour tenir dans le cache processeur (surtout avec 1 booléen sur 8 bits). Donc tu te prends des page faults à tour de bras (d'autant plus qu'il y a de couleurs sur l'image), ce qui plombe probablement tes perfs.
    Ses booléens sont sur un seul bit. Mais de toutes façons, il est quand même peu probable qu'une image tienne en cache...
    Et c'est justement pour ça que je lui ai demandé la boucle de parcours, pour vérifier qu'il fait ça dans le bon sens

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 16
    Par défaut
    Il n'y a pas de parcourt de la matrice 3d, sauf lors du remplissage mais à ce moment la vitesse m'importe peu.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    	for (int i=0; i<256; i++) {
    		for (int j=0; j<256; j++) {
    			for (int k=0; k<256; k++) {
    				setEstPeauTable(i,j,k, estPeauCalcule(i, j, k) ); // estPeauCalcule correspond à mon systeme d'equation
    			}
    		}
    	}

    Ce qui est couteux et qui freine le temps réel c'est le parcourt de la frame webcam avec 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
    16
    17
    CvScalar scal;
     
    for(int x=0; x < frame->width ; x++)
    {
    	for(int y=0; y < frame->height; y++)
    	{
    		scal = cvGet2D(frame, y, x);
    		if(crit->estPeau((int)scal.val[0],(int)scal.val[1],(int)scal.val[2]))
    		{
    		        //on marque le pixel d'une autre image "masque" en noir
    		}
    			else
    		{
    			//on marque le pixel d'une autre image "masque" en blanc
    		}
    	}
    }
    des long int de la matrice sont donc lus 0,3 millions de fois par frame.

  6. #6
    Membre Expert
    Avatar de Joel F
    Homme Profil pro
    Chercheur en informatique
    Inscrit en
    Septembre 2002
    Messages
    918
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur en informatique
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2002
    Messages : 918
    Par défaut
    Personnellement j'éviterais le if dans la boucle for et j'utiliserais l'opérateur ternaire si l'image de destination est la même. Certains compilos vectorise tout seul ce genre de truc ou du moins émettent l'instruction correct pour ?: sans saut.

    Ensuite parcours tu bien ta matrice dans le sens de la mémoire histoire de pas péter le cache ?

    oh est pourquoi le cast en int ?

  7. #7
    Membre Expert
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Par défaut
    cvGet2D fait des vérifications de borne à chaque appel, je crois. Et crée un objet temporaire renvoyé. Utilise plutôt directement la matrice imageData, ce sera beaucoup plus performant.

    Sinon, c'est le mauvais sens de parcours (tu parcours ta matrice en colonnes, alors que tu devrais la parcourir en lignes) --> inverse simplement tes deux boucles for :

    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
     
    for(int y=0; y < frame->height; y++)
    {
    	for(int x=0; x < frame->width ; x++)
    	{
    		scal = cvGet2D(frame, y, x);
    		if(crit->estPeau((int)scal.val[0],(int)scal.val[1],(int)scal.val[2]))
    		{
    		        //on marque le pixel d'une autre image "masque" en noir
    		}
    			else
    		{
    			//on marque le pixel d'une autre image "masque" en blanc
    		}
    	}
    }
    Ca devrait aller beaucoup mieux.

  8. #8
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 16
    Par défaut
    Personnellement j'éviterais le if dans la boucle for et j'utiliserais l'opérateur ternaire si l'image de destination est la même. Certains compilos vectorise tout seul ce genre de truc ou du moins émettent l'instruction correct pour ?: sans saut.
    Je ne pensais pas que l'opérateur ternaire pouvait apporter un gain en vitesse. J'ai essayer de l'utiliser ici, mais c'est un cas plus complexe que l'exemple de base min a<b ? a:b
    Je n'ai donc pas réussit à trouver une formulation acceptable par le compilateur.

    pourquoi le cast en int ?
    Juste pour eviter ça:
    warning C4244: 'argument'*: conversion de 'double' en 'int', perte possible de données

    Sinon, c'est le mauvais sens de parcours (tu parcours ta matrice en colonnes, alors que tu devrais la parcourir en lignes) --> inverse simplement tes deux boucles for :
    Ca n'a rien changé à la vitesse.

    cvGet2D fait des vérifications de borne à chaque appel, je crois. Et crée un objet temporaire renvoyé. Utilise plutôt directement la matrice imageData, ce sera beaucoup plus performant.
    Le probleme venait de la! J'ai donc changé le code du parcourt de l'image.
    Voici un exemple de test, ca tourne 5 fois plus vite! (0,4s au lieu de 2s sur un eeePC sachant que la simple capture webcam+affichage demande 0,15s.

    Le parcourt de l'image + le test estPeau ne coute donc plus qu'environ 0,25s!

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    	uchar* ptr;
    	for( int y=0; y<frame->height; y++ ) {
    		ptr = (uchar*) (
    			frame->imageData + y * frame->widthStep
    			);
    		for( int x=0; x<frame->width; x++ ) {
    			if(crit->estPeauCalcule(ptr[3*x],ptr[3*x+1],ptr[3*x+2])) {
    				// action bidon pour voir le resultat:
    				ptr[3*x] = 0;
    				ptr[3*x+2] = 255;
    			}
     
    		}
    	}
    Merci beaucoup!

    J'attends de tester ca sur un PC puissant avec le programme globale et la vitesse devrait être suffisante.

    Reste une optimisation possible:

    En fait, si. Là, ta matrice est trop grosse pour tenir dans le cache processeur (surtout avec 1 booléen sur 8 bits). Donc tu te prends des page faults à tour de bras (d'autant plus qu'il y a de couleurs sur l'image), ce qui plombe probablement tes perfs.
    Remplacer la matrice 3d de booleen par une structure ayant une compression (étant donné que chaque ligne comporte 000...0011...1100....00)
    Peut être le les quelques calculs nécessaires en plus dans ce cas seront compensés par un accès mémoire plus rapide si la structure est logé dans le cache du proc...

    Ca vaut le coup de tenter à votre avis?

  9. #9
    Membre Expert
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Par défaut
    Sinon, c'est le mauvais sens de parcours (tu parcours ta matrice en colonnes, alors que tu devrais la parcourir en lignes) --> inverse simplement tes deux boucles for :
    Ca n'a rien changé à la vitesse.
    J'en suis extrêmement étonné. Soit c'était le bon sens, et ça aurait empiré, soit c'était le mauvais, et ça aurait amélioré les choses. Mais rien, ça m'étonne vraiment (je doute que le compilateur s'octroie le droit de changer ça dans ses optimisations).

    Le probleme venait de la! J'ai donc changé le code du parcourt de l'image.
    Voici un exemple de test, ca tourne 5 fois plus vite!
    Maintenant que tu as fait ça, est-ce que changer le sens de parcours ne fait toujours rien ?

  10. #10
    Membre chevronné
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    309
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 309
    Par défaut
    Citation Envoyé par white_tentacle Voir le message
    J'en suis extrêmement étonné. Soit c'était le bon sens, et ça aurait empiré, soit c'était le mauvais, et ça aurait amélioré les choses. Mais rien, ça m'étonne vraiment (je doute que le compilateur s'octroie le droit de changer ça dans ses optimisations).
    Si cvGet2D trash de toutes façons le cache, ça ne change plus rien. Et si cvGet2D est "lent" devant un cache miss, c'est imperceptible aussi.

  11. #11
    Membre Expert
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Par défaut
    Citation Envoyé par TropMDR Voir le message
    Si cvGet2D trash de toutes façons le cache, ça ne change plus rien. Et si cvGet2D est "lent" devant un cache miss, c'est imperceptible aussi.
    Oui, c'était bien le sens de ma deuxième question .

  12. #12
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 16
    Par défaut
    Maintenant que tu as fait ça, est-ce que changer le sens de parcours ne fait toujours rien ?
    le *char imageData est stocke l'image ligne par ligne, si je veux parcourir colonne par colonne en inversant les boucles for, ca risque d'être plus long.

    Vu que le code actuel fonctionne avec un pointeur qui se place à chaque début de ligne, ca va être contraignant d'inverser les 2 boucles.

    Si je ne créer pas ptr et que j'accède directement à

    frame->imagedata [y * frame->widthStep + 3 * x + i] //i=0 ou 1 ou 2

    Est ce que c'est plus long?

    Recalcule t'il vraiment y * frame->widthStep à chaque changement de x?

    Si oui peut être devrais-je travailler avec des variables intermediaires... Je vais aller coder tout ca!

Discussions similaires

  1. [Débutant] Acquisition d'une vidéo (en temps réel) via webcam
    Par WhiteTigerZ dans le forum Images
    Réponses: 2
    Dernier message: 12/03/2011, 00h49
  2. Réponses: 0
    Dernier message: 19/05/2010, 10h25
  3. Traitement vidéo en temps réel
    Par Florian V dans le forum LabVIEW
    Réponses: 17
    Dernier message: 26/10/2009, 10h21

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