Détecter un point du centre d'une cible...

Détecter un point du centre d'une cible... - C++ - Programmation

Marsh Posté le 21-05-2004 à 13:19:26    

Bijour les gens,
 
Voilà, j'ai un petit problème pour détecter un point particulier de mon écran.  :(  
Imaginez une image qui resemblerait à une série de cercles concentriques, un peu comme une cible de tir à l'arc ou de fléchettes. Les cercles sont noirs et l'espace entre les cercles est laissé en blanc. Mon problème est simple : Comment est-ce que je peux récupérer les coordonnées d'un des points contenus dans le cercle le plus petit (le cercle du milieu de la cible), n'importe lequel fait l'affaire, pourvu qu'il soit contenu dans le centre de la cible... Vous voyez le truc hein?!  :)  
 
J'ai tenté de coder ca en effectuant une boucle sur chaque ligne et en incrémentant un compteur dès qu'un pixel noir est lu. Je garde alors le numéro d'une des lignes qui contiennent le plus de pixels noirs (en excluant les lignes pour lesquelles deux pixels noirs sont adjacents (partie supérieure d'un cercle par ex.)) Ce numéro de ligne est une de mes coordonnées recherchées. Je n'ai plus qu'à effectuer la même opération sur les colonnes et j'aurai ma deuxième coordonnée.
Voici le bout de code que j'ai écrit :

Code :
  1. int FindCenter (int picwidth, int picheight, CDC* pDC)
  2. {
  3. int ord;
  4. int *countpix;
  5. countpix = new int[picheight];
  6. for (int k = 1; k <= picheight; k++)
  7.  countpix[k] = 0;
  8. for (int i = 1; i <= picheight; i++)
  9. {
  10.  for (int j = 1; j <= picwidth; j++)
  11.  {
  12.   if (pDC->GetPixel (j,i) == RGB (0, 0, 0) &&
  13.       pDC->GetPixel (j+1, i) == RGB (255, 255, 255)
  14.   {
  15.    countpix[i] ++;
  16.   }
  17.  }
  18.  if (countpix[i] < countpix[i-1])
  19.  {
  20.   ord = i-1;
  21.   break;
  22.  }
  23. }
  24. return ord;
  25. }


Bon, mais apparemment il y a qqchose qui ne fonctionne pas dans ce code et je prévois que pour une image de la taille de mon écran, l'opération sera longue...  :cry:  
Est-ce que vous avez des idées d'algorithmes, un peu plus rapides? Comment est-ce que je pourrais coder ca plus efficacement?
Toutes vos suggestions sont les bienvenues. Par avance merci.

Reply

Marsh Posté le 21-05-2004 à 13:19:26   

Reply

Marsh Posté le 21-05-2004 à 13:29:29    

le centre de la cible correspond au centre de l'image?

Reply

Marsh Posté le 21-05-2004 à 13:34:43    

Ben non justement... C'est une cible qui peut avoir une taille variable (nombre variable de ronds concentriques) et qui peut être affichée n'importe où à l'écran.
C'eût été trop simple sinon... :)

Reply

Marsh Posté le 21-05-2004 à 13:35:51    

il n'y a que ta cible à l'écran? ou il y a d'autres objets?

Reply

Marsh Posté le 21-05-2004 à 13:41:11    

Effectue une correlation du motif de la cible sur l'image.
Si tu n'as qu'une cible dans l'image, le max de corrélation te donne la position de la cible.
 
 
 

Reply

Marsh Posté le 21-05-2004 à 13:46:16    

moktar1er -> Il n'y a que ma cible à l'écran, pas d'autres objets.  
Joel F -> Je ne connais pas le motif de la cible à l'avance :(...
Y aurait pas un truc plus simple?... :) Qu'est-ce que vous pensez de mon idée au départ? A votre avis, ca peut fonctionner?

Reply

Marsh Posté le 21-05-2004 à 14:06:42    

bah s'il n'y a que la cible: détection d'objet->boîte englobante->centre de la cible

Reply

Marsh Posté le 21-05-2004 à 14:12:07    

ta cible tu en as un modéle : série de cercle concntrique.
Apres par corréllation successive avec un algo scale-independant, tu va retrouver la meilleur estimation de la position/rayon de ta cible.


Message édité par Joel F le 21-05-2004 à 14:12:20
Reply

Marsh Posté le 21-05-2004 à 14:41:29    

Bon, j'ai oublié de vous dire que je suis débutant... :)
J'aime bien l'idée de la boîte englobante, mais comment tu peux coder ca, en gros.

Reply

Marsh Posté le 21-05-2004 à 15:04:43    

bah si le fond de ton image est uniforme, tu va chercher le premier pixel de couleur différente du fond dans les 4 directions:
- tu prends 1 boîte qui fait la taille de ton image
- te déplace le coté gauche vers la droite jusqu'à ce que tu rencontre 1 point de couleur différente du fond
- la même chose pour les 3 autres cotés
- et normalement, le centre de ta boite, c'est le centre de ton cercle

Reply

Marsh Posté le 21-05-2004 à 15:04:43   

Reply

Marsh Posté le 21-05-2004 à 16:32:11    

Reply

Marsh Posté le 24-05-2004 à 09:19:57    


 
alors là, proposer un hough pour un problème comme le sien c'est super intelligent sisi...
il peut faire un super algo de detection d'objet par composantes connexes qui va lui trouver sa cible en quelques millisecondes, mais toi tu lui proposes de se lancer sur une usine à gaz
en plus, que la cible soit circulaire ou autre on n'en a rien à battre à priori. ce n'est pas une detection de cercle qu'il cherche, c'est une detection de centre d'objet.
donc là dessus, hough, non! :o

Reply

Marsh Posté le 24-05-2004 à 10:09:05    

Salut tout le monde,
Mon problème a légèrement évolué...  :) Il se trouve que je peux utiliser la souris pour cliquer un des points du centre de ma cible et ainsi récupérer les coordonnées du point cliqué. Cela facilite énormément les choses. Merci pour toutes vos suggestions.  :hello:

Reply

Marsh Posté le 24-05-2004 à 10:10:43    

dis... t'aurais pas un exemple d'image à nous poster ici, qu'on fasse mumuse avec [:cupra]

Reply

Marsh Posté le 24-05-2004 à 10:14:11    

j'y connais rien, donc [:cupra]

Reply

Marsh Posté le 24-05-2004 à 10:29:49    

Il s'avère que ma cible composée de cercles concentriques peut également être de forme patatoidale. Donc au lieu d'être une cible toute propre faite avec de jolis cercles, il faut s'imaginer une succession de formes concentriques plus ou moins quelconques (Dessinées sous Paint par ex., la cible peut-être de taille variable, composée d'un nombre aléatoire de patates et située n'importe où sur l'image).
Je veux bien poster un exemple de figure avec laquelle je travaille mais je comprends pas bien comment on fait, il faut d'abord l'uploader qqpart sur un http et utiliser les balises [img], c'est ca?
Sinon, est-ce que qqn sait quelle fonction utiliser pour récupérer les coordonnées d'un pixel cliqué avec la souris??

Reply

Marsh Posté le 24-05-2004 à 10:36:33    

- pour ton image oui c'est ça, il faut l'uploader sur un serveur  quelconque
- pour les coordonées, ça dépend un peu de ce avec quoi du développe (MFC, Win32 etc.)
 
edit: pour heberger ton image, tu peux aller sur www.imageshack.us
et tu postes ensuite l'url de ton image entre [img] et [/img]


Message édité par Moktar1er le 24-05-2004 à 10:38:41
Reply

Marsh Posté le 24-05-2004 à 10:41:35    

Je développe avec les MFC sous Visual C++ 6.0. Je pensais pouvoir utiliser GetDeviceCaps mais c'est pas bon, la fonction ne permet pas de récupérer les coordonnées du pixel.
 Pour l'exemple d'image, je crois qu'il serait plus simple que tu en traces une sous paint par toi-même, tu vois à peu près à quoi ca ressemble?? Y a intérêt parce que j'ai fait de super descriptions... :)

Reply

Marsh Posté le 24-05-2004 à 10:46:19    

genre ça?
http://img19.imageshack.us/img19/1055/cible.PNG
 
pour les MFC, désolé, j'ai utilisé ça ya trop longtemps maintenant :D tu peux sûrement trouver ton bonheur dans la MSDN

Reply

Marsh Posté le 24-05-2004 à 10:52:56    

Bon, apparemment mes explications étaient pas si claires  :D ...
Ca serait plutôt genre ca :
http://img12.imageshack.us/img12/6593/patates.jpg
Comment est-ce que je peux alors récupérer les coordonnées d'une des points de la patate la plus petite, celle qui se trouve au milieu de ma pseudo cible.
En fait, pour tout vous dire, mon application doit ensuite colorier chaque anneau de la cible d'une couleur différente. J'utilise alors les coordonnées d'une ligne horizontale passant par toutes les patates, je parcours la ligne, et chaque fois que je passe d'un anneau à un autre, je colore avec une autre couleur, si c'est pas déjà fait.
Existe-t-il un algorithme classique, connu, qui peut exécuter ce genre d'opération??

Reply

Marsh Posté le 24-05-2004 à 11:04:55    

pour le remplissage c'est simple comme bonjour, tu fais appel à ton ami "flood fill", vu la taille de tes anneaux, ça devrait passer sans problèmes (et rapide en plus)
pour la detection de centre, tu pars d'un coin de l'image et tu recherche 1 point noir; le premier que tu trouves c'est forcément un point du contour le plus exterieur -> suivi de contour + etiquetage
tu reprends ta recherche de point noir non etiquetté et dès que tu en trouves 1, re-suivi de contour et re-etiquettage
et ainsi de suite, jusqu'à ce que tu ne retombe sur 1 point noir de la même etiquette que la dernière que tu as créé; dans ce cas tu as trouvé ton dernier cercle
et voilà :D

Reply

Marsh Posté le 24-05-2004 à 11:08:34    

Ok ca m'a pas l'air trop compliqué, mais qu'est-ce que tu entends par étiquetage?? Il ne faudrait pas plutôt partir d'un coin de la boîte englobante?

Reply

Marsh Posté le 24-05-2004 à 11:14:24    

etiquettage: tu donnes une "couleur" à chaque point du premier contour (genre 0,0,1)
pareil (0,0,2) aux points du 2ème contour etc.
tu trouveras facilement des infos sur le net à propos de "suivi de contour" et "etiquettage"
ça fait partie des bases de l'analyse d'image ;)
sinon plus bête:
tu pars de l'exterieur et tu cherches 1 point noir: si tu en trouves 1, tu avances tant que c'est noir (pour pallier au problème d'épaisseur de trait), et dès que tu sors du contour, tu remplis (flood-fill) avec 1 couleur
et après tu déroules:
- tant que non noir j'avance
- tant que noir j'avance
- je remplis avec une nouvelle couleur

Reply

Marsh Posté le 24-05-2004 à 11:19:41    

Ok merci. Actuellement j'utilise la deuxième solution. Je pense que je vais la garder, elle a l'air de fonctionner correctement, il ne me reste plus qu'à choper la bonne ligne pour effectuer l'opération...

Reply

Marsh Posté le 24-05-2004 à 12:37:01    

moktar1er a écrit :

alors là, proposer un hough pour un problème comme le sien c'est super intelligent sisi...


J't'emmerde bonhomme! Il veut un algo de recherche de centre; comme par hasard, je tombe sur le lien 5 min après; je reviens donc gentillement pour lui proposer. Après, il en fait ce qu'il veut! Au pire, ce sera bon pour sa culture et celle de tout ceux qui viendront lire le post. Bref, j'vois pas l'intéret de ta critique!

Reply

Marsh Posté le 24-05-2004 à 13:41:28    

torpe23 a écrit :

J't'emmerde bonhomme! Il veut un algo de recherche de centre; comme par hasard, je tombe sur le lien 5 min après; je reviens donc gentillement pour lui proposer. Après, il en fait ce qu'il veut! Au pire, ce sera bon pour sa culture et celle de tout ceux qui viendront lire le post. Bref, j'vois pas l'intéret de ta critique!


 
euh... déjà tu peux commencer par faire attention à tes mots
ensuite ma critique je te l'ai déjà exposée plus haut:
hough = terriblement lent = Hors Sujet par rapport à sa demande à lui (patatoïdes)
donc voilà pour pourquoi Hough ne sert à rien dans ce cas

Reply

Marsh Posté le 25-05-2004 à 12:59:32    

Bon, alors j'ai écrit une petite fonction censée me renvoyer le numéro de la dernière ligne passant par toutes les patates de ma cible :

Code :
  1. int FindLine (int picwidth, int picheight, CDC *pDC)
  2. {
  3. int counter, ycoord;
  4. int *tab, *tot;
  5. tab = new int[picwidth];
  6. tot = new int[picheight];
  7. for (int i = 1; i <= picheight; i++)
  8. {
  9.  tot = 0;
  10.  counter = 0;
  11.  for (int j = 1; j <= picwidth; j++)
  12.  {
  13.   if (pDC->GetPixel (j,i) == RGB (0, 0, 0))
  14.    tab [j] = 1;
  15.   else
  16.    tab [j] = 0;
  17.  }
  18.  for (int l = 1; l <= picwidth; l++)
  19.   if (tab[j] >= tab[j-1] && tab[j] > tab[j+1])
  20.    counter ++;
  21.  tot[i] = counter;
  22. }
  23. for (int k = 1; k <= picheight; k++)
  24. {
  25.  if (tot[k] > tot[k+1])
  26.  {
  27.   ycoord = k;
  28.   break;
  29.  }
  30. }
  31. return ycoord;
  32. }


Seulement bien évidemment ca ne tourne pas. Explications : L'image a une largeur [i]picwidth et une hauteur picheight. Je déclare un tableau tab, de taille picwidth. Pour chaque ligne, je remplis ce tableau tab avec des 1 ou des 0, selon que le pixel lu soit noir ou blanc. Une fois que ma ligne est lue et que mon tableau tab est rempli, je le parcourt à nouveau et je détecte le nombre de passages de 1 à 0 (front descendant). Je stock ce nombre dans le tableau tot. Ainsi tot[i] contient le nombre de fronts descendants de i ème ligne.
Une fois que mon tableau tot est rempli, je cherche l'indice i tel que tot[i] soit supérieur à tous les autres tot[k] (k != i). Bien entendu il y a plusieurs lignes pourlesquelles tot[i] est max : ce sont toutes lignes passant par ma patate du milieu. Je sélectionne la dernière par un test tout simple :

Code :
  1. if (tot[k] > tot[k+1])


En effet les valeurs contenues dans tot[i] sont croissantes en fonction de i, jusqu'a cette fameuse ligne dont je veux récupérer la position.
Bon, j'espère que tout est clair et que vous allez me dire ce bug, parce qu'apparemment ca môrch pô...  :??:  
Je retourne bien le numéro de la ligne avec

Code :
  1. return k;

?

Reply

Marsh Posté le 25-05-2004 à 13:15:01    

En fait je me complique un peu la vie, j'ai pas besoin de deux tableaux et de ces 1 et ces 0, je peux faire ca directement et m'épargner une étape superflue :
int FindLine (int picwidth, int picheight, CDC *pDC)

Code :
  1. {
  2. int counter, ycoord;
  3. int *tot;
  4. tot = new int[picheight];
  5. for (int i = 1; i <= picheight; i++)
  6. {
  7.  counter = 0;
  8.  for (int j = 1; j <= picwidth; j++)
  9.   if (pDC->GetPixel (j,i) == RGB (0, 0, 0) &&
  10.    pDC->GetPixel (j+1, i) == RGB (255, 255, 255))
  11.    counter ++;
  12.  tot[i] = counter;
  13. }
  14. for (int k = 1; k <= picheight; k++)
  15. {
  16.  if (tot[k] > tot[k+1])
  17.  {
  18.   ycoord = k;
  19.   break;
  20.  }
  21. }
  22. return ycoord;
  23. }


Donc en fait, ce qui merde, à mon avis, c'est la recherche de la position du plus grand élément dans tot... Des suggestions?

Reply

Marsh Posté le 25-05-2004 à 13:20:05    

Mais évidemment que ca merde, suis allé trop vite là. Ma condition

Code :
  1. if (tot[k] > tot[k+1])

est valable pour plus d'une ligne... Ferais mieux de réfléchir un peu...  

Reply

Marsh Posté le 25-05-2004 à 13:20:43    

déjà, fais tes boucles:
i=0; i<picheight; i++
j=0; j<picwidth; j++
k=0; k<picheight; k++
 
parceque là tu fais des débordements

Reply

Marsh Posté le 25-05-2004 à 13:24:53    

?? Pourquoi? Ca colle pas si je vais de 1 à picwidth? C'pareil non?

Reply

Marsh Posté le 25-05-2004 à 14:11:15    

bah nan
ton tableau a picheight cases
vu qu'en C les indices commencent à 0, l'indice max c'est picheight-1

Reply

Marsh Posté le 25-05-2004 à 15:07:09    

Oui exact, j'ai corrigé ca, et je crois que c'est ca qui buggé en fait... Donc voici ma fonction finale, qui fonctionne, tests à l'appui :

Code :
  1. int FindLine (int picwidth, int picheight, CDC *pDC)
  2. {
  3. int counter, ycoord;
  4. int *tot;
  5. tot = new int[picheight];
  6. for (int i = 0; i < picheight; i++)
  7. {
  8.  counter = 0;
  9.  for (int j = 0; j < picwidth; j++)
  10.   if (pDC->GetPixel (j,i) == RGB (0, 0, 0) &&
  11.    pDC->GetPixel (j+1, i) == RGB (255, 255, 255))
  12.    counter ++;
  13.  tot[i] = counter;
  14. }
  15. for (int m = 0; m < picheight; m++)
  16.  if (tot[m] > tot[m+1])
  17.  {
  18.   ycoord = m;
  19.   break;
  20.  }
  21. return ycoord;
  22. }


Merci pour le coup de pouce.
Si tu utilises également cette fonction :

Code :
  1. void ChangeColor (int picwidth, int picheight, CDC* pDC)
  2. {
  3. int k = 0;
  4. int ymid = FindLine (picwidth, picheight, pDC);
  5. for (int l = 0; l < picwidth; l++)
  6.  if (pDC->GetPixel (l, ymid) == RGB (0, 0, 0) &&
  7.   pDC->GetPixel (l-1, ymid) == RGB (255, 255, 255))
  8.  {
  9.   CBrush* new_brush = new CBrush (RGB(255-20*k, 255-20*k, 255-20*k));
  10.   pDC->SelectObject (new_brush);
  11.   pDC->ExtFloodFill (l-1, ymid, RGB (255,255,255), FLOODFILLSURFACE);
  12.   k++;
  13.  }
  14. }


tu peux tester avec l'image que j'ai postée un peu plus haut, ca tourne. Encore une fois merci pour ton aide moktar1er et merci également aux autres pour leurs suggestions.

Reply

Marsh Posté le 25-05-2004 à 15:08:24    

j'avoue que je n'ai pas regardé le code dans le détail, mais le principal est que ça marche comme tu veux
content d'avoir pu rendre service

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed