GeckoGeek.fr

Paradigme d'un lézard

Mercredi 17 Mai 2017

Tutorial OpenCV : Isoler et Traquer une Couleur

Par Lya le 24/03/2010 dans Programmation, Réalité Augmentée | 56 commentaires

Continuons sur la lancée d’OpenCv. Nous avons vu dans le précédent billet comment récupérer le flux d’une vidéo ou d’une webcam. Avant d’afficher ce dernier, il est possible de faire subir aux images tout un tas de traitements (niark). L’un d’entre eux, qui est amusant et relativement facile à réaliser avec OpenCV, est le tracking d’objet.

Par les détails ou par la couleur

Globalement avec OpenCV vous pouvez utiliser facilement deux types de méthodes pour traquer des objets. Celles qui repèrent des détails caractéristiques de l’objet et celles qui se basent sur la détection de couleur. Le choix dépend de vos conditions.

Si votre objet contient des détails et qu’il n’a pas de couleur particulière (ie qui se détache fortement de son environnement) vous préférerez la première méthode. En revanche si vous souhaitez traquer un objet qui n’a pas de forme prédéfinie mais qui possède une couleur repérable alors vous appliquerez la seconde.

Dans ce tutoriel, nous allons nous intéresser à celle qui se base sur la couleur. L’algorithme que nous utiliserons sera légèrement différent (en terme d’utilisation) de celui du Camshift qui est présent dans les exemples fourni avec openCV (et que nous vous conseillons d’essayer d’ailleurs : OpenCV-2.0.0/samples/c/camshiftdemo.c).

Voici quelques vidéos de l’algorithme en action :



Le code est maintenant expliqué pas à pas. La version finale est présentée en bas de page.

Isoler une couleur

Je suppose à partir de là que vous avez votre code qui récupère un flux vidéo. Nous allons donc voir maintenant comment isoler une couleur choisie.

Binarisation

La binarisation consiste à séparer les pixels de l’image en deux classes distinctes, généralement représentées par deux couleurs, le blanc et le noir. Notre première classe correspondra à notre couleur à isoler, la seconde à toutes les autres couleurs. Ainsi, si notre couleur sélectionnée est le rouge, nous verrons sur notre image binarisée tous les éléments rouges apparaître en blanc sur un fond noir (ou l’inverse selon l’attribution des couleurs aux classes).

Si nous voulions isoler plusieurs couleurs, nous devrons réaliser une segmentation pour obtenir plusieurs classes (la binarisation est une segmentation qui produit toujours deux classes).

L’image hsv

Nous allons tout d’abord convertir notre image qui est en BGR (équivalent de RGB mais avec une inversion des canaux bleu et rouge) en HSV (Hue, Saturation, Value, en français : TSV – Teinte, Saturation, Valeur). Nous passons l’image en HSV car ainsi nous pourrons nous baser sur la teinte et la saturation de la couleur en laissant plus libre la « brillance » (V – value) de cette dernière. Ce qui nous permet, en partie seulement, d’éloigner les problèmes liés à l’éclairage.

IplImage *hsv;
hsv = cvCloneImage(image);
cvCvtColor(image, hsv, CV_BGR2HSV);

La conversion de RGB vers HSV est sans perte. Toutes les couleurs RGB ont une correspondance en HSV. (Attention, ce n’est pas le cas pour l’opération inverse, HSV vers RGB.). Remarque : sur OpenCV, la composante Hue n’est pas codée sur 8 bits (0 à 255) comme les autres mais de 0 à 180 (donc perte de précision).

Le masque

Nous devons maintenant créer un masque qui nous permettra de représenter l’image binarisée. Il doit donc être lui aussi de la même taille que notre image originale. Mais il n’a besoin que d’un seul canal (0 à 255).

IplImage *mask;
mask = cvCreateImage(cvGetSize(image), image->depth, 1);

Il nous faut le remplir. Supposons que nous avons la valeur de la couleur que nous recherchons en HSV. Théoriquement, nous devons mettre en blanc (par exemple) tous les pixels ayant les mêmes valeurs HSV que notre couleur. Pratiquement, le résultat ne serait pas très convaincant et nous ne récupérerions que quelques pixels.

Nous allons donc rechercher les pixels qui se situent dans un intervalle autour de cette couleur, et nous laisserons la valeur (V) de côté (ie conditions d’éclairage). Nous utiliserons donc une valeur de tolérance. Ici, elle sera la même pour la teinte et la saturation, mais elle pourrait très bien être différente.
Nous cherchons donc tous les pixels qui vérifient :

H – tolérance <= Hpixel < H + tolérance && S - tolérance <= Spixel < S + tolérance. Une fonction opencv nous permet d’appliquer cette opération directement à tous les pixels de notre image HSV et met à jour directement notre masque. Si l’expression est vérifiée pour un pixel donné de l’image, elle met le pixel correspondant du masque à 255 (blanc), sinon, elle le met à 0 (noir).

cvInRangeS(hsv, cvScalar(h – tolerance -1, s – tolerance, 0), cvScalar(h + tolerance -1, s + tolerance, 255), mask);

Opérateurs morphologiques et isolation d’un objet

Nous avons maintenant une image en noir et blanc qui nous indique où se trouve notre couleur dans l’image par des « tâches blanches ». Or nous voulons suivre un objet de couleur, il va donc nous falloir l’isoler.

Globalement (à moins que vous choisissez la couleur la plus présente dans votre environnement) l’objet correspondra à la tâche la plus grosse et la plus dense. Il nous faut donc nous débarrasser de ces pixels éparpillés ça et là qui étaient contenus dans l’intervalle mais qui ne représentent pas notre objet.

C’est là qu’interviennent les opérateurs morphologiques. Nous allons effectuer une ouverture morphologique. L’ouverture consiste à l’application successive de deux opérateurs morphologiques. D’abord nous effectuons une érosion. Cela nous permet de supprimer les pixels « isolés » qui ne correspondent pas à notre objet de couleur. Ensuite nous effectuons une dilatation qui nous permet de renforcer les groupes denses de pixels (donc notre objet).

Pour rappel, dans notre image nous avons mis le blanc en couleur repérée, donc il nous faut inverser l’ouverture (car elle est basée sur les pixels noirs).

On crée d’abord le noyau de notre opération morphologique. Ici je l’ai choisi un peu plus grand que le noyau de base (3,3) afin de pouvoir supprimer les petits amas de pixels parasites. La forme circulaire a été choisie car elle correspond plus à un environnement extérieur (bien que les tables, armoires, & co soient carrées).

IplConvKernel *kernel;
kernel = cvCreateStructuringElementEx(5, 5, 2, 2, CV_SHAPE_ELLIPSE);

Ensuite nous appliquons l’ouverture (à l’envers) à notre masque (pour les dilatations et érosions, l’image temporaire n’est pas nécessaire).

cvDilate(mask, mask, kernel, 1);
cvErode(mask, mask, kernel, 1);

Avec cela, vous ne verrez apparaître en blanc que votre objet (si sa couleur n’est pas récurrente dans le fond de l’image, cela va de soi).

Choisir la couleur

Le plus simple est de choisir la couleur directement sur l’image du flux vidéo, en cliquant dessus. C’est relativement simple à effectuer. Sur la fenêtre dans laquelle nous affichons le flux, nous ajoutons une fonction de callback sur l’event de la souris :

cvSetMouseCallback("GeckoGeek Color Tracking", getObjectColor);

N’oubliez pas que les fenêtres sont identifiées par leur nom, donc ne vous trompez pas en les désignant.
Quand un événement souris est détecté, la fonction « getObjectColor » est appelée.

Elle est définit ainsi :

void getObjectColor(int event, int x, int y, int flags, void *param = NULL)

Il nous suffit maintenant de la définir.

Avant tout, il faut détecter l’événement « clic gauche » :

if(event == CV_EVENT_LBUTTONUP)

Ensuite, nous convertissons l’image (qui est en BGR) en HSV comme nous l’avons vu précédemment et nous récupérons le pixel sélectionné (en x, y) :

CvScalar pixel;
pixel = cvGet2D(hsv, y, x);

Il ne reste qu’à mettre à jour les valeurs de notre couleur choisie :

h = (int)pixel.val[0];
s = (int)pixel.val[1];
v = (int)pixel.val[2];

Traquer la couleur

En analysant le déplacement de la « tâche » qui représente notre objet sur les images binarisées nous pouvons le suivre. Une possibilité est de calculer le centre de la tâche et de regarder le déplacement de ce centre.

Calcul du barycentre

Il nous faut récupérer les coordonnées x et y de notre tâche afin de calculer son barycentre. Pour cela nous parcourons le masque et nous additionnons les coordonnées (les x et les y respectivement) de tous les pixels blancs (255) dans notre cas. Nous comptons au passage le nombre de point afin de pouvoir diviser nos sommes.

for(x = 0; x < mask->width; x++) {
	for(y = 0; y < mask->height; y++) {
		if(((uchar *)(mask->imageData + y*mask->widthStep))[x] == 255) {
			sommeX += x;
			sommeY += y;
			(*nbPixels)++;
		}
	}
}

Si nous avons une « tâche » dans l’image (donc des pixel blancs), on calcule le barycentre, sinon on donne au centre une valeur en dehors de l’image.

cvPoint((int)(sommeX / (*nbPixels)), (int)(sommeY / (*nbPixels)));

Ajout d’un marqueur et lissage du déplacement

Nous pouvons maintenant ajouter un marqueur sur notre image qui sera centré sur le barycentre calculé. Par exemple sur la vidéo nous avons ajouté un cercle rouge et parfois une image. Vous pouvez y mettre ce que vous voulez.

if (nbPixels > 10)
	cvDrawCircle(image, objectPos, 15, CV_RGB(255, 0, 0), -1);
cvShowImage("GeckoGeek Color Tracking", image);

Nous n’affichons qu’au delà de dix pixels trouvés afin de ne pas afficher de cercle si l’objet n’est pas présent mais que quelques points de couleurs sont détectés.

Par contre, il va nous falloir lisser le déplacement. Vous ne détecterez pas toujours le même nombre de points, surtout si vous bougez très légèrement. Votre objet n’aura pas bougé à l’image, mais votre centre lui (et donc votre marqueur) bougera sans cesse. Il faut aussi donner une impression de suivi lorsque l’objet se déplace très vite (et non une apparition à un endroit puis à un autre sans rien entre les deux).

Du coup, nous allons créer des pas, un pas minimum et un pas maximum, et nous allons considérer la distance sur laquelle il faut se déplacer sur x et sur y. Nous recalculons ce déplacement à chaque image pour mettre à jour la nouvelle position. On sauvegarde dans objectPos la position de l’image précédente (donc la position actuelle avant mise à jour). Le barycentre calculé sur l’image est stocké lui dans objectNextPos, la position à atteindre.

if (abs(objectPos.x - objectNextPos.x) > STEP_MIN) {
	objectNextStepX = max(STEP_MIN, min(STEP_MAX, abs(objectPos.x - objectNextPos.x) / 2));
	objectPos.x += (-1) * sign(objectPos.x - objectNextPos.x) * objectNextStepX;
}
if (abs(objectPos.y - objectNextPos.y) > STEP_MIN) {
	objectNextStepY = max(STEP_MIN, min(STEP_MAX, abs(objectPos.y - objectNextPos.y) / 2));
	objectPos.y += (-1) * sign(objectPos.y - objectNextPos.y) * objectNextStepY;
}

Ainsi le déplacement de notre objet est lissé. La méthode que nous utilisons est très simple est très basique. Il est possible de la remplacer par différents algorithmes qui donneront des résultats encore plus satisfaisants.

Libération de la mémoire

N’oubliez pas qu’à chaque fois que vous créez un objet, il vous faudra le supprimer.

Il faut donc supprimer (je cite en vrac) les images hsv, le masque, et le noyau des opérateurs morphologiques.

cvReleaseImage(&hsv);
cvReleaseImage(&mask);
cvReleaseStructuringElement(&kernel);

Et bien sûr les fenêtres et la capture.

Tout en un

A noter que dans l’algorithme présenté, les paramètres ont été réglés pour que l’on puisse détecter aussi bien des gros comme des tout petits objets et des couleurs très variées voir parfois proche de l’environnement de fond. Dans la vidéo d’illustration, Pour tous les objets présentés, quelque soit leur forme, leur taille et leur couleur, aucun des paramètres n’a été modifié, nous nous contentions seulement de cliquer sur la nouvelle couleur à traquer. Vous voyez donc bien ainsi qu’il est possible d’améliorer grandement la résultat si vous voulez l’utiliser dans un cas précis avec moins de variations (même forme, même couleur, etc.).

A vous donc de l’adapter à vos besoin et de faire varier les paramètres (tolérance, opérateur morphologiques et noyaux, les pas …). Vous pouvez également sélectionner une zone comme « couleur modèle » plutôt qu’un pixel, ou effectuer une détection de contour sur l’image binarisée avant de calculer le barycentre, adapter la taille du marqueur en fonction des homothéties (objet qui avance et qui recule), si votre objet à une forme orientée vous pouvez effectuer des rotations (préférable de le faire avec une mire quand même, car plus précis), vous pouvez aussi repérer plusieurs objets (composantes connexes), bref il y a beaucoup de possibilités.

Une partie de ces paramètres peut être aussi représentée sous forme de trackbars dans la fenêtre que vous affichez, ce qui vous permettra de les régler plus facilement sans avoir à relancer le programme.

Voici le code que nous venons de voir en entier :

/*
 * Code written by Lya (GeckoGeek.fr)
 */

#include "opencv/highgui.h"
#include "opencv/cv.h"

#include <iostream>
#include <stdlib.h>
#include <stdio.h>

// Maths methods
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))  
#define abs(x) ((x) > 0 ? (x) : -(x))
#define sign(x) ((x) > 0 ? 1 : -1)

// Step mooving for object min & max
#define STEP_MIN 5
#define STEP_MAX 100 

IplImage *image;

// Position of the object we overlay
CvPoint objectPos = cvPoint(-1, -1);
// Color tracked and our tolerance towards it
int h = 0, s = 0, v = 0, tolerance = 10;

/*
 * Transform the image into a two colored image, one color for the color we want to track, another color for the others colors
 * From this image, we get two datas : the number of pixel detected, and the center of gravity of these pixel
 */
CvPoint binarisation(IplImage* image, int *nbPixels) {

	int x, y;
	CvScalar pixel;
	IplImage *hsv, *mask;
	IplConvKernel *kernel;
	int sommeX = 0, sommeY = 0;
	*nbPixels = 0;

	// Create the mask &initialize it to white (no color detected)
	mask = cvCreateImage(cvGetSize(image), image->depth, 1);

	// Create the hsv image
	hsv = cvCloneImage(image);
	cvCvtColor(image, hsv, CV_BGR2HSV);

	// We create the mask
	cvInRangeS(hsv, cvScalar(h - tolerance -1, s - tolerance, 0), cvScalar(h + tolerance -1, s + tolerance, 255), mask);

	// Create kernels for the morphological operation
	kernel = cvCreateStructuringElementEx(5, 5, 2, 2, CV_SHAPE_ELLIPSE);

	// Morphological opening (inverse because we have white pixels on black background)
	cvDilate(mask, mask, kernel, 1);
	cvErode(mask, mask, kernel, 1);  

	// We go through the mask to look for the tracked object and get its gravity center
	for(x = 0; x < mask->width; x++) {
		for(y = 0; y < mask->height; y++) { 

			// If its a tracked pixel, count it to the center of gravity's calcul
			if(((uchar *)(mask->imageData + y*mask->widthStep))[x] == 255) {
				sommeX += x;
				sommeY += y;
				(*nbPixels)++;
			}
		}
	}

	// Show the result of the mask image
	cvShowImage("GeckoGeek Mask", mask);

	// We release the memory of kernels
	cvReleaseStructuringElement(&kernel);

	// We release the memory of the mask
	cvReleaseImage(&mask);
	// We release the memory of the hsv image
    	cvReleaseImage(&hsv);

	// If there is no pixel, we return a center outside the image, else we return the center of gravity
	if(*nbPixels > 0)
		return cvPoint((int)(sommeX / (*nbPixels)), (int)(sommeY / (*nbPixels)));
	else
		return cvPoint(-1, -1);
}

/*
 * Add a circle on the video that fellow your colored object
 */
void addObjectToVideo(IplImage* image, CvPoint objectNextPos, int nbPixels) {

	int objectNextStepX, objectNextStepY;

	// Calculate circle next position (if there is enough pixels)
	if (nbPixels > 10) {

		// Reset position if no pixel were found
		if (objectPos.x == -1 || objectPos.y == -1) {
			objectPos.x = objectNextPos.x;
			objectPos.y = objectNextPos.y;
		}

		// Move step by step the object position to the desired position
		if (abs(objectPos.x - objectNextPos.x) > STEP_MIN) {
			objectNextStepX = max(STEP_MIN, min(STEP_MAX, abs(objectPos.x - objectNextPos.x) / 2));
			objectPos.x += (-1) * sign(objectPos.x - objectNextPos.x) * objectNextStepX;
		}
		if (abs(objectPos.y - objectNextPos.y) > STEP_MIN) {
			objectNextStepY = max(STEP_MIN, min(STEP_MAX, abs(objectPos.y - objectNextPos.y) / 2));
			objectPos.y += (-1) * sign(objectPos.y - objectNextPos.y) * objectNextStepY;
		}

	// -1 = object isn't within the camera range
	} else {

		objectPos.x = -1;
		objectPos.y = -1;

	}

	// Draw an object (circle) centered on the calculated center of gravity
	if (nbPixels > 10)
		cvDrawCircle(image, objectPos, 15, CV_RGB(255, 0, 0), -1);

	// We show the image on the window
	cvShowImage("GeckoGeek Color Tracking", image);

}

/*
 * Get the color of the pixel where the mouse has clicked
 * We put this color as model color (the color we want to tracked)
 */
void getObjectColor(int event, int x, int y, int flags, void *param = NULL) {

	// Vars
	CvScalar pixel;
	IplImage *hsv;

	if(event == CV_EVENT_LBUTTONUP)	{

		// Get the hsv image
		hsv = cvCloneImage(image);
		cvCvtColor(image, hsv, CV_BGR2HSV);

		// Get the selected pixel
		pixel = cvGet2D(hsv, y, x);

		// Change the value of the tracked color with the color of the selected pixel
		h = (int)pixel.val[0];
		s = (int)pixel.val[1];
		v = (int)pixel.val[2];

		// Release the memory of the hsv image
    		cvReleaseImage(&hsv);

	}

}

int main() {

	// Image & hsvImage
	IplImage *hsv;
	// Video Capture
	CvCapture *capture;
	// Key for keyboard event
	char key;

	// Number of tracked pixels
	int nbPixels;
	// Next position of the object we overlay
	CvPoint objectNextPos;

	// Initialize the video Capture (200 => CV_CAP_V4L2)
 	capture = cvCreateCameraCapture(200);

	// Check if the capture is ok
    	if (!capture) {
		printf("Can't initialize the video capture.\n");
        	return -1;
 	}

	// Create the windows
   	cvNamedWindow("GeckoGeek Color Tracking", CV_WINDOW_AUTOSIZE);
   	cvNamedWindow("GeckoGeek Mask", CV_WINDOW_AUTOSIZE);
	cvMoveWindow("GeckoGeek Color Tracking", 0, 100);
	cvMoveWindow("GeckoGeek Mask", 650, 100);

	// Mouse event to select the tracked color on the original image
	cvSetMouseCallback("GeckoGeek Color Tracking", getObjectColor);

	// While we don't want to quit
	while(key != 'Q' && key != 'q') {

		// We get the current image
		image = cvQueryFrame(capture);

		// If there is no image, we exit the loop
		if(!image)
			continue;

		objectNextPos = binarisation(image, &nbPixels);
		addObjectToVideo(image, objectNextPos, nbPixels);

		// We wait 10 ms
		key = cvWaitKey(10);

	}

	// Destroy the windows we have created
	cvDestroyWindow("GeckoGeek Color Tracking");
	cvDestroyWindow("GeckoGeek Mask");

	// Destroy the capture
	cvReleaseCapture(&capture);

	return 0;

}

Et pour compiler le tout :

g++ monProgramme.cpp -o monProg -lcv -lhighgui

ou bien

g++ monProgramme.cpp -o monProg `pkg-config --cflags opencv` `pkg-config --libs opencv`

Voilà, à vous de jouer ;-]

Commentaires (56)
  1. zeta le 24 Mar 2010 à 00:43

    Tu as un soucis avec tes > qui devienent des > dans les bouts de codes

  2. Lya le 24 Mar 2010 à 10:16

    Effectivement ^^ (l’éditeur qui essaye d’interpréter… :p :p). Hop, c’est corrigé !
    Merci

  3. acetik le 25 Mar 2010 à 00:49

    Sympatique … OpenCV c’est quand meme une librairie bien sympa.
    Quand j’étais à NYU, je m’étais amuser (pas vraiment c’était un projet … :P) à suivre des parties du visages (genre bouche, nez) avec comme objectif d’animer une tête en 3d (je n’ai jamais eu le temps d’en arriver là …).

  4. Vinz le 25 Mar 2010 à 10:05

    Héhé oué j’avais vu une vidéo sur Youtube avec un type qui avait localisé toutes les parties d’un visage et avec tracé des traits de différentes couleurs sur les points clés : sourcils, bouche, nez, joues etc. L’étape d’après aurait été de faire une tête en 3D effectivement :-) mais bon, sa vidéo ramait pas mal, il devait pas avoir bien optimisé la chose, ou tout simplement utiliser le CPA pour reconnaitre chaque partie ^^
    M’enfin, OpenCV fait effectivement des trucs sympas :-) et mélangé avec une meilleur interface comme QT ca peut donner plus de trucs ^^
    Merci de ta lecture !
    A+

  5. Lya le 25 Mar 2010 à 10:31

    Ouais c’est sympa ça de traquer les parties du visage ^^ Il y a le remplacement par une structure 3D, mais ça peut aussi permettre un peu de morphing :p
    On peut toujours faire des trucs funs avec OpenCV 😉
    @+ :-)

  6. swatz le 10 Jan 2011 à 01:39

    Pile Poil ce que je voulais , avec une bonne doc
    Merci kiki ,merci Bibi

  7. goek le 31 Mar 2011 à 01:02

    Voila ce que j’ai fais en 3 mois en partant de rien, sans utiliser aucune bibliotheque. OpenCV, c’est quand meme beaucoup moins prise de tete ! Merci beaucoup pour ce tuto :)

  8. Manuel le 14 Apr 2011 à 16:45

    Salut!

    Mes félicitations pour ce tutoriel il est très bien. J’ai juste une petite question:
    Je dois travailler dans mon école dans projet pour reconnaître une personne par les couleurs de ses vêtements. Je me dispose à utiliser OpenCV j’avoue je suis un “very beginner” j’arrive déjà à faire quelques choses. Mais ce que je voudrais c’est d’avoir une bonne guide d’OpenCV j’au vu que tu as utilisé une fonction “cvInRangeS” et ce n’est pas exactement sur le manuel de refference de C++. Est-ce que tu connais un site web ou un bon manuel d’openCV

    Merci en avance!

    PS : Désolé pour mon français je ne suis pas encore très dué

  9. Vinz le 16 Apr 2011 à 19:29

    Hello,
    Je te recommande le bouquin de référence d’OpenCV, c’est le simple simple et complet. ( http://www.amazon.fr/Learning-OpenCV-Gary-R-Bradski/dp/0596516134/ref=sr_1_1?ie=UTF8&qid=1302978635&sr=8-1 ).
    Sinon pour ton projet, quel intérêt de reconnaître une personne par la couleur de ses vêtements ? C’est faisable, bien sur, mais est-ce assez précis ? sans compter le fait qu’elle changera de vêtements !? Enfin cela dépend du contexte de ton projet 😉
    Bon courage !
    Vincent

  10. Manuel le 19 Apr 2011 à 08:20

    Salut merci de répondre. En fait c’est juste le re-identifier pendant une session d’une journée. La personne entre dans le bâtiment vidéoprotéjé et je le suis par toutes les caméras disponibles dans la bâtiment. Voilà il est peu probable qu’elle change totalement de vêtements.

  11. Vinz le 19 Apr 2011 à 13:26

    Ok je vois. Comme pour suivre une personne durant une JPO ou traquer un élève en somme ^^. Ca reste faisable je pense avec les couleurs même si des méthodes axées sur le visage de la personne (ou ses “dimensions”) seront peut-être plus précises (ou à fusionner). Je te recommande le bouquin cité plus haut 😉 Pense juste au problèmes de luminosité et de distance qui vont influer sur tes résultats. Dans tous les cas je te conseille de faire avant tout traitement une identification des personnes (doit bien y avoir un code opencv gratuit quelque part) pour te faciliter la tâche, quoi que tu fasses.

  12. Manuel le 20 Apr 2011 à 08:43

    Merci j’ai déjà obtenu le bouquin, effectivement il est déjà très utile pour moi. D’autre part effectivement, l’idée finale c’est d’ajouter d’autres caractéristiques à fusionner pour obtenir de bons résultats. Pour l’instant je suis encore dans l’étape du tracking et segmentation du cible.

  13. leat le 20 Apr 2011 à 16:03

    super le tuto :p
    par contre…. un petit bug…
    quand je compile j’ai une fenêtre qui s’affiche avec “Run-Time Check Failure #3 – The variable ‘key’ is being used without being initialized.”
    est ce que vous savez d’où ça vient ?
    merci

  14. Vinz le 20 Apr 2011 à 18:19

    @Manuel : Bon courage !

    @leat : humm je vois. Dans le main(), lors de la déclaration “char key;”, remplacez par : “char key = 0;”, cela ne devrait plus buguer 😉 on a oublié de l’initialisé, d’où le message.

  15. leat le 21 Apr 2011 à 14:30

    heuuu… j’ai encore un petit problème :s
    en fait j’ai changé le bout de code vu que je travail sur open cv 2.2.
    Quand je compile tout, la webcam s’allume, et j’ai les deux fenêtres et les points qui apparaissent mais j’ai 2 fenêtre grise…
    J’ai essayé de passé sur opencv 2.1, mais j’ai un problème de compatibilité…

    merci :p

  16. Vinz le 21 Apr 2011 à 15:22

    Pas encore essayé le code sur la v2.2, désolé ^^ pour les fenêtre grises, c’est bizarre. Le doc officielle indique quelque chose sur de grande modification de la version 2 à la 2.2 ?

  17. Manuel le 26 Apr 2011 à 14:20

    Salut j’ai un petit problème avec l’élimination de l’ombre est-ce que vous avez une idée? Je suis en train d’appliquer la soustraction du fond implémentée dans opencv “background_segm” (GMM) mais il semble que la partie de shadow removal n’est pas implémenté.

  18. Julien le 26 Apr 2011 à 16:55

    Bonjour,
    Pourriez-vous m’indiquer un tuto d’aussi bonne qualité (merci d’ailleurs ;)) mais sur la reconnaissance de forme ou de détails caractéristiques autre que la couleur ?
    Est-il possible, avec OpenCV, de reconnaitre des couleurs invisible à l’oeil nu ? Je pense, par exemple, aux ondes infrarouges dans la mesure, bien sur, où le périphérique de capture les détectent. Merci d’avance de votre réponse.

  19. Lya le 30 Apr 2011 à 09:15

    Bonjour,

    Alors sur le net je n’ai pas trop regardé, mais pour le tracking de détails tu as des exemples dans le bouquin de référence d’O’Reilly cité plus haut. De souvenir il est appliqué sur le tracking d’une plaque d’immatriculation d’une voiture. Ca te donnera les classes de bases à utiliser et les paramètres sur lesquels agir. Sachant qu’il est intéressant après avoir trouvé le détail, de cropper l’image (dans une certaine mesure, en fonction de la vitesse possible de déplacement de l’objet) pour traiter une moins grande surface, et donc aller plus vite.

    Pour l’infrarouge, oui c’est possible, car la caméra proche-infrarouge / infrarouge ou thermique va donner en entrée une image différente (niveaux de gris par exemple => plus c’est blanc plus c’est chaud). Il suffit de déterminer la plage de valeur de ce que l’on veut repérer (très chaud, chaud, froid, etc.). (Attention si on est sur des niveaux de gris, il vaut mieux ne pas utiliser HSV pour l’espace colorimétrique, car le noir / gris c’est “du blanc avec moins de lumière” ou inversement).
    Le mieux c’est de commencer par regarder ce que donne l’image du capteur. Puis choisir l’espace colorimétrique en conséquence et la plage de valeurs associée à la valeur recherchée. Et enfin, corriger le tout par une série de tests.

  20. HoodMan le 2 May 2011 à 10:07

    Salut à tous;
    j’ai juste relevé une petite erreur.
    “La conversion de RGB vers HSV est sans perte”
    De ce que j’ai pu voir sur le net, le Hue dans OpenCV se code de 0 à 179 au lieu de 0 à 255, on a donc une perte de précision pour la couleur lorsqu’on effectue une conversion.
    Pour plus de précision, http://www.shervinemami.co.cc/colorConversion.html
    Sinon super tuto très utile, merci beaucoup =)

  21. Lya le 3 May 2011 à 09:48

    Oui c’est exacte,
    La remarque est vraie dans le cas général : toutes les couleurs en RGB ont une image dans l’espace HSV. Sauf sur OpenCV où la composante Hue (généralement utilisée pour les couleurs rouge, jaune, rose, violet, etc.) n’est plus codée sur 8 bits (0 à 255) comme les autres mais de 0 à 180 (il me semble). Donc effectivement ça entraîne une perte de précision qui peut s’avérer gênante dans certaines applications où l’on a besoin de reconvertir en RGB. Pour une conversion sans perte (de RGB vers HSV), il faut refaire soi-même les fonctions. Voici un exemple : http://www.shervinemami.info/colorConversion.html#fullHueRange
    Merci pour avoir relevé cette précision.

  22. Lya le 3 May 2011 à 18:05

    @Manuel : Dsl ton commentaire était tombé dans les spams.
    Qu’entends-tu par “ombre” ? Dans la détection tu détecte l’objet et son ombre, et quand tu enlèves le fond ça te laisse les deux, c’est ça ? Ou bien tu veux plutôt pouvoir détecter l’ombre pour compléter ton algorithme de soustraction de fond et la supprimer elle aussi ?

  23. pierre-andré le 5 May 2011 à 13:06

    Bonjour,

    J’ai lu ton tuto et je dois dire qu’il est très bien!! Ça ma fait comprendre bien des truc merci.
    Sinon j’ai une petite question, pour le tracking je voulais savoir si on peut utiliser ta méthode pour suivre plusieurs objets a la fois? Par ce que si on calcul le barycentre de tout ce qui est blanc et qu’il y a deux zones blanches (que je veux suivre indépendamment) je vais avoir un seul point entre les deux zones! Comment calculer le barycentre de chaque zone pour en suite dessiner un cercle rouge sur chaqu’une?

    Merci

  24. Lya le 6 May 2011 à 12:56

    Bonjour,
    Oui c’est exacte. Comme je l’évoque dans la dernière partie, c’est effectivement possible, mais il faut utiliser les composantes connexes pour distinguer les différentes “tâches”. Une fois qu’elles sont identifiées, on peut calculer le barycentre de chacune comme tu le dis, et donc suivre plusieurs objets.

  25. pierre-andré le 6 May 2011 à 16:40

    Merci pour la réponse je vais voir dans cette direction.
    Pour le moment je m’étais dirigé vers les ROI j’avais découpé chaque frame en petites ROI pour ensuite faire le même traitement que pour la grande image. Ça marche… mais c’est un peut lent!!

  26. pierre-andré le 11 May 2011 à 16:15

    Bonjour,

    Et bien avec une bonne journée de programmation je suis arrivé à utiliser les composantes connexes pour mon application!
    Encore merci pour l’info!

  27. pierre-andré le 16 May 2011 à 09:58

    bonjour,

    Je voudrais savoir si il était possible d’implémenter opencv pour des applications embarquées?
    Enfin je me doute que oui mais je ne sais pas vraiment quels critères je dois regarder?
    pour le moment j’aimerais utiliser l’une des deux plateformes suivantes:
    Tegra2 (dual core) de NVIDIA
    ou
    TI OMAP4430 (dual core) de Texas Instrument
    Mais comment savoir si elles sont compatible avec opencv?

    merci.

  28. Vinz le 17 May 2011 à 13:15

    Hello,
    Beaucoup de choses sont possibles avec OpenCV en embarqué. Ce qu’il faut surtout regarder (outre la puissance de la machine, on est d’accord) c’est l’OS qui sera sur la machine. Si c’est un Linux classique, alors aucun soucis. Après les performances dépendront de la taille des images à analyser. Pas forcément besoin d’analyser des images de 1200*800 sur quelque chose d’embarqué ?! tout dépend du besoin final pour ce point là.
    Et si en plus y’a du Intel dans le système embarqué, alors rajouter l’IPP peut aussi être intérèssant !
    Vincent

  29. kadi le 15 Jun 2011 à 02:15

    bonjour,

    tré bon tuto , merci , juste je ne dispose pas de cam et j’ai voulu le tester en le passant une video ! pouvez vous m’indiquer comment je peux lire une vidéo par opencv !

    cependant je veux faire la memem chose sauf que je dois segmenter l’image en plusieurs couleur ( 4 couleurs ) comment je peut le faire !

    merci bcp , votre code ma illustré plusieurs choses ^^

  30. Logi le 19 Jun 2011 à 18:16

    pouvez vous m’aider à voies multiples objets de couleur dans une image?
    i permet de détecter la main et la tête avec la couleur de peau détecter.
    Que dois-je faire en premier?

    thx, avant ..

  31. Stéphane le 7 Aug 2011 à 16:43

    J’ai 2 images noires avec sur celle de gauche un point rouge et celle de droite un point blanc. La webcam est allumée, pas d’erreur. Je suis sous opencv2.3 avec codeblocks10.05 et windows vista. Si quelqu’un a une idée…
    Merci d’avance
    Stéphane

  32. sana le 2 Oct 2011 à 12:46

    hi,
    i saw your video of color tracking.it is really interesting.Can you tell me how to track multiple objects of same colors with their x,y coordinates.I am using c.

  33. Laurent le 2 Jan 2012 à 15:15

    sinon pour le tracking y aussi un livre d’exos en français sur opencv : http://www.editions-ellipses.fr/product_info.php?products_id=7231

    spécial débutant en C, notamment pour l’installation d’OpenCV (visual/dev c++)

  34. bvish le 5 Jan 2012 à 13:24

    Bonjour,
    je tien tout d’abord à vous remercier pour ce tutoriel qui m’a beaucoup aider dans le cadre de mon projet(dont le but est de détecter des carrés de même couleur(jaune par exemple) à l’aide d’une camera HD, et de récupérer les coordonnée de chaque carrée).
    Pour l’instant tout marche bien mais à condition d’avoir juste un seul carré, mais dés que je rajoute un autre carré, je le détecte mais j’arrive plus à avoir les bonne coordonnées.
    si vous avez une idée n’hésiter pas
    merci

  35. ahamedBacar le 1 Feb 2012 à 16:56

    Bonjour
    Afin de différencier tes deux couleurs est-ce tu as eu recours à la notion d’analyse factorielle discriminante dans ton algorithme ?
    Cordialement.

  36. Coco le 5 Mar 2012 à 15:09

    Bonjour,
    Je n’arrive pas exécuter ce code. Le build se fait bien mais j’ai ça en debug :

    GNU gdb 6.3.50-20050815 (Apple version gdb-1708) (Thu Nov 3 21:59:02 UTC 2011)
    Copyright 2004 Free Software Foundation, Inc.
    GDB is free software, covered by the GNU General Public License, and you are
    welcome to change it and/or distribute copies of it under certain conditions.
    Type “show copying” to see the conditions.
    There is absolutely no warranty for GDB. Type “show warranty” for details.
    This GDB was configured as “x86_64-apple-darwin”.
    tty /dev/ttys000
    [Switching to process 493 thread 0x0]
    Can’t initialize the video capture.
    Program ended with exit code: 255

    Je travail sous Mac OS X Lion avec openCV 2.3.1 et xcode 4.2.1. Je n’ai pas eu de souci avec ce tuto http://www.geckogeek.fr/lire-le-flux-dune-webcam-camera-video-avec-opencv.html

    Si quelqu’un a une idée :)
    Merci d’avance

  37. Coco le 6 Mar 2012 à 02:24

    En faite c’était à cause de :
    capture = cvCreateCameraCapture(200);
    Je l’ai changé par :
    capture = cvCreateCameraCapture(CV_CAP_ANY);
    Et ça marche.

    Merci pour le tuto 😉

  38. dania511 le 8 Apr 2012 à 02:12

    SVP, j’ai besoin de votre aide.
    je veux binariser une image et puis détecter les zones noirs, les découper, et les afficher .
    “bien sure j’ai utilisée votre fonction “binarisation
    mais le résultat n’est acceptable. le problème ,je croix, que le parcours des pixels ne se fait pas .

    le code est le suivant:

    int main()
    {
    int minX=0;
    int minY=0;
    CvScalar pixel;
    int seuil; //seuil de binarisation

    IplImage *img=cvLoadImage(“persan256.jpg”); //lecture de l’image source

    cvNamedWindow(“Image”, CV_WINDOW_AUTOSIZE); //création de fenetre d’image source
    cvShowImage(“Image”, img); //afficher l’image source dans la fenetre
    cvNamedWindow(“Binarisation”, CV_WINDOW_AUTOSIZE); //création de fenetre d’image binaire
    seuil=127;
    IplImage *img_bin=binarisation(img,seuil); //appel au fonction de binarisation

    cvShowImage(“Binarisation”, img_bin); //afficher l’image binaire dans la fenetre

    int maxX=256;
    int maxY=256;

    for( int i=0; i < 255; i++)
    {
    for (int j=0; j <255; j++)
    {

    recuperer le pixel//
    pixel = cvGet2D(img_bin,i,j);
    printf("pixel=%f\n",pixel.val[0]);
    if( pixel.val[0] == 0)
    {

    if( j < minX)minX=j;
    printf("minX=%d\n",minX);
    if( i maxX)maxX=j;
    printf(“maxX=%d\n”,maxX);
    if( i > maxX)maxX=i;
    printf(“maxX=%d\n”,maxX);

    }

    cvSetImageROI(img_bin, cvRect(minX, minY, maxX-minX, maxY-minY));
    cvNamedWindow(“Roi”);
    cvShowImage(“Roi”, img_bin);
    cvReleaseImage(&img_bin);
    cvWaitKey(0);

    }
    }

    cvWaitKey(0);

    return 0 ;
    }

  39. Ala le 25 Jul 2012 à 04:06

    Salut tout le monde ,
    j’ai besoin d’un programmeur pro en opencv car je veux tracker un objet et j’ai pas réussi . merci

  40. Dwarliz le 5 Sep 2012 à 13:04

    Bonjour à tous.

    Je cherche dans le cadre d’un projet à créer un programme qui attend comme paramètre une vidéo lambda, et qui doit sortir la même vidéo, mais avec les “bandes noires” en haut et en bas de la vidéo en moins (si la vidéo en possède).
    Le format de la vidéo sera, généralement en .avi
    Honnêtement, j’essayai de mon mieux, mais je n’ai pour le moment aboutit à aucun résultat concluant…

    Merci d’avance pour toute proposition pouvant m’aider !

  41. tarek le 19 Nov 2012 à 02:14

    Salut à tous,
    tt d’abord c’est un bon tuto mais j’ai un petit problem quand j’execute le code ça compile sans erreur et ça marche mais il me donne deux fenetre à droite noire avec un point rouge et à gauche blache avec un point blanc.Si quelqu’un peu m’aider j’en ai besion pour mon pfe plzz ;((

  42. rouge le 22 Nov 2012 à 18:05

    je vous demande de m’aider par un prg qui fait la détection d’un pt et donne leur coordonné ds 1 image,svp

  43. lamine le 3 Dec 2012 à 20:52

    salut à tous, svp qui peut m’aider pour le tracking de deux objets de couleurs différents en utilisant une webcam et un arrière plan controlé

  44. JeanRé le 2 Jan 2013 à 14:04

    Excellent tutoriel, clair et suffisamment détaillé.
    Il m’a permis de réaliser un petit bricolage “contrôler un son via webcam”:
    http://youtu.be/1sJyTnXI-Yo

  45. Fellype le 7 Jan 2013 à 01:02

    Excellent tutoriel!!!!
    Merci beaucoup!!!! 😉

  46. Fiphou le 20 May 2013 à 15:09

    Bonjour à tous,
    Tout d’abord merci pour ce tuto, qui permet de découvrir OpenCV en toute simplicité.
    Par contre je pense que l’espace HSV n’est pas le meilleur espace pour faire de la détection de couleur (en revanche il a une approche très simple pour comprendre), je pense que l’espace xyY est plus adapté car la chrominance est déterminé par x et y et la luminosité par Y. Et pour savoir si la couleur visualisé est proche de celle sélectionné il suffit de mesurer la distance entre les deux couleurs à l’aide de la norme 2 (sqrt((x0-x)^2+(y0-x))). J’espère que ça pourra vous être utile.
    Voici un lien très complet sur la colorimétrie
    Cordialement

  47. oga le 1 Jul 2013 à 09:21

    Bonjour
    J’aimerais avoir votre
    Est ce difficile de refaire un minijeu eyetoy (comme sur la Playsatation, de formes tombent de l’ecran et disparaisse quand on les touche ) en c++ avec open cv ? le temps de travail approximatif ?
    Merci

  48. sffronx le 2 Aug 2013 à 10:41

    For latest news you have to pay a visit internet and on world-wide-web I found this web site as a most excellent website for most recent updates.

  49. Florian le 5 Mar 2014 à 09:51

    Bonjour,

    Je débute vraiment en C mais je vais essayer d’être clair ^^ Je souhaite réaliser un traquage de couleur, donc j’ai déjà suivi votre tuto précédent sur la récupération du flux vidéo. Ca marche très bien, et j’ai compris chaque étape. Cependant j’ai du mal à comprendre celui-ci, a partir du moment où je rentre la ligne
    cvInRangeS(hsv, cvScalar(h – tolerance -1, s – tolerance, 0), cvScalar(h + tolerance -1, s + tolerance, 255), mask);
    le programme ne veut plus compiler, prétextant qu’il n’y a pas assez d’arguments..
    J’ai bien entendu essayer de compiler le “tout en un” proposé, mais j’ai 11 erreurs.. Que peut-il manquer ? Et qu’est ce que “g++ monProgramme.cpp -o monProg -lcv -lhighgui” ?

    Merci

  50. Florian le 6 Mar 2014 à 13:20

    Autant pour moi, j’ai trouvé moi même.. Il fallait juste ouvrir un projet en C++ et ça marche niquel !

  51. Johnf134 le 3 Sep 2014 à 16:31

    I like what you guys are up too. This kind of clever work and exposure! bkkafkdbaedk

  52. maxi le 20 Apr 2015 à 14:27

    hi,
    First of all thank you for the tutorial is my great help. I have another concern
    I veudrait namely: how to delineate my detection zone? (ie to ensure that the program remains part of an area)

  53. Coldfire le 26 Oct 2015 à 12:26

    Hi tout le monde !!
    voilà je veux bosser sur la reconnaissance des plaques d’immatriculation avec la bibliothèque opencv mais franchement je ne sais pas par où commencer :p alors si qqun peut m’aider son aide est la bienvenue :p

  54. Coldfire le 26 Oct 2015 à 12:59

    salut tt le monde!!
    voilà je veux réaliser un application opencv pour reconnaitre les plaques d’immatricualtion mais je ne sais pas par où commencer !!
    donnez moi des idées :p

  55. mounia le 8 Jan 2016 à 21:40

    j veux calculer le vecteur de mouvent d un main svp !

  56. lyra le 25 Nov 2016 à 12:18

    si a la place d’un point rouge je veux charger un model 3D et faire en sorte que ce soit lui qui représente le centre de gravité je dois faire comment svp? merci !


Laisser un commentaire