Upload
lecong
View
214
Download
0
Embed Size (px)
Citation preview
Sommaire
C’est durant l’été 2002 que le laboratoire de mécatronique de l’École Polytechnique de
Montréal fut inauguré. Dédié à la programmation de systèmes asservis, on y retrouve un
terrain et deux équipes de trois robots rouleurs joueurs de soccer. Les robots en question
sont en mesures d’évoluer de façon complètement autonome sur le terrain du moment
qu’une certaine intelligence leur est accordée par la programmation en C++ d’un cerveau.
L’intérêt de l’infrastructure du laboratoire réside dans une coopération entre robots
autonomes qui ne pourrait être mieux modélisée qu’en permettant aux robots de coopérer
au sein d’une équipe tout en s’affrontant d’une équipe à l’autre.
Quoique les robots soient aveugles, ils sont en mesure de se repérer par odométrie tant et
aussi longtemps que celle-ci n’est pas faussée par une collision ou par un dérapage. Tout
de même, le ballon est quant à lui un objet inerte qui se doit d’être détecté de façon
précise si on ne souhaite pas assister à du soccer pour aveugles. C’est dans cette
perspective qu’a été développé un système de vision globale qui transmet, par réseau IP,
toute l’information visuelle aux robots.
Le présent rapport a donc pour objectif de décrire l’aspect vision du laboratoire de
mécatronique. Dans un premier temps, la problématique adressée par le système de vision
est décrite en détail au niveau implantation matérielle et au niveau traitement d’image.
L’envergure du système impliquant une méthode rigoureuse, l’aspect méthodologique de
la démarche entreprise fait office de deuxième sujet abordé alors que son implantation
logicielle est décrite en troisième lieu. Finalement, c’est dans une perspective de critique
constructive que les améliorations à apporter au système sont discutées.
ii
INTRODUCTION............................................................................................................. 1
1. LA PROBLÉMATIQUE .............................................................................................. 4 1.1 LA DÉTECTION............................................................................................................ 4 1.2 L’IDENTIFICATION DES ROBOTS.................................................................................. 5 1.3 POSITION ET ORIENTATION DES ÉLÉMENTS ................................................................. 6 1.4 COUVRIR LA TOTALITÉ DU TERRAIN ........................................................................... 7
2. LA MÉTHODOLOGIE................................................................................................ 9 2.1 L’ÉBAUCHE D’UNE SOLUTION..................................................................................... 9
2.1.1 Couvrir tout le terrain à grâce à deux caméras................................................. 9 2.1.2 Une solution populaire mise de côté ................................................................ 12 2.1.3 La segmentation des couleurs : une solution simple et efficace ...................... 13 2.1.4 La détection des régions................................................................................... 14 2.1.5 Le calcul de l’orientation des robots................................................................ 16 2.1.6 L’identification des robots en tant que joueurs d’une équipe.......................... 20
2.2 LE PROTOTYPAGE ..................................................................................................... 21 2.3 L’IMPORTANCE DU DESIGN....................................................................................... 23
3. LES RÉSULTATS ...................................................................................................... 25 3.1 L’ARCHITECTURE DU SYSTÈME................................................................................. 25
3.1.1 Le module de fusion de l’information .............................................................. 27 3.1.2 Le module de capture d’image ......................................................................... 28 3.1.3 Le module d’analyse d’image .......................................................................... 30 3.1.4 Le module interface graphique ........................................................................ 33
3.2 LA CALIBRATION ...................................................................................................... 38 3.2.1 Le patron de calibration................................................................................... 38 3.2.2 L’utilisation du logiciel de calibration win_cali.............................................. 40
3.3 LES ALGORITHMES ET TRAITEMENTS IMPORTANTS ................................................... 42 3.3.1 Le calcul de l’orientation des robots................................................................ 42 3.3.2 L’identification des robots ............................................................................... 43 3.3.3 La fusion de l’analyse d’images provenant de deux caméras.......................... 43
4. DISCUSSION .............................................................................................................. 51 4.1 UNE MÉTHODE D’IDENTIFICATION DES ROBOTS À REVOIR ........................................ 51 4.2 UNE IDÉE POUR ÉLIMINER LES LENTILLES À GRANDE OUVERTURE............................ 52 4.3 LE PATRON DE CALIBRATION .................................................................................... 53 4.4 UNE MOYENNE PLUS PRÉCISE DANS LA FUSION DES IMAGES ..................................... 53
BIBLIOGRAPHIE.......................................................................................................... 55
ANNEXE A – DESCRIPTION DES CLASSES........................................................... 56
iii
Remerciements
À M. Richard Hurteau, mon directeur de projet, pour m’avoir offert l’opportunité de
participer au projet, pour m’avoir enseigné l’importance de la méthode, pour son
attitude toujours aussi rassurante.
À M. Julien Beaudry, mon collègue et ami, pour m’avoir permis de partager sa VISION.
À M. Alexandre Forget, mon collègue et ami, pour son savoir, ses conseils et son aide.
À M. Hong Hai Nguyen, pour ses explications et son aide sur la calibration des caméras.
iv
Liste des tableaux Tableau 2. 1 Valeur du centroïde pour chaque motif........................................................ 19 Tableau 2. 2 Erreur sur la position du centroïde pour chaque motif ................................. 19
Tableau 4. 1 Suggestion de couleurs pour les identificateurs ........................................... 52
v
Liste des figures Figure 2. 1 Aménagement matériel ................................................................................... 10 Figure 2. 2 Portion viable de l'image ................................................................................ 10 Figure 2. 3 Angle d'ouverture de la lentille....................................................................... 11 Figure 2. 4 Encodage des séries de pixels......................................................................... 14 Figure 2. 5 Regroupent des séries de pixels ...................................................................... 15 Figure 2. 6 Exemple de motif de détection ....................................................................... 17 Figure 2. 7 Précision maximale......................................................................................... 17 Figure 2. 8 Précision minimale ......................................................................................... 17 Figure 2. 9 Variation de la précision en fonction de d ...................................................... 18 Figure 2. 10 Motifs utilisés pour les tests de précision ..................................................... 19 Figure 2. 11 Identificateurs de couleurs des robots........................................................... 21 Figure 2. 12 Interface du prototype................................................................................... 23
Figure 3. 1 Architecture du système.................................................................................. 26 Figure 3. 2 Diagramme de classes du module de fusion des images ................................ 27 Figure 3. 3 Diagramme de classes du module de capture d'images .................................. 28 Figure 3. 4 Disposition de l'image en mémoire................................................................. 31 Figure 3. 5 Diagramme de classes du module interface graphique................................... 33 Figure 3. 6 Activation et désactivation de l'affichage ....................................................... 34 Figure 3. 7 Le changement de contexte............................................................................. 35 Figure 3. 8 Utilitaire de configuration du système............................................................ 36 Figure 3. 9 Diagramme de concepts d'un objet médiateur ................................................ 37 Figure 3. 10 L'utilitaire de calibration............................................................................... 39 Figure 3. 11 Le motif de détection de l'orientation ........................................................... 42 Figure 3. 12 La zone de recouvrement.............................................................................. 44 Figure 3. 13 Cas de recouvrement 1.................................................................................. 45 Figure 3. 14 Cas de recouvrement 2.................................................................................. 45 Figure 3. 15 Cas de recouvrement 3.................................................................................. 45 Figure 3. 16 Cas de recouvrement 4.................................................................................. 46 Figure 3. 17 Cas de recouvrement 5.................................................................................. 46 Figure 3. 18 Cas de recouvrement 6.................................................................................. 46 Figure 3. 19 Cas de recouvrement 7.................................................................................. 47 Figure 3. 20 Cas de recouvrement 8.................................................................................. 47 Figure 3. 21 Cas de recouvrement 9.................................................................................. 47 Figure 3. 22 Cas de recouvrement 10................................................................................ 48 Figure 3. 23 Cas de recouvrement 11................................................................................ 48 Figure 3. 24 Cas de recouvrement 12................................................................................ 48 Figure 3. 25 Cas de recouvrement 13................................................................................ 49 Figure 3. 26 Cas de recouvrement 14................................................................................ 49
vi
Dictionnaire des termes et acronymes utilisés
Binarisation : Procédure qui consiste à appliquer un seuillage à une image
couleur ou à une image en tons de gris de telle sorte que les pixels soient éteints
ou allumés. Il en résulte une image en noir et blanc.
Boîte de délimitation : Traduction de l’expression anglaise « bounding box » qui
représente le quadrilatère qui circonscrit une région.
Calibration : Procédure qui permet de corriger la déformation induite dans une
image par la lentille de la caméra et par l’orientation imprécise de celle-ci.
Carte d’acquisition : Pièce d’équipement électronique reliée d’une part à la carte
mère de l’ordinateur et d’autre part à une caméra analogique. La carte
d’acquisition permet d’acquérir les images provenant de la caméra et de les
insérer dans la mémoire de l’ordinateur sous forme numérique.
Découplage : Principe de base de la réutilisation en programmation orientée objet
qui veut qu’un module soit indépendant et utilisable sans avoir recours à d’autres
objets.
Distorsion radiale : Déformation qu’impose le rayon de courbure de la lentille
d’une caméra à une image.
Élément : Toute région d’intérêt détectée dans une image.
FVS : « Falcon Vision System ». C’est le nom qui a été donné au logiciel de
vision décrit dans ce rapport.
Médiateur : Patron de conception logicielle qui consiste à implémenter un objet
faisant le pont entre deux autres objets ou entre deux applications de manière à les
découpler.
Seuil : Limite d’intensité par rapport à laquelle une image est binarisée. Les pixels
dont l’intensité est inférieure à la valeur du seuil sont éteint alors que ceux dont
l’intensité est supérieure à la valeur du seuil sont allumés.
V4L : Le pilote « Video For Linux » qui permet d’interfacer la carte d’acquisition
d’images connue sous le nom de « frame grabber ».
Introduction
Qu’il soit question de l’infiniment petit dans un contexte de nanorobotique ou encore de
l’infiniment grand dans le cadre d’un programme d’exploration spatiale, la coopération
entre robots est à l’ordre du jour. Dans la plus petite des deux échelles, des robots
microscopiques pourraient un jour agir de concert afin de détruire une tumeur cancéreuse
à l’image du sort que réservent nos globules blancs aux corps étrangers. Dans la plus
grande des deux échelles, l’exploration de planètes éloignées aurait tout avantage à se
faire par coopération entres robots. En effet, si on pense à la désintégration du Mars
Climate Orbiter en septembre 1999 dans l’atmosphère de la Rouge, on doit se rendre à
l’évidence que la destruction d’un unique module omni-fonctionnel s’avère très peu
rentable lorsque celle-ci survient avant le début de l’exploration à cause d’une erreur de
conversion du système impérial vers le système métrique. D’autant plus qu’il sera sans
doute plus facile de faire coopérer plusieurs modules robotisés aux fonctionnalités
limitées que de faire adopter le système métrique à nos voisins du sud.
C’est dans un contexte de coopération entre systèmes asservis, que le laboratoire de
mécatronique de l’École Polytechnique de Montréal s’est doté d’une équipe de robots
joueurs de soccer. Les robots sont en mesure d’évoluer de façon autonome en fonction de
l’intelligence qui leur est conférée par la programmation d’un cerveau qui prend la forme,
non pas d’une masse visqueuse à composition neuronale, mais d’une instance d’une
classe C++ au sein d’une architecture logicielle orientée objet. Le but est de faire jouer
les robots au soccer. Le défi est de battre l’autre équipe. On peut donc affirmer qu’il
s’agit d’implanter une coopération entre robots dans un contexte d’adversité. Bien
qu’aucun desdits robots ne soit destiné à s’en prendre à une tumeur ou à faire un voyage
interplanétaire la situation modélisée s’y apparente d’où une partie de son intérêt.
D’une part, les robots sont habilités à se repérer par eux-mêmes en ayant recours à
l’odométrie rendue possible par des encodeurs de position sur les moteurs. D’autre part,
ils peuvent communiquer entre-eux ou avec un serveur de match par communication IP
2
sans-fil à l’aide de liens RF. Le seul problème est que ces robots rouleurs de quelques
cinquante centimètres de haut et de quarante centimètres de diamètre sont aveugles et
qu’ils ne peuvent ni voir le ballon ni se fier à l’odométrie pendant plus d’un certain temps
à cause de l’accumulation d’erreurs. Ces pour remédier à ce problème qu’un système de
vision artificielle globale a été développé pour transmettre aux robots l’information
visuelle nécessaire au bon déroulement d’une partie de soccer. Le présent ouvrage se
divise en quatre chapitres se veut donc un rapport de conception logicielle du système de
vision qui porte le nom de FVS.
Avant de se lancer dans la conception de quelque système que ce soit, il est important de
définir le problème afin d’y apporter une solution complète et adéquate. Conséquemment,
le premier chapitre détaille la problématique adressée par le système de vision. Il y est
question des enjeux majeurs en terme de performance et de traitement d’image. On y
discute aussi des données que le système de vision doit transmettre aux robots et au
serveur de match ainsi que des considérations matérielles du système.
Dans un deuxième temps, le second chapitre qu’est celui sur la méthodologie fait état de
la démarche scientifique qui a été menée à bien pour solutionner le problème en tenant
compte de tous les enjeux énoncés dans la problématique. On y discute donc des
différentes solutions envisagées ainsi que des choix qui ont été faits dans l’optique d’une
solution adéquate. Les résultats de certains tests et de certains calculs y sont présentés
pour appuyer les choix qui ont été faits.
Troisièmement, dans le chapitre qui présente les résultats, la solution telle que
développée au niveau logiciel est décrite en détail et on retrouve d’ailleurs en annexe une
explication de toutes les fonctions et de tous les attributs des classes qui ont été
programmées pour réaliser le système. Une brève discussion de l’utilisation du système
accompagne la description du module d’interface graphique et une présentation succincte
de ce qui doit être fait pour calibrer les caméras se retrouve dans la section de ce chapitre
3
qui traite justement de calibration. Des explications concernant les algorithmes de
traitements principaux viennent finalement clore ce chapitre.
En quatrième et dernier lieu, un chapitre est consacré à la discussion du système qui a été
développé. Dans la perspective ou on considère que ledit système pourra être modifié et
amélioré, l’auteur y propose certaines alternatives aux solutions adoptées ainsi que
quelques idées qui valent la peine d’être mentionnées.
1. La Problématique
La problématique est la phase du développement où une première évaluation des
requis est établie. Bien que cette étape soit en quelque sorte la fondation de l’édifice
qu’est une réalisation logicielle et matérielle de qualité, il est inévitable que certains
problèmes ne soient pris en considération qu’une fois qu’ils se présentent. Malgré tout,
grâce à un processus rigoureux et itératif par lequel les tests succèdent propositions et
idées valables et précèdent toute décision, on arrive à faire une liste plutôt exhaustive des
défis dans l’optique où on perçoit lesdits problèmes comme tels.
1.1 La détection
Avant d’envisager quelque traitement que ce soit, il faut détecter les éléments, robots ou
ballon, se trouvant sur le terrain et ce de façon aussi efficace et rapide que possible. Or, la
rapidité implique trop souvent un compromis au niveau de l’efficacité, voir de la véracité
des résultats. Deux problèmes majeurs peuvent donc survenir dans ce processus. D’une
part, la non-détection d’un élément qui se doit d’être détecté et d’autre part, la détection
erronée d’un élément qui ne devrait pas l’être.
Dans le premier cas, advenant qu’un robot ne soit pas détecté à une itération quelconque,
le problème n’est pas plus grave qu’il le faut du moment que le système réalise et signale
que ladite détection n’a pas pu être faite. Le robot n’a alors qu’à attendre à la prochaine
itération et à continuer de se fier à son odométrie en attendant. Cette situation peut
devenir problématique dès lors que le nombre d’itérations pour lesquelles les données ne
sont pas disponibles devient important. En prenant pour acquis qu’un système de vision
digne de ce nom se devrait de faire ce pourquoi il est conçu, on considère ce premier
critère comme étant la prémisse de base du système.
5
Dans le deuxième cas, le problème est un peu plus gênant car si une région est identifiée
comme étant un robot ou encore un ballon alors qu’elle ne l’est pas, il s’avère difficile
d’établir laquelle des régions détectées est belle et bien digne d’intérêt et laquelle ne l’est
pas. Il est alors toujours possible de vérifier quelques critères supplémentaires,
impliquant ainsi une certaine diminution de performance du traitement, mais à la limite,
une itération de détection peut être complètement faussée et conséquemment les données
peuvent être absentes pour tous les robots. Dans le même ordre d’idée que pour le
premier problème, la situation n’est pas dramatique dans la mesure où elle est signalée et
où elle ne se produit pas trop souvent.
Par contre, si on combine les deux cas ensemble, on obtient un mélange qu’on peut
qualifier d’explosif quitte à s’écarter légèrement du contexte de la discussion. En effet, si
un robot X n’est pas détecté et qu’à la même itération, une région Y non pertinente l’est
et que les données relatives à Y sont transmises à X, qu’arrive-t-il ? Il est toujours
possible d’implanter certains mécanismes de confirmation et de validation du côté du
robot pour se prémunir des données exceptionnellement faussées, mais si ça devait se
produire durant plusieurs itérations successives le problème pourrait perturber le bon
fonctionnement du système. Pire encore, si la situation se produit par rapport au ballon, le
problème vient perturber tous les éléments du système. La détection, quoique élémentaire
et primordiale, s’avère être un processus auquel il faut accorder beaucoup d’importance.
Il faut donc idéalement prévoir des mécanismes permettant de le rendre plus robuste, ce
qui m’amène à traiter du problème suivant.
1.2 L’identification des robots
Une fois les robots et le ballon détectés, il faut déterminer lequel est lequel de
façon exacte. En effet, parce que nous estimons avoir une formule gagnante et non par
manque de ressources, les robots sont, à toute fin pratique, identiques et ce même d’une
équipe à l’autre. Il s’agit donc de trouver un identificateur quelconque, mais viable qui
6
permette de discerner quels sont les joueurs d’une équipe et lesquels sont les joueurs de
l’équipe adverse. D’une part on veut envoyer l’information au bon robot et d’autre part, il
faut que ce dernier soit informé de ce qui concerne ses coéquipiers et ses d’adversaires
dans le contexte où il s’agit d’une coopération concurrentielle.
Une fois de plus, les problèmes pouvant survenir sont délicats et doivent êtres anticipés
afin de s’en prémunir. Le problème principal est l’identification erronée qui s’apparente
beaucoup à la combinaison d’une détection erronée et d’une non-détection simultanée
souligné à la section précédente. Les deux problèmes sont très semblables en ce sens que
les conséquences en sont pratiquement les mêmes mis à part le fait qu’une identification
erronée perturbe nécessairement deux robots simultanément puisque les données les
concernant sont alors interverties. Toutefois en solutionnant la question d’identification,
on minimise la probabilité d’occurrence de détections fautives. En effet, advenant qu’il y
ait trop de régions identifiées comme étant des robots, celle qui fait défaut n’a, en théorie,
pas d’identificateur. Il s’agit maintenant de déterminer ce que les robots doivent recevoir
comme données du système de vision.
1.3 Position et orientation des éléments
Il a été établi que le système de vision doit être en mesure de fournir la position et
l’orientation des robots ainsi que la position du ballon aux différents systèmes concernés,
à savoir les robots eux-mêmes et le serveur de match. Pour ce faire, il s’agit de trouver un
motif de détection permettant de déterminer quelle partie de la région détectée correspond
à l’avant du robot. Or, l’ajout d’un tel motif a une contrepartie qui a des répercussions au
niveau de la précision du centre de masse de la région. Il est toujours possible d’apporter
certains correctifs mathématiques au calcul de ce dernier, mais cela implique un certain
coût au niveau du traitement qu’il est préférable de minimiser dans l’optique d’un
traitement rapide des images.
7
Une solution optimale se doit donc de rendre la détection de l’avant du robot possible,
pour des fins de calcul d’orientation et ce, sans compromettre la précision au niveau de la
détermination de la position du robot. En effet, plus celle-ci est précise, plus il est
possible de permettre aux robots de passer près les uns des autres sans qu’il n’y ait de
collision. D’autre part, « botter » le ballon de façon précise implique une précision autant
au niveau de la position du ballon qu’au niveau de l’orientation et de la position du robot
qui effectue le botté. Il va sans dire que la localisation des obstacles que représentent les
autres éléments présents sur le terrain est cruciale.
1.4 Couvrir la totalité du terrain
Le terrain sur lequel les robots évoluent mesure 6 mètres par 3 mètres et le plafond du
local dans lequel il se trouve a une hauteur d’un peu plus de 2 mètres. Ces contraintes de
dimensions physiques constituent la première difficulté en ce qui concerne la réalisation
du système car elles ont des répercussions majeures sur les trois dimensions de la
problématique présentées précédemment.
Malgré l’utilisation de lentilles ayant un très grand angle d’ouverture, il s’avère
impossible de couvrir la totalité du terrain avec une seule caméra puisque le plafond nous
empêche de positionner celle-ci à la distance nécessaire pour le faire. D’ailleurs la
précision de l’analyse d’image étant directement proportionnelle à la taille des objets
considérés, il n’est pas souhaitable de couvrir trop de terrain dans une seule image.
D’autre part, plus l’angle d’ouverture est grand, plus la déformation radiale due au rayon
de courbure de la lentille est importante. Non seulement est-elle importante, mais elle
varie en fonction de la distance par rapport au centre de la lentille ce qui la rend difficile à
quantifier. Les mesures en périphérie du terrain sont conséquemment moins précises que
celles situées directement sous une caméra.
8
L’alternative ou, dépendamment de l’approche, le complément aux lentilles à grand angle
d’ouverture, est d’utiliser plus d’une caméra pour couvrir la totalité du terrain. Une fois
de plus, il s’agit d’un compromis à faire entre la précision et la rapidité de saisie et de
traitement des images. Il faut aussi considérer les implications budgétaires d’un recours à
de nombreuses caméras qui étant déjà dispendieuses nécessitent, pour chacune d’elle, une
lentille et une carte d’acquisition. Bien qu’une carte soit faite pour supporter plusieurs
caméras simultanément, les temps d’acquisitions deviennent alors suffisamment long
pour les considérer comme étant hors de propos dans un contexte de performance dans le
temps. Il faut donc avoir recours aux lentilles spéciales pour minimiser le nombre de
caméras nécessaires d’autant plus que le coût en performance, même avec une carte
d’acquisition par caméra est important.
En effet, le fait d’utiliser plus d’une caméra introduit la nécessité d’une zone de
recouvrement entre les images afin d’éviter de se retrouver avec des fractions d’un
élément pertinent dans plus d’une image. Le recouvrement fait en sorte que l’élément en
question sera présent en totalité dans plus d’une image à la fois et il faut alors fusionner
les résultats de l’analyse de chacune d’elle. Une alternative consiste à fusionner les
images elles-mêmes, mais à quel prix ? Rappelons-nous que c’est en périphérie des
images que la déformation est la plus importante alors il est très difficile de reconstituer
une seule grande image à partir de deux images distinctes sans introduire des
déformations de toute sorte.
Bref, l’énumération de tous ces problèmes potentiels témoigne de la nécessité d’avoir
recours à une méthode de développement rigoureuse. Chaque pas en direction de la
complétion du système se doit d’être analysé, vérifié et validé afin d’anticiper toutes les
conséquences possibles et de ne pas se lancer dans une mauvaise direction qui
impliquerait des modifications majeures. Malgré toutes ces précautions, il ne faut pas
perdre de vue que tout projet a sa part d’imprévus.
2. La Méthodologie
Cette section du document présente, dans un premier temps, une description des
dispositions matérielles qui ont été mises en place pour atteindre les objectifs fixés en
début de projet. La problématique étant plus ou moins bien définie à cette étape
préliminaire du développement, un des objectifs en question consiste à faire une
exploration systématique de ce qui est réalisable ou non avec les moyens dont nous
disposons. Dans un deuxième temps, il y est question de la méthode de développement
elle-même ou, en d’autres mots, des aspects qui relèvent de la planification structurelle
du développement du système de vision.
2.1 L’ébauche d’une solution
« Avant de plonger, il faut savoir nager» disent certain. « Avant de développer et d’aller
de l’avant il faut réfléchir, proposer et tester » dirait M. Hurteau, le directeur du projet. Le
développement du système de vision pour robots footballeurs a donc débuté par une
phase d’exploration des différentes solutions que nous étions en mesure d’implanter.
2.1.1 Couvrir tout le terrain à grâce à deux caméras
Dans un premier temps, il s’avérait essentiel de prévoir l’aménagement matériel
nécessaire pour couvrir le terrain. Sachant que le plus grand angle d’ouverture disponible
à l’aide d’une lentille se situe autour de 90° il s’avère essentiel d’avoir recours à deux
caméras pour couvrir la totalité du terrain qui mesure 6m x 3m. Ayant toutes les données
nécessaires pour effectuer une première estimation, il nous a alors été possible de décider
de l’aménagement à réaliser.
10
2.1.1.1- Les données :
• Résolution :
resx = 640 pixels resy = 480 pixels
• Angle d’ouverture : γ = 90o
• Dimensions du terrain : Long = 6m Larg = 3m
• Dimensions du robot : Environ : 0.4m X 0.4m
Figure 2. 1 Aménagement matériel
2.1.1.2- Les Hypothèses :
1) Deux caméras couvrent chacune la moitié du terrain en plus d’une zone de
recouvrement.
2) La zone de recouvrement doit être au moins aussi grande que le robot.
3) On laisse tomber 20 pixels en périphérie de l’image pour tenir compte des
imprécisions dues à la lentille.
2.1.1.3- Les Calculs :
Selon l’hypothèse 3
Resx = 640 – (2x20) = 600 pixels
Resy = 480 – (2x20) = 440 pixels
Figure 2. 2 Portion viable de l'image
600
440
res
res
γ/2
Comme l’image est plus large que haute, on suppose que l’angle d’ouverture de 90o
correspond à la largeur de l’image. En supposant (les corrections nécessaires) pour une
correspondance directement proportionnelle et uniforme dans toute l’image entre la taille
des pixels et la dimension réelle, on doit donc couvrir la largeur du terrain avec 440
pixels.
En accord av
longueur du te
Il s’agit alors
zone afin de
disposons.
Figure 2. 3 Ang
Ces résultats
caméras est po
45o
Précision linéaire = 3m x (1/ 440 pixels) ≈ 7mm/pixel11
ec l’hypothèse 2, on obtient une image qui couvre dans le sens de la
rrain :
de calculer la hauteur à laquelle la caméra doit être fixée pour couvrir cette
déterminer si cet aménagement est possible dans le local dont nous
le d'ouverture de la lentille
simples, mais fiables viennent confirmer que l’aménagement à deux
ssible et que c’est dans cette direction que nos travaux doivent s’orienter.
4m/2
Hauteur de la caméra = 2m
600 pixels x 7mm/pixel ≈ 4m
12
2.1.2 Une solution populaire mise de côté
Dans un premier temps nous avons envisagé la détection d’arêtes comme solution au
problème de détection des éléments. Les descriptions et les explications sur cette
technique abondent dans la littérature [1] ainsi que sur Internet. Or, comme les éléments
en question se trouvent la plupart du temps éparpillés sur tout le terrain et que ladite
méthode implique l’utilisation de filtre convolutionnels tel le filtre de Sobel, nous avons
jugé que le traitement serait très lourd pour chaque image et que cette caractéristique
allait à l’encontre des prérogatives implicites de performance du système.
En effet un filtre convolutionnel prend la forme d’une matrice 3x3 qu’on déplace sur tout
les pixels de l’image. Le pixel qui sur lequel se superpose le centre de la matrice est filtré
en prenant la valeur de la somme des produits de l’intensité des 8 pixels qui l’entourent et
des valeurs qui se trouvent aux cases correspondantes dans la matrice. Ainsi, soit M une
matrice de 3 lignes par 3 colonnes et (x,y) la position du pixel à filtrer, I(x,y) l’intensité
du pixel (x,y), la valeur filtrée I ’(x,y) d’intensité du pixel se calcule alors comme suit :
I ’(x,y) = Σ1i = -1Σ1
j = -1 M[i+1][j+1] * I(x+i, y+j) tel que i ≠ 0 et j ≠ 0
À raison de 8 multiplications et additions en nombres flottants par pixel pour un premier
filtrage d’une seule image de 640 x 480 pixels, nous avons jugé que le traitement
n’atteindrait pas nos aspirations en terme de performance et n’avons pas poussé les tests
dans ce sens plus loin que la simple réflexion. Sans doute existe-t-il de nombreuses
méthodes pour accélérer le processus, mais nous avons opté pour une autre solution et
laissé celle-ci pour contre.
13
2.1.3 La segmentation des couleurs : une solution simple et efficace
La méthode que nous avons jugée la plus efficace se veut aussi une des plus simple à
implanter. Brièvement, il s’agit de reconnaître certaines régions comme étant des zones
ou les pixels ont tous sensiblement la même couleur. Les algorithmes de détection [1] qui
se basent sur cette technique appliquent en général un seuillage sur les différentes
couleurs. Par exemple, en dans le système de couleur RGB les pixels pour lesquels R >
150/255,
G < 70/255 et B < 70/255 pourraient être considérés comme étant rouge. Il faut alors
appliquer ce même genre de critère à tous les pixels et pour toutes les couleurs qu’on
souhaite détecter. Évidemment, dès qu’un pixel a été identifié comme étant rouge, inutile
de vérifier à nouveau s’il est vert. Il est donc possible d’obtenir de très bonnes
performances même avec des régions de couleurs variées. Néanmoins, quoique la
correspondance ne soit pas linéaire, moins il y a de couleurs à traiter plus c’est efficace.
C’est dans cet ordre d’idée que vient s’insérer la solution qui, après moult tests, a été
adoptée dans le cadre du système FVS. Nous nous sommes donc mis à segmenter les
couleurs dans toutes les teintes ce qui a donné lieu à de nombreuses heures de bricolage à
l’aide de cartons de toute sorte. Telle ou telle couleur se détachait mieux qu’une autre,
mais les résultats n’étaient pas à la hauteur nos attentes. L’œil humain possède de 75 M à
150 M de bâtonnets, sensibles à l’intensité lumineuse environ 7 M de cônes, sensibles à
la couleur. L’appareil visuel en question est donc beaucoup plus sensible aux contrastes
d’intensité qu’aux contrastes de couleur et c’est exactement ce que nos tests sont venus
confirmer dans le cas de la vision machine par approche de segmentation des couleurs.
Conséquemment, pour des raisons de performance, la décision a été prise que les robots
tout comme le ballon allaient êtres de couleurs claires alors que le reste des éléments du
terrain à savoir ceux pour lesquels la détection n’est pas souhaitable allaient êtres aussi
foncés que possible. Le seuillage dans le système FVS ne se fait donc pas sur les
différentes valeurs de RGB, mais simplement sur l’intensité lumineuse des pixels. Ainsi
14
pour tout pixel i tel que (Ri + Gi + Bi)/3 > SEUIL, pixel = 1 autrement pixel = 0. Les
régions que nous détections sont alors des regroupements de 1 sur fond de 0. C’est ce
qu’on appelle la binarisation de l’image.
2.1.4 La détection des régions
La technique qui a été expliquée jusqu’ici ne fait qu’allumer les pixels pertinents et
éteindre ceux qui ne le sont pas sans toutefois, produire d’information sur les éléments
présents sur le terrain, ni même identifier les régions. C’est là où intervient un outil,
développée à l’Université Carnegie Mellon, qui prend la forme d’une classe programmée
en C++ et qui porte le nom de CMVision [2]. La détection des régions se fait donc en
passant l’image binarisée par segmentation des couleurs en argument à une instance de la
classe CMVision qui implémente les fonctionnalités de connexion des régions. Cette
étape permet donc de regrouper les pixels appartenant à une même région en une seule
entité aux propriétés distinctes. L’opération se fait en deux temps. D’abord, l’encodage
des runs consiste à regrouper les pixels de même couleur qui se trouvent liés les uns aux
autres sur une même ligne. L’image est donc parcourue ligne par ligne de gauche à droite
afin d’identifier les runs en question. La figure 2.4 illustre le processus d’identification.
Figure 2. 4 Encodage des séries de pixels
run1 run2
run3 run4
run5run6
15
Le parcours horizontal des pixels permet donc dans la figure ci-haute d’identifier 6 runs
qui sont alors placées dans un arbre de recherche. Il s’agit alors d’effectuer la deuxième
étape de l’identification des régions. Chacune de celle-ci possède un identificateur unique
et un pointeur vers son parent. Initialement chaque région est identifiée comme étant son
propre parent (Figure 2.5 a) ). La méthode consiste à effectuer une recherche unificatrice
avec compression de chemin. Les régions présentent dans l’arbre sont parcourues afin
d’ajuster le pointeur parental vers leur parent le plus éloigné (Figure 2.5 b)). Les lignes
adjacentes sont ainsi parcourues deux par deux. Lorsqu’une run A a une parente B qui
possède déjà elle-même une parente C, c’est vers C que le pointeur de A est redirigé
(Figure 2.5 c)). Finalement lorsqu’il y a recouvrement, les pointeurs sont redirigées de
manière à ce qu’une même région n’ait qu’un seul parent qui identifie désormais toutes
les runs qui composent la région en question (Figure 2.5 d)).
Figure 2. 5 Regroupent des séries de pixels
Une fois les régions identifiées, il est possible de calculer leurs propriétés respectives à
savoir le centroïde, l’aire totale et la boîte qui délimite la région (mieux connue sous le
nom de bounding box). Elles sont ensuite triées en ordre décroissant de taille afin que les
régions les plus importantes puissent être considérées en premier lieu. En effet, malgré la
qualité d’une image, on y retrouve toujours une certaine quantité de bruit ou de reflets
que le seuillage réalisé préalablement ne parvient pas à éliminer. Ces défauts peuvent être
identifiés comme des régions et il est alors possible de les éliminer à l’aide de leur taille
insignifiante ou par d’autres critères tels le rapport d’aspect que nous sommes en mesure
a) b)
c) d)
16
de calculer à l’aide de la boîte délimitante. Les robots étant cylindriques et le ballon
sphérique leur rapport d’aspect hauteur sur largeur se doit donc d’être avoisinant de 1.
2.1.5 Le calcul de l’orientation des robots
Le déroulement logique du processus d’analyse d’image veut qu’une fois qu’on connaît
la position d’une région et qu’elle a été identifiée comme étant un robot, on procède à
l’évaluation de son orientation dans le référentiel du terrain de soccer. Tel que mentionné
dans la problématique, nous avons, pour ce faire, recours à un motif de détection qui
permet de déterminer où se trouve l’avant du robot. Nous avons donc envisagé et testé
des solutions de tout genre que nous pouvons regrouper dans deux catégories soit : d’une
part, les solutions actives lumineuses et, d’autre part, les solutions passives. Les solutions
actives ont rapidement été mises de côté car elles impliquent une certaine consommation
d’énergie qui affecte l’autonomie des robots et ne procurait aucun avantage sur les
solutions passives. Nous avons donc évalué plusieurs motifs dont deux critères
importants sont ressortis. D’abord, l’influence du motif sur le calcul du centroïde de la
région doit être minimale et la précision offerte sur l’orientation doit être maximale.
2.1.5.1 La précision de l’orientation
Pour calculer et prévoir la précision de l’orientation telle qu’analysée par un éventuel
système de vision, il est d’abord important de rappeler que la disposition du système de
caméra telle que détaillée à la section 2.1.1 procure une précision de 7mm par pixel.
Même si le calcul du centroïde grâce à la classe CMVision retourne une position en
nombre flottant avec fraction de pixel on se doit de poser certaines hypothèses
simplificatrices et d’éviter d’être trop optimiste quant à cette précision. Donc en
supposant que :
1) Le robot tourne autour de son centroïde.
17
2) Le motif de repérage a au plus 0.4 m de long et il est centré.
3) Aucune optimisation de l’image et un déplacement détectable minimal de 1 pixel.
Erreur !
Figure 2. 6 Exemple de motif de détection
Dans le meilleur des cas, le motif est parfaitement aligné avec les pixels.
Figure 2. 7 Précision maximale
Dans le pire des cas, le motif est parfaitement aligné avec la diagonale pixels.
Figure 2. 8 Précision minimale
d
Précision angulaire maximale ≈ arctan(7mm / d)
d
7mm
Précision angulaire minimale ≈ arctan(√2 x 7mm / d)
d
√2 x 7mm
18
Nous sommes alors en mesure de tracer la relation entre la distance du motif de détection
par rapport au centre de la région et la précision angulaire (Figure 2.9). On constate alors
que plus le centre du motif de détection est éloigné du centre de la région, plus cette
précision est élevée. Le motif de détection d’orientation doit donc tirer profit de cette
propriété.
Figure 2. 9 Variation de la précision en fonction de d
2.1.5.1 L’influence du motif de détection sur la précision des autres mesures
Il est important que le motif choisi ne vienne par interférer avec le calcul du centre de la
région elle-même sans quoi on observe une perte de précision qui affecte les deux
paramètres inter reliés que sont la position de l’objet et son orientation. Bref, le choix du
motif doit se faire judicieusement. Nous avons donc eu recours à la boîte de vision de
Matlab pour faire des tests sur les différents motifs.
19
Figure 2. 10 Motifs utilisés pour les tests de précision
Les résultats ci-dessous correspondent à l’analyse des trois motifs hauts qui ont été extrait
d’une image que nous avons binarisée. Pour ce faire, nous avons déposé un disque blanc
sur un fond noir et avons réalisé trois saisie d’image. La première a été prise telle qu’elle
alors que dans un second et troisième temps nous lui avons ajouté un et trois cercles noirs
en guise de marqueurs pour détecter l’orientation. Par la suite, à l’aide des outils de
Matlab, nous avons déterminé le centre de la région par une méthode très similaire à celle
utilisée par CMVision. En voici les résultats :
Patron / Mesure Sans Motif Motif à un point Motif à trois points
Centroïde en x
[pixels]
68.0338 67.8784 68.1460
Centroïde en y
[pixels]
68.2166 68.3199 68.1849
Tableau 2. 1 Valeur du centroïde pour chaque motif
En supposant que la position exacte du centre est celle du centre du cercle ne comportant
aucun marqueur d’orientation, nous avons calculé l’erreur introduite par chaque motif.
Patron / Erreur Motif à un point Motif à trois points
Erreur en x [pixels] 0.1554 0.0317
Erreur en y [pixels] 0.1033 0.1122
Tableau 2. 2 Erreur sur la position du centroïde pour chaque motif
20
On constate que l’erreur est moindre si le motif de détection est bien réparti autour du
centre de la région de manière à influencer celui-ci de façon très semblable dans toutes
les directions. Nous nous sommes dès lors tourné vers le motif à trois marqueurs pour
traiter l’orientation du robot.
2.1.6 L’identification des robots en tant que joueurs d’une équipe
Maintenant que nous savons comment nous y prendre pour détecter les robots ainsi que
pour déterminer leurs positions et orientations respectives, il reste à savoir de quel robot
il s’agit. Tel que discuté dans la problématique, le fait d’attribuer de l’information au
mauvais robot a pour conséquence de perturber le bon fonctionnement de tout le système.
Toutes les observations exposées jusqu’ici tiennent toujours en ce sens que la méthode
choisie doit être non invasive afin de ne pas perturber le calcul des autres paramètres.
Nous avons donc envisagé plusieurs solutions, mais celle que nous avons retenue se base
sur un identificateur de couleur se trouvant au centre du robot. Ainsi, les composantes
rouges et bleues du système RGB sont utilisées afin d’identifier l’équipe, alors que la
composante verte permet d’identifier le numéro du joueur. Conséquemment, les trois
robots de l’équipe des rouges ont un identificateur pour lequel les proportions de rouge et
de bleu sont respectivement de 255/255 et de 0/255 alors que ceux de l’équipe des bleus
ont une proportion de bleu égale à 255/255 et de rouge égale à 0/255. L’identification par
le vert se fait comme suit : les robots numéros 1, 2 et 3 ont respectivement un
identificateur pour lequel la proportion de vert est de 0/255, 127/255 et 255/255. Le fait
que l’identificateur soit positionné au centre du robot respecte l’hypothèse qui veut que
l’influence sur la position soit pratiquement la même dans toutes les directions.
21
Figure 2. 11 Identificateurs de couleurs des robots
2.2 Le prototypage
Bien que la démarche n’ait pas été identifiée comme étant du prototypage dès le départ, la
définition plus ou moins exacte du problème a donné lieu au développement d’un premier
système de vision qui fut baptisé pour rire Falcon Vision System. Le nom est resté et la
version actuelle du logiciel s’appelle FVS. Bref, il n’avait pas été planifié qu’une bonne
partie du développement serait consacrée à l’implantation d’un logiciel qui serait
abandonné en cours de route. En effet, comme le problème et les solutions à y apporter se
sont définis à mesure que le développement avançait, le premier système finit par
atteindre ses limites fonctionnelles et on passa dès lors plus de temps à le déverminer
qu’à le développer. Ledit système s’averra tout de même très fonctionnel du moment
qu’on ne tentait pas de traiter l’image provenant des deux caméras en même temps.
D’autre part, même à une seule caméra, l’absence de design fît en sorte que ses
performances n’étaient pas à comparer avec celle du FVS autant au niveau des temps de
calcul qu’au niveau de la disponibilité des résultats à chaque itération. On put tout de
même s’en servir pour une démonstration au colloque de lancement de la librairie
publique MICROB qui eu lieu à l’IREQ ainsi que pour la journée porte ouverte à l’École
Polytechnique.
Tel que souligné, la problématique se clarifia peu à peu en cours de route. Évidemment
tous les aspects critiques et complexes du traitement comme l’orientation et
22
l’identification, avaient été bien réfléchis, testés et discutés dès le départ, mais peu de
considération a été accordée aux petits détails qui dans un projet de cette envergure
deviennent vite nombreux. Par exemple, il ne s’écoula pas beaucoup de temps avant que
nous ayons à nous rendre à l’évidence qu’une interface graphique permettant de faire les
réglages était nécessaire. Tout faire à la ligne de commande, quand on pense au nombre
de paramètres ajustables, devenait complètement absurde.
D’autre part, à partir de ce moment, l’implantation n’avait d’autre choix que d’être multi-
threads. Les problèmes de corruption des données inter-processus, firent leur apparition
dès le moment ou on tenta de réduire le nombre de passages d’arguments par valeurs
entre les processus légers, pour privilégier le passage des arguments par références afin
de réduire les appels aux constructeurs copie des différents objets et ainsi accroître les
performances. Somme toute, quoique le premier logiciel ait été pratiquement fonctionnel
et qu’il aurait sans doute été possible de le terminer, son entretien était à toute fin
pratique infaisable. Le fait d’apporter une modification à un endroit impliquait chaque
fois de revoir tout le code et il arrivait régulièrement que son fonctionnement devienne
complètement aléatoire. La solution devint donc évidente : on devait ranger le « Falcon
Vision System » dans le rayon des prototypes et tout recommencer depuis le début.
Une façon pessimiste de percevoir le premier système est de le considérer comme un
échec. D’un point de vue plus optimiste, nous devons nous rendre à l’évidence que cette
première ébauche nous a permis de clarifier la problématique dans ses détails les moins
évidents et de ne pas répéter les même erreurs lorsque est venu le temps de concevoir et
de développer la version FVS. Le prototypage est une pratique courante en génie logiciel
pour clarifier les requis et on put constater le bien fondé de cette approche.
23
Figure 2. 12 Interface du prototype
2.3 L’importance du design
Le prototypage fait partie intégrante de l’étape de conception de logiciel qu’est le design.
D’ailleurs, tels que souligné à la section précédente notre prototype n’est en fait rien
d’autre que le fruit d’une absence de design. Ce n’est qu’en passant par cette étape
cruciale qu’on peut atteindre un certain standard de qualité dans le développement du
produit logiciel. L’entrepreneur qui construit des maisons a beau être très expérimenté,
s’il travaille sans plans, il est certain que la construction ne se fera pas sans embûches
d’autant plus que le produit fini présentera de nombreuses irrégularités. Il en va de même
pour l’ingénieur informatique qui ne prévoit rien d’avance.
Dans le cadre de la version finale du système, l’architecture a été beaucoup mieux pensée
et même avec tous les efforts qui ont étés investis dans cette étape préliminaire, il serait
24
sans doute possible de l’améliorer. Néanmoins, j’estime que la réalisation est de bonne
qualité et je dirais même excellente si on considère que la version FVS a été entièrement
conçue et développée en moins de quatre mois. Il en résulte un système modulaire et sans
duplication des données avec une structure permettant d’apporter des modifications ou
des améliorations à un seul endroit sans perturber le reste du fonctionnement de
l’application.
Le module de saisie d’image a donc été totalement découplé de la partie traitement
d’image. La raison est simple : le matériel, les pilotes ou la version du système
d’exploitation pourront éventuellement être appelés à changer. Ainsi, s’il devait y avoir
une incompatibilité quelconque, seul le module de capture d’image devra être modifié et
encore mieux, il s’agira probablement même de ne modifier ou de ne remplacer que le
pilote, en l’occurrence V4L, de la carte de saisie d’images. Dans un même ordre d’idée,
l’interface graphique a été complètement dissociée de l’application et il est possible de la
remplacer ou de la modifier en n’adaptant que le médiateur dédié.
Parallèlement, le développeur qui n’a pas participé à la conception ou au développement
du FVS pourra se contenter de ne travailler que sur le module qui l’intéresse, sans devoir
nécessairement posséder une vue d’ensemble du système pour y apporter sa contribution.
Par exemple, le développeur qui serait insatisfait des performances du calcul
d’orientation peut aller dans le module de traitement d’image et ne modifier que la
fonction dédiée à cet effet du moment que celle-ci continue à retourner une valeur
compatible. La modularité rend aussi le système complètement extensible en ce sens,
qu’on peut ajouter autant de modules que souhaité et qu’il sera dès lors possible de faire
appel aux fonctionnalités ajoutées à partir du cœur du système comme si elles avaient
toujours fait partie de ce dernier. La balle est donc dans le camp des enthousiastes, des
perfectionnistes et des insatisfaits. Le code est ouvert, le document présent explique
clairement la structure du système et celui-ci est modifiable en moins de deux et pourra
toujours je l’espère être amélioré.
3. Les Résultats
3.1 L’architecture du système
Le flux des données de la saisie de l’image, en passant par son traitement permettant la
détection des éléments d’intérêts jusqu’à la fusion de l’information provenant des deux
caméras nécessaires pour couvrir l’ensemble du terrain, se prête on ne peut mieux à une
structure hiérarchique [3]. Parallèlement, la modularité se veut une qualité essentielle
étant donné que certaines parties du système pourront être amenées à changer
indépendamment du reste. C’est donc en ayant ces caractéristiques comme objectifs que
le système a été conçu. La meilleure façon de décrire conceptuellement l’implémentation
du système est de dire qu’il s’agit d’une arborescence dans laquelle le contrôle part de la
racine de l’arbre vers les feuilles alors que les données remontent des feuilles vers la
racine.
Dans la Figure 3.1 présenté à la page suivante, l’interface graphique MyGui qui est
implanté dans la classe FVS_Interface communique avec l’engin de fusion MyFusion à
travers un objet de type Médiateur qui est un patron de conception permettant de
découpler l’application de sa représentation graphique [4]. Qu’il y ait fusion des images
provenant de deux caméras ou qu’il n’y ait qu’une seule image provenant de l’une ou
l’autre des caméras, le contrôle passe par l’engin de fusion. Celui-ci possède donc un
engin de capture par caméra ainsi qu’un objet d’analyse d’image par caméra. Ces derniers
sont représentés ici-bas par les objets CaptureCam1, CaptureCam2, AnalystCam1 et
AnalystCam2. À leurs tours, les engins de capture possèdent un objet de type
FVS_Camera, dont la calibration est implantée dans l’objet FVS_Calib qui le compose, et
d’un objet FrameGrabber de type V4L qui n’est nul autre qu’une interface vers le pilote
pour communiquer avec la carte de saisie d’image à laquelle est reliée une caméra.
Chaque objet d’analyse d’image est composé d’un objet de type FVS_Image pour
accueillir le résultat de chaque capture d’image pour fins de traitement.
26
Prenons l’analyse d’une simple capture de la caméra1 pour détailler une séquence typique
d’utilisation. Lorsque l’usager appuie sur le bouton Capture de l’interface, celle-ci
transmet le message à l’engin de fusion à travers le médiateur. L’engin de fusion
ordonne donc à l’engin de capture CaptureCam1 d’effectuer une saisie d’image dont le
résultat sera stocké dans l’objet FVS_Image de l’objet d’analyse attitré, soit
AnalystCam1. Ce dernier effectue les traitements nécessaires, à savoir l’identification, le
calcul de position et le calcul d’orientation pour tous les robots présents dans l’image et
les résultats sont stockés dans les structures de données (liste de FVS_Robots etc..)
appropriées appartenant à ce même objet. Les résultats sont alors retournés à l’objet
MyFusion qui effectue les conversions nécessaires pour calibrer les résultats en fonction
de la déformation de la lentille de la caméra 1. Toutes les facilités nécessaires pour ce
faire sont disponibles à travers l’objet FVS_Calib de la caméra 1. Il ne reste plus à l’objet
MyFusion à envoyer les données sur le réseau et à signaler à l’interface à travers le
médiateur qu’elle doit rafraîchir son affichage.
Figure 3. 1 Architecture du système
27
3.1.1 Le module de fusion de l’information
La seule fonctionnalité distincte qui est implémentée dans la classe FVS_FusionEngine
est la fusion de deux images avec tout ce qu’elle implique. Par contre, qu’il s’agisse
d’une saisie à une caméra ou à deux caméras, que la saisie se fasse en continue ou une
image à la fois, tout le contrôle est issu de cette classe et c’est dans celle-ci
qu’aboutissent toutes les données et résultats du traitement. Bien que la communication
ne se fasse qu’à travers un médiateur, l’interface voit toute l’application comme étant un
seul objet de type FVS_FusionEngine. En plus des structures de données nécessaires pour
recueillir les informations concernant les robots et le ballon, la classe FVS_FusionEngine
est composée de deux objets FVS_CaptureEnfine et de deux objets FVS_ImAnalyst à
travers desquels elle effectue respectivement, pour chaque caméra, la saisie et le
traitement des images.
Figure 3. 2 Diagramme de classes du module de fusion des images
FVS_FusionEngine
FVS_ImAnalyst : public CMVision
FVS_CaptureEngine
1..2 1..2
28
3.1.2 Le module de capture d’image
Ce module contient tous les objets dont les fonctionnalités ou les attributs concernent la
saisie d’images. Une saisie est donc propre à une caméra pour laquelle une calibration est
nécessaire. La saisie est rendue possible au niveau matériel par une carte d’acquisition
(Frame Grabber) SENSORAY PC104+ Model 311(Rev.D). La communication avec une
de ces cartes se fait par l’entremise d’un pilote implémenté dans un objet V4L pour «
Video For Linux ».
Figure 3. 3 Diagramme de classes du module de capture d'images
3.1.2.1 La classe FVS_CaptureEngine
Cette classe n’est en fait qu’une façade au paquetage de saisie d’image car elle n’ajoute
aucune fonctionnalité autre que la commodité d’utilisation. En fait, il s’agit plutôt d’une
pseudo-façade car c’est cette classe qui implémente la sauvegarde des images sous
différents formats, mais si on considère qu’il s’agit d’une fonctionnalité utile à l’utilitaire
de calibration ou pour des fins de déverminage, laissons tomber le qualificatif de pseudo.
Son utilité est la création, l’initialisation et la manipulation des composantes du
FVS_CaptureEngine
FVS_Camera
FVS_Calib
V4L
29
paquetage de saisie. On instancie donc un objet FVS_CaptureEngine par carte
d’acquisition ou par caméra.
3.1.2.2 La classe FVS_Camera
Cette classe définit tous les paramètres relatifs à la caméra qui est adressée par l’engin de
capture. En effet, une caméra est caractérisée par une position bien à elle par rapport à
l’origine du terrain. D’autre part, la déformation de l’image provenant d’une caméra est
fonction de son orientation spatiale et de sa lentille. La calibration est donc propre à une
caméra doit être refaite si la position ou l’orientation de la caméra est le moindrement
perturbée.
3.1.2.3 La classe FVS_Calib
Cette classe contient toutes les données, chargées à partir d’un fichier, et les fonctions
utiles pour apporter les transformations nécessaires aux coordonnées afin de compenser
le désalignement de la caméra par rapport aux trois axes ainsi que pour réduire les effets
indésirables de la distorsion radiale due à la lentille. Le fichier est obtenu grâce à un
utilitaire de calibration auquel on fournit une image .raw d’un gabarit de calibration non-
coplanaire prise à partir de la caméra concernée. L’implantation de cette classe ainsi que
l’utilitaire que nous utilisons nous ont été gracieusement fournis par M. Hong Hai
Nguyen du Perception and Robotics Laboratory[5] de l’École Polytechnique de
Montréal. La classe FVS_Calib est donc une version très réduite de la classe de
calibration de l’utilitaire de M. Nguyen.
3.1.2.4 La classe V4L++
La classe V4L++ fait partie de la librairie SPU-Toolbox [6]. Tel que mentionné, elle
permet un accès facile aux fonctionnalités du pilote d’utilisation de la carte d’acquisition
d’image. Le pilote utilisé par cette classe s’appelle « Video for Linux » [7]. Un objet V4L
30
sera donc instancié pour chaque caméra avec un identificateur de fichier qui correspond à
la pièce d’équipement appropriée. L’identificateur de la première caméra correspond à
« /dev/video0 » alors que celui de la seconde correspond à « /dev/video1 ». Pour plus
d’information sur V4L++ ou sur Video for Linux consulter :
3.1.3 Le module d’analyse d’image
Une fois la saisie d’image complétée par le module de capture, le résultat est transmis au
module d’analyse. Dans un premier temps, c’est au sein de ce module que se font tous les
traitements sur l’image tels la segmentation des couleurs et l’identification des régions.
En second lieu, c’est dans ce même module que se font les traitements plus spécifiques
tels le calcul de l’orientation des robots ou encore leur identification en tant que joueur et
membre d’une équipe.
3.1.3.1 La classe FVS_ImAnalyst
La classe FVS_ImAnalyst est le point d’entré du module. Toute l’information et les
procédures applicables aux données ou à l’image passent par une instance de cette classe.
C’est donc dans celle-ci que sont implémentées toutes les fonctions de traitements
spécifiques tels qu’énoncés ci-haut et c’est dans ses structures de données qu’est stockée
toute l’information concernant les éléments détectés au cours du traitement d’une image.
3.1.3.2 La classe FVS_Image
Chaque objet d’analyse d’image contient sa propre instance de la classe FVS_Image.
C’est dans ses attributs qu’est contenue la représentation d’une image sous toutes ses
formes. Image couleur, image binarisée, image avec entête ou simple vecteur de pixels,
tout y est. Conséquemment, c’est dans la classe FVS_Image que se trouvent toutes les
méthodes de traitement général de l’image à savoir la binarisation, le calcul des données
relatives à l’histogramme d’intensité et la récupération de la couleur d’un pixel à partir de
31
ses coordonnées. Pour les deux types d’image, couleur et binarisée, la classe contient un
attribut Frame et un attribut Image, par exemple l’image couleur est représentée à la fois
par l’attribut ColorImage et par l’attribut ColorFrame. La différence est que l’image
contient une entête qui précède le Frame.
Figure 3. 4 Disposition de l'image en mémoire
Cette représentation simple et efficace permet de charger les images .pnm directement
dans l’interface plutôt que des les y dessiner pixel par pixel.
3.1.3.3 La classe FVS_Element
Toute région détectée dans une image est d’abord considérée comme étant une instance
de FVS_Element. Cette classe possède toutes les facilités de calculs de paramètres
d’intérêts à partir des données relatives à toute région à savoir, l’aire, le centroïde et la
boîte de délimitation. Ainsi on peut, grâce à cette classe, obtenir rapidement l’information
concernant le diamètre ou le rapport d’aspect d’une région. Lorsque les caractéristiques
d’un élément concordent avec celles d’un robot par exemple, l’élément est alors identifié
de façon plus précise comme étant un FVS_Robot. D’ailleurs les classes FVS_Robot et
FVS_Ball héritent de la classe FVS_Element et disposent ainsi de tous ses attributs et de
toutes ses méthodes.
Entête .pnm
Frame de im_width * im_heigth *bytes_per_pix octets
ColorImage* ColorFrame*
32
3.1.3.4 La classe FVS_Robot
Tel que mentionné, la classe FVS_Robot hérite de FVS_Element. Celle-ci possède tout
de même des attributs et des méthodes supplémentaires afin de rendre l’identification
possible et de permettre le stockage du résultat du calcul de l’orientation qui est propre au
robot. L’attribut green_amount qui contient l’intensité de la composante verte de
l’identificateur du robot permet en plus de procéder à une réidentification des robots suite
à la fusion de l’information provenant de deux caméras.
3.1.3.5 La classe FVS_Ball
Cette classe hérite publiquement de FVS_Element et n’a aucune donnée ni fonctionnalité
supplémentaire jusqu’ici. Elle a tout de même été implanté de manière à ce qu’on puisse
rapidement ajouter des critères supplémentaires pour la détection du ballon tel la couleur
de celui-ci par exemple.
3.1.3.6 La classe FVS_Field
La classe FVS_Field n’a pas de fonctionnalité spéciale ou de méthode effectuant un
traitement quelconque. Sa seule utilité est de contenir et de rendre facilement accessible
l’information concernant le terrain de soccer. C’est donc dans un objet de ce type qu’est
stockée l’information concernant les dimensions du terrain, le nombre de robots de
chaque équipe et la position du centre du terrain dans une image. On aurait très bien pu
s’en passer en programmant ses paramètres de façon statique dans le code, mais son
utilisation procure flexibilité et commodité d’où le choix de son implantation.
33
3.1.4 Le module interface graphique
L’interface est composée de widgets (« window gadgets ») et de sous-fenêtre aux
fonctionnalités bien définies qui peuvent exister de façon indépendante de l’interface
mère ou être utilisées dans une autre interface. C’est par cette modularité que
l’interactivité de certains éléments de l’interface avec l’usager est rendue possible. Les
sous-fenêtres en question se comptent au nombre de quatre et sont représentés dans la
figure ci-dessous en relation de composition avec l’interface générale.
Figure 3. 5 Diagramme de classes du module interface graphique
3.1.4.1 La classe FVS_Interface
La classe FVS_Interface est fait une agrégation de plusieurs fenêtres avec lesquelles
l’usager peut intéragir. L’approche qui a été adopté en ce qui concerne la performance du
sytème consiste à faire tout ce qui il y a faire à chaque itération le plus vite possible. En
d’autres mots il s’agit d’une approche « meilleur effort ». Conséquement, moins il y a
d’opérations à effectuer plus les itérations d’analyse se font rapidement. L’interface a
donc été implantée de manière à ce qu’on puisse désactiver toutes les fonctionnalités
34
gourmandes en temps cpu afin de raccourcir le délai entre la disponibilité de nouvelles
informations concernant la situation sur le terrain. Après tout, bien qu’il soit utile de
monitorer la vision pour effectuer des réglages, pour faire des démonstrations ou pour
s’assurer que tout fonctionne bien, une fois que tout est en marche seuls les robots et le
serveur de match ont besoin d’utiliser le système et nous, humains, pouvons dès lors
avoir recours à notre système visuel personnel.
Figure 3. 6 Activation et désactivation de l'affichage
3.1.4.2 La classe Hist_Widget
On peut voir la classe Hist_Widget en action dans la partie gauche de la figure 3.6. Cette
dernière permet d’afficher l’histogramme du nombre de pixels en fonction de l’intensité.
L’histogramme typique a donc l’allure de deux bosses de chameau asymétriques où celle
de gauche, généralement très élévée, représente tous les pixels pour lesquels l’intensité
est très faible. Elle correspond en fait à tout ce qu’il y a de noir dans l’image. La bosse de
droite illustre les pixels blancs qui sont caractérisés par une intensité élevée. La fenêtre
Hist_Widget nous permet ainsi de bien ajuster la limite par rapport à laquelle la
segmentation des couleur, ou de l’intensité dans notre cas, est effectuée. L’usager n’a
qu’à ajuster le bouton glissoir de manière à ce qu’il se trouve assez près de la bosse de
gauche. C’est donc un outil très utile, mais qui implique de nombreux calculs ainsi qu’un
35
affichage lourd à l’écran et qui affecte sérieusement la performance. Il devrait donc être
utilisé pour fins de réglage puis désactivé.
3.1.4.3 La classe ContextWidget
La classe ContextWidget, comme son nom l’indique rend possible un affichage
contextuel. En effet, le système peut être utilisé selon deux modes différents. Le mode
capture implique que l’usager appuie sur le bouton capture chaque fois qu’il désire
effectuer une nouvelle itération de traitement. Il peut aussi choisir de sauvegarder l’image
saisie que ce soit pour la calibration ou pour en tapisser les murs du laboratoire. La
fenêtre ContextWidget lui montre alors les boutons qui permettent de faire ces
opérations. Le deuxième mode est celui de la capture en continu. Le contexte est alors
différent et l’usager ne peut que démarrer ou arrêter la capture et ce sont, dans ce mode,
les opérations que la fenêtre ContextWidget lui propose.
Figure 3. 7 Le changement de contexte
3.1.4.4 La classe SettingsWidget
De nombreux paramètre peuvent varier en ce qui concerne les conditions d’opération du
système. Pensons seulement au nombre de robots présents sur le terrain. La classe
SettingsWidget permet d’ajuster tous ces paramètres à l’aide d’une interface conviviale.
L’usager peut ainsi sauvegarder ses ajustements afin que l’application soit déjà ajustée à
sa prochaine utilisation ou encore les sauvegarder sous un autre nom afin de les charger
ultérieurement.
36
Figure 3. 8 Utilitaire de configuration du système
3.1.4.4 La classe MainScreen
La classe MainScreen n’est nulle autre que l’écran principal dans lequel s’affiche l’image
saisie par la caméra qui est monitorée. Bien qu’elle ne possède aucun bouton, elle est tout
de même interactive car c’est elle qui rend possible la sélection d’un rectagle d’intérêt
dans l’image. Lorsque l’usager défini un rectagle en déplaçant sa souris au dessus de
l’objet MainScreen avec le bouton gauche de sa souris enfoncé, un message est envoyé à
l’application lorsque bouton est relâché afin que tout ce qui se trouve à l’extérieur du
rectangle ne soit pas analysé. Le fait d’appuyer sur le bouton droit de la souris au-dessus
de l’écran a pour effet de désactiver la fonctionnalité de rectangle de délimitation. Au
même titre que l’histogramme, l’affichage de l’image à l’écran est une procédure très
gourmande en temps CPU et il vaut mieux la désactiver en contexte de performance.
37
3.1.4.5 La classe Mediator_GuiApp
La classe Mediator_GuiApp, n’a pour unique fonction que de faire le pont entre
l’interface et l’application de manière à ce que celles-ci soient découplées au maximum
en accord avec les principes des architectures MVC (Modèle Vue Contrôle) qui prévalent
dans la conception de logiciels avec interface graphique. Une instance de l’objet
Mediator_GuiApp possède donc un pointeur vers l’interface et un pointeur vers l’engin
de fusion tout comme ceux-ci possèdent un pointeur vers ledit médiateur. L’interface
peut donc être programmé de façon complètement différent et la seule chose qu’on a à
adapter en conséquence est le médiateur.
Figure 3. 9 Diagramme de concepts d'un objet médiateur
Interface Médiateur Application
38
3.2 La calibration
Tel que mentionné précédemment, l’image saisie par les caméras est imparfaite, c’est à
dire déformée. Les positions et orientations déduites à partir de telles images sont donc
inexactes de par l’inexactitude de la reproduction de la scène dans le cliché. Ces
déformations sont dues d’une part, à la distorsion radiale induite par les lentilles à grande
ouverture et d’autre part, par le fait qu’il est impossible d’aligner parfaitement le plan
image ou la cellule photosensible de la caméra, avec le plan de scène. C’est grâce à la
calibration qu’on arrive à corriger autant que possible ladite déformation.
Afin de trouver réponse à nos questions, nous nous sommes tourné vers un spécialiste de
la vision, M. Hong Hai Nguyen du Laboratoire en perception et en robotique de l’École
Polytechnique, qui nous a gracieusement fait profiter de son expertise en matière de
calibration. En plus de prendre le temps de nous expliquer son fonctionnement, M.
Nguyen nous a fourni l’utilitaire de calibration ainsi que son code source en C++.
D’ailleurs, à quelques fonctions près, la classe FVS_Calib utilisée dans le système FVS
est une version réduite d’une des classes qu’on retrouve dans le l’utilitaire en question.
La calibration pouvant probablement faire l’objet d’un projet de fin d’étude à elle seule,
je serai très bref en ce qui la concerne et me contenterai d’expliquer notre façon de
procéder. La méthode utilisée fait appel à la calibration de caméras de Tsai, du nom de
l’auteur de cette technique M. Roger Y. Tsai. J’invite donc le lecteur intéressé à des
explications mathématiques plus approfondies à consulter le lien proposé en annexe pour
un article produit au Massachusets Institute of Technology sur le sujet [8].
3.2.1 Le patron de calibration L’utilitaire de calibration a été programmé sous Windows alors que le système de vision
est implémenté sous Linux. Une migration rapide a été tentée, mais s’est avérée plus
39
compliquée que prévue et a été remise à plus tard question de priorités. L’utilitaire prend
une image du patron de calibration en entrée et produit en sortie un fichier contenant les
constantes nécessaires à la résolution des équations permettant d’obtenir les coordonnées
réelles corrigées.
Le patron de calibration consiste en une série de marqueurs de taille fixe se trouvant à
distance égale les uns des autres. Il est à noter qu’une calibration issue d’un patron où
tous les points sont sur un même plan donne lieu l’inversion d’une matrice dont le
déterminant vaut zéro. En d’autres mots, il est nécessaire que le patron en question
comporte des marqueurs sur deux plans distincts. Notre patron prend donc la forme d’un
plastique blanc de 2.5m par 2.5m sur lequel on retrouve des marqueurs circulaires à tous
les 30 cm. Certains marqueurs, formant le deuxième plan se trouvent sur de petits
poteaux de 30 cm de haut. Évidemment le 2.5 m n’a aucune importance et tous les autres
paramètres, tels la hauteur du deuxième plan ou encore la distance entre les marqueurs,
sont ajustables et sont définis dans le logiciel de calibration. On peut voir l’allure du
patron dans la partie gauche de la figure 3.10 ci-dessous qui est une saisie d’écran de
l’interface du programme de calibration.
Figure 3. 10 L'utilitaire de calibration
40
3.2.2 L’utilisation du logiciel de calibration win_cali
L’image que prend le programme en entrée, est prise à partie du système FVS en format
raw qui est tout simplement un format d’image sans entête. L’usager procède donc à la
saisie et à la sauvegarde de l’image en mode capture (voir section 3.1.4.3). Cette image
est ensuite transmise à la station Windows sur lequel le programme de calibration est
exécuté. Pour utiliser le programme de calibration, l’image doit porter le nom
ImageN.raw où N est un numéro. Voici les étapes à suivre pour utiliser le programme à
bon escient :
1) Une fois l’application win_cali.exe démarré, l’usager sélectionne l’image en appuyant
sur la touche « n » alors que le curseur de la souris est au-dessus de la portion gauche de
l’interface. Plusieurs images peuvent être présentes dans le répertoire de travail et
l’usager devra appuyer sur « n » jusqu’à ce qu’il voit son image apparaître.
2) Dans le quadrillé vert se trouvant dans la moitié droite de l’interface, l’usager doit
cliquer sur les intersections du quadrillé qui correspondent aux marqueurs dans l’image
de gauche. Le bouton gauche de la souris doit être utilisé pour les marqueurs du plan
inférieur du patron alors que le bouton droit sert pour les marqueurs du plan supérieur.
3) Dans le même ordre, l’usager doit cliquer, toujours à l’aide du bouton gauche de la
souris, sur les marqueurs mais cette fois-ci dans l’image.
4) Une fois ces trois étapes complétées, l’usager appuie sur esc et un fichier de
paramètres du nom de cam_para.txt est généré par un appel système au programme
ncal_fo.exe. Les paramètres importants du fichier sont la distance focale, la distorsion
radiale, la translation et la rotation de la caméra. Il est à noter que l’origine des résultats
obtenus coïncide alors avec le marqueur inférieur gauche du patron de calibration.
41
5) Il s’agit maintenant de transférer le fichier produit dans le répertoire capture du
système FVS, et de le nommer cam_para1.txt s’il s’agit de la calibration de la caméra #1
ou de le nommer cam_para2.txt s’il s’agit de la calibration de la caméra #2. Il est à noter
qu’on retrouve dans ce fichier les paramètres un à la suite de l’autre dans une seule
colonne à la fin du fichier ainsi que de façon explicite au début du fichier. Seule
l’information en colonne est pertinente pour le système FVS et toutes les données
explicitées qui précèdent ladite colonne doivent être supprimées à l’aide d’un éditeur de
texte. Ci-bas se trouve un exemple de fichier et seule la partie en gras doit être conservée.
//Fichier cam_para.txt f = 5.197026 [mm] kappa1 = 1.392319e-002 [1/mm^2] Tx = -450.063826, Ty = 869.501682, Tz = 2250.442070 [mm] Rx = 179.830554, Ry = 0.763895, Rz = 0.267015 [deg] ... … 7.6800000000e+002 6.4000000000e+002 8.4000000000e-003 9.8000000000e-003 1.0080000000e-002 9.8000000000e-003 3.2894296677e+002 2.4464278856e+002 1.0277994199e+000 5.1970261952e+000 1.3923188610e-002 -4.5006382580e+002 8.6950168223e+002 2.2504420700e+003 3.1386352648e+000 1.3332476651e-002 4.6602960770e-003 0.0000000000e+000 0.0000000000e+000
Pour clore le sujet, soulignons que la calibration fait du bon travail, mais qu’elle a ses
limites et que celles-ci son très faciles à atteindre surtout avec les lentilles utilisées au
laboratoire de mécatronique. Il est donc impératif d’ajuster et de positionner les caméras
le mieux possibles.
42
3.3 Les algorithmes et traitements importants
3.3.1 Le calcul de l’orientation des robots
Tel que mentionné à la section 2.1.5 au sujet de la précision de l’orientation, le choix du
motif de détection d’orientation se doit de perturber le moins possible le calcul du
centroïde de la région (du robot) qui le contient, faute de quoi résulte une position et une
orientation faussée. Nous avons donc opté pour un motif de détection à trois repères
disposés à distance égale du centre. Les segments de droites qui relient le centre du robot
aux deux points situés à l’arrière de celui-ci forment entres-eux un angle de 90° tels
qu’illustré dans la figure ci-dessous.
Figure 3. 11 Le motif de détection de l'orientation
De cette façon il est possible de déterminer facilement lequel des trois marqueurs est
celui qui se trouve à l’avant du robot. Pour ce faire, on a recours à trois vecteurs unitaires
dont les origines respectives se trouvent toutes au centre du robot et qui sont orientés de
telle sorte à ce chacun pointe vers le centre d’un des marqueurs du motif de détection.
Sachant que le résultat du produit scalaire entre deux vecteurs unitaires est le cosinus de
l’angle entre les deux, il suffit de trouver la paire de vecteur dont le produit scalaire est
avoisinant de zéro. On sait dès lors, que les deux marqueurs visés par les vecteurs en
question sont ceux qui se trouvent à l’arrière du robot et, implicitement, que l’autre
marqueur est celui qui se trouve à l’avant. Par un autre produit scalaire entre le vecteur
43
unitaire du marqueur avant et un vecteur unitaire confondu avec l’axe de référence, on
obtient le cosinus de l’orientation du robot par rapport à l’axe de référence. Le vecteur
partant du centre du robot vers le marqueur avant révèle par ses composantes en x et en y
dans quel cadran se trouve le marqueur et l’arcosinus du résultat du produit scalaire
permet de calculer l’orientation exacte.
3.3.2 L’identification des robots
Comme il a été discuté à la section 2.1.6, l’identification des robots se fait par couleurs.
Elle est donc traitée après que la position des robots ait été déterminée puisqu’il est alors
possible de récupérer un échantillon de couleur sachant que le centre de l’identificateur
coïncide avec la position du robot. On fait donc une moyenne de la couleur des pixels se
trouvant dans un carré de 4 pixels de côté autour du centre. On est immédiatement en
mesure de déterminer l’équipe d’appartenance de chaque robot par la teinte de rouge et
de bleu. La valeur de la composante verte de l’identificateur est alors stockée pour
chaque robot. Une fois cette étape terminée, on procède par comparaison et le robot ayant
la plus faible valeur de vert dans son identificateur est identifié comme étant le robot #1,
celui qui a la valeur la plus élevée est le robot #3 et l’autre est le robot #2. La
comparaison des intensités de vert doit d’ailleurs être effectuée à nouveau lorsqu’il y a
fusion de deux images d’où la pertinence de son stockage.
La nécessité de procéder par comparaison découle du fait que l’éclairage n’est pas
uniforme sur tout le terrain et que la couleur des identificateurs telle que perçue par les
caméras varie de façon considérable en fonction de la position sur le terrain.
3.3.3 La fusion de l’analyse d’images provenant de deux caméras
44
Le simple fait d’avoir recours à deux caméras pour couvrir tout le terrain implique qu’il y
ait une zone de recouvrement de dimension supérieure à la dimension du plus gros
élément à détecter, en l’occurrence un robot. Les robots ayant une forme cylindrique de
0.4 m de diamètre sont perçus comme des cercles lorsqu’on les regarde en plongé. La
zone de recouvrement se doit donc d’être plus grande que 0.4 m. Évidemment le champ
de vision d’une caméra ne se termine pas brusquement à l’arête de la zone de
recouvrement. La fusion des données se déroule donc comme suit. Pour la caméra 1 tout
élément détecté dans la zone 1 telle qu’identifiée dans la figure 3.12, est ajouté
directement à la liste des éléments du terrain et tout élément détecté dans la zone deux est
ignoré car il aura été détecté avec plus de précision par la caméra 2. Pour la caméra 2 on
procède de la même façon sauf que la zone d’intérêt est la zone 2 alors que la zone à
ignorer est la zone 1.
Figure 3. 12 La zone de recouvrement
Or lorsque l’élément détecté se trouve dans la zone 3, on doit vérifier s’il a été détecté par
les deux caméras. Pour ce faire, on part de l’hypothèse qui veut qu’il doive y avoir un
recouvrement d’aire considérable entre les boîtes de délimitation des deux éléments.
Cette vérification est suffisante dans le cas du ballon alors que dans le cas d’un robot on
effectue la vérification seulement si les robots détectés par les deux caméras font partie
de la même équipe. On identifie donc quatorze cas de recouvrement possible.
1 2 3
45
Soit (xn1, yn1) la coordonnée inférieure gauche et (xn2, yn2) la coordonnée supérieure
droite de la boîte de délimitation du robot détecté par la caméra #n.
Cas 1 : (x21 > x11) & (x21 < x12) & (y22 > y11)
& (y22 < y12)
Aire de recouvrement = (x12 – x21) * (y22 – y11)
Figure 3. 13 Cas de recouvrement 1
Cas 2 : (x12 > x21) & (x12 < x22) & (y12 > y21)
& (y12 < y22)
Aire de recouvrement = (x12 – x21) * (y22 – y11)
Figure 3. 14 Cas de recouvrement 2
Cas 3 : (x11 > x21) & (x11 < x22) & (y12 > y21)
& (y12 < y22)
Aire de recouvrement = (x22 – x11) * (y12 – y21)
Figure 3. 15 Cas de recouvrement 3
(x12 , y12)
(x11 , y11)
(x22 , y22)
(x21 , y21)
(x12 , y12)
(x11 , y11)
(x22 , y22)
(x21 , y21)
(x22 , y22)
(x21 , y21)
(x12 , y12)
(x11 , y11)
46
Cas 4 : (x22 > x11) & (x22 < x12) & (y22 > y11)
& (y22 < y12)
Aire de recouvrement = (x22 – x11) * (y22 – y11)
Figure 3. 16 Cas de recouvrement 4
Cas 5 : (x11 > x21) & (x12 < x22) & (y22 > y11)
& (y22 < y12)
Aire de recouvrement = (x12 - x11)*(y22 - y11)
Figure 3. 17 Cas de recouvrement 5
Cas 6 : (x11 > x21) & (x12 < x22) & (y12 > y21)
& (y12 < y22)
Aire de recouvrement = (x12 - x11)*(y12 - y21)
Figure 3. 18 Cas de recouvrement 6
(x22 , y22)
(x21 , y21)
(x12 , y12)
(x11 , y11)
(x12 , y12)
(x11 , y11)
(x22 , y22)
(x21 , y21)
(x12 , y12)
(x11 , y11)
(x22 , y22)
(x21 , y21)
47
Cas 7 : (x21 > x11) & (x21 < x12) & (y11 > y21)
& (y12 < y22)
Aire de recouvrement = (x12 - x21)*(y12 - y11)
Figure 3. 19 Cas de recouvrement 7
Cas 8 : (x11 > x21) & (x11 < x22) & (y11 > y21)
& (y12 < y22)
Aire de recouvrement = (x22 - x11)*(y12 - y21)
Figure 3. 20 Cas de recouvrement 8
Cas 9 : (x21 > x11) & (x22 < x12) & (y12 > y21)
& (y12 < y22))
Aire de recouvrement = (x22 - x21)*(y12 - y21)
Figure 3. 21 Cas de recouvrement 9
(x22 , y22)
(x21 , y21)
(x12 , y12)
(x11 , y11)
(x12 , y12)
(x11 , y11)
(x22 , y22)
(x21 , y21)
(x22 , y22)
(x21 , y21)
(x12 , y12)
(x11 , y11)
48
Cas 10 : (x21 > x11) & (x22 < x12) & (y22 > y11)
& (y22 < y12))
Aire de recouvrement = (x22 - x21)*(y22 - y11)
Figure 3. 22 Cas de recouvrement 10
Cas 11 : (x11 > x21) & (x11 < x22) & (y21 > y11)
& (y22 < y12))
Aire de recouvrement = (x22 - x11)*(y22 - y21)
Figure 3. 23 Cas de recouvrement 11
Cas 12 : (x21 > x11) & (x21 < x12) & (y21 > y11)
& (y22 < y12))
Aire de recouvrement = (x12 - x21)*(y22 - y11)
Figure 3. 24 Cas de recouvrement 12
(x12 , y12)
(x11 , y11)
(x22 , y22)
(x21 , y21)
(x22 , y22)
(x21 , y21)
(x12 , y12)
(x11 , y11)
(x22 , y22)
(x21 , y21)
(x12 , y12)
(x11 , y11)
49
Cas 13 : (x11 > x21) & (x12 < x22) & (y11 > y21)
& (y12 < y22))
Aire de recouvrement = (x22 - x21)*(y12 - y21)
Figure 3. 25 Cas de recouvrement 13
Cas 14 : (x21 > x11) & (x22 < x12) & (y21 > y11)
& (y22 < y12))
Aire de recouvrement = (x22 - x21)*(y22 - y21)
Figure 3. 26 Cas de recouvrement 14
Le lecteur curieux se demandera probablement pourquoi retrouve-t-on des rectangles et
des carrés plus grand que d’autres dans les figures ci-dessus si on sait que les robots,
étant cylindriques et de même taille, devraient tous avoir des boîtes de délimitation
carrées et de tailles égales. Or, bien que nous ayons recours à une calibration pour en
contrer les effets, les images sont déformées à cause des lentilles et il est impossible
d’aligner parfaitement deux caméras de façon coplanaire. D’ailleurs plusieurs de ces cas
(x22 , y22)
(x21 , y21)
(x12 , y12)
(x11 , y11)
(x12 , y12)
(x11 , y11)
(x22 , y22)
(x21 , y21)
50
n’ont pratiquement aucune chance de se produire, mais pourquoi prendre le risque.
D’autre part, les quatorze cas étant mutuellement exclusifs, le traitement est très efficace
une fois les optimisations faites par le compilateur.
Bref, si l’aire de recouvrement est nulle à la sortie du test c’est que le robot avec lequel la
comparaison a été faite correspond à un tout autre robot et on peut affirmer qu’il n’y a
pas de dédoublement d’information en ce qui concerne ces deux éléments. Si c’est le cas
pour tous les robots de la même équipe se trouvant dans l’aire de recouvrement, c’est que
le robot n’a été détecté que par une des deux caméras et il peut être ajouté à la liste des
robots se trouvant sur le terrain sans traitement supplémentaire. Autrement, si l’aire de
recouvrement est supérieure à une valeur limite par exemple 500 mm2 c’est qu’il y a
dédoublement de l’information et que les deux robots testés sont en fait un seul et même
robot. Conséquemment, pour toutes les données de ce robot on effectue une moyenne des
valeurs telles qu’analysés par les caméras 1 et 2 et on ajoute le robot une seule fois à la
liste d’éléments présents sur le terrain.
4. Discussion Cette dernière section du rapport se veut une critique, aux intentions constructives, du
travail qui a été fait afin d’atteindre les objectifs du système de vision et de tout ce qui
l’entoure. Il en s’agit en fait, d’un retour sur ce qui a été fait, sur ce qui n’a pas été fait
ainsi que sur certaines idées qui valent la peines d’être couchées sur papier.
4.1 Une méthode d’identification des robots à revoir
La principale lacune du système FVS au niveau traitement d’image concerne
l’identification des robots. Ayant longtemps été convaincu que l’utilisation de la couleur
n’y avait pas sa place puisqu’elle a pour conséquence de tripler la quantité d’information
à traiter, l’expérience s’est néanmoins révélée concluante. La méthode en question
procure beaucoup de flexibilité par rapport à l’approche monochrome et il apparaît
évident que l’utilisation de motifs du genre aurait aussi comporté sa part de problèmes si
on considère la déformation des images. Conséquemment, l’approche couleur n’est pas
mauvaise, mais il serait sans doute préférable de mettre sa flexibilité à profit.
Le fait d’avoir recours à la teinte de vert pour identifier le joueur nous oblige à procéder
par comparaison de toutes ces teintes pour une même équipe et il arrive trop souvent que
l’identification soit erronée. Or, on observe une variation de la composante verte que
j’estime à plus de 50% dépendamment de la position du robot sur le terrain. L’approche
est très jolie et très esthétique, mais les conséquences d’une mauvaise identification sont
ce qu’il peut arriver de pire en terme de confusion chez les robots. En effet, chaque
mauvaise identification, induit tous les robots en erreur.
Il serait donc préférable d’avoir recours à 6 couleurs faciles à distinguer les unes des
autres et de les attitrer individuellement aux robots de chaque équipe. Un bon choix pour
ce faire serait d’avoir recours aux identificateurs définis dans le tableau 4.1 ci-dessous.
52
Équipe des bleus Robot Identificateur Composantes
1 Noir R = 0.0, G = 0.0, B = 0.0
2 Bleu R = 0.0, G = 0.0, B = 1.0
3 Vert R = 0.0, G = 1.0, B = 0.0
Équipe des rouges 1 Rouge R = 1.0, G = 0.0, B = 0.0
2 Blanc R = 1.0, G = 1.0, B = 1.0
3 Jaune R = 1.0, G = 1.0, B = 0.0
Tableau 4. 1 Suggestion de couleurs pour les identificateurs
Remarquons que les couleurs ci-dessus sont complètement différentes pour la plupart et
ce, non seulement en terme de couleur, mais aussi en terme d’intensité. Des tests seraient
à faire pour s’assurer que le jaune n’est jamais confondu avec le blanc, ce qui serait fort
surprenant, mais pour ce qui est des 5 autres identificateurs il est pratiquement impossible
qu’il y ait confusion. L’implantation de cette façon de faire n’implique d’ailleurs de
modifier que la fonction identification() de la classe FVS_ImAnalyst (Voir Annexe A)
ainsi qu’un peu de bricolage pour les nouvelles couleurs des identificateurs. Son
utilisation permettrait d’ailleurs d’éliminer le traitement sortPlayers() de la classe
FVS_FusionEngine (Voir Annexe A) ce qui entraînerait une légère amélioration des
performances en mode saisie à deux caméras.
4.2 Une idée pour éliminer les lentilles à grande ouverture
Cette idée a été suggérée par un de mes collègues du laboratoire, M. Alexandre Forget.
Un problème majeur avec l’aménagement matériel découle, comme il a été si souvent
mentionnée dans ce rapport, de la déformation imposée aux images par les lentilles. Une
alternative aux lentilles serait donc d’avoir recours à des miroirs afin de pourvoir éloigner
les caméras encore plus pour compenser un angle d’ouverture plus faible. La caméra
53
pourrait donc être placée horizontalement par rapport au terrain et filmer un miroir
incliné sur lequel se réfléchirait la scène. La mise au point devrait être faite une seule fois
pour être ajustée à la distance qui sépare l’objectif du miroir. Il faudrait tout de même
valider l’hypothèse par calcul pour s’assurer qu’il n’en résulte pas une perte de précision
et pour s’assurer que la disposition du local s’y prête bien, mais l’idée semble très bonne
et vaut certainement la peine d’être soulignée.
4.3 Le patron de calibration
Pour calibrer les caméras, nous avons recours au patron qui a été présenté à la section
3.2.1. Or, alors que ledit patron a pour fonction de corriger l’inexactitude des calculs faits
à partir des images, il s’avère que ce dernier est lui-même imparfait et imprécis. En effet,
le patron a été bricolé sur des panneaux de vinyle qui, malgré toutes nos indications à
celui qui les a taillés, ne sont pas droit et ce détail à lui seul induit sans aucun doute une
erreur considérable. D’autre part, les marqueurs de calibration qui doivent être disposés à
une distance précise de 30 cm les uns des autres, ont été collés présumément au bon
endroit à l’aide d’une règle. Il faut donc espérer que la précision des images déformée est
inférieure à la correction apportée par le patron et surtout que les erreurs ne
s’additionnent pas. Il ne faut pas considérer ces propos comme du pessimisme car les
résultats sont à première vue très bons quoique à l’heure actuelle, ils n’aient pas été
quantifiés.
4.4 Une moyenne plus précise dans la fusion des images Pour fusionner l’information qui provient des deux caméras, on traite d’abord les images
individuellement puis on détermine quels éléments se trouvent dans la zone de
recouvrement avant de faire une moyenne sur la valeur de leurs attributs tels la position et
l’orientation. Pour le moment, cette moyenne se fait de façon géométrique et les résultats
sont tout à fait acceptable. Or, il est évident que plus un élément est rapproché du centre
d’une image plus le calcul de sa position et de son orientation est précis puisque la
54
distorsion radiale est proportionnelle à la distance par rapport au centre en question.
Conséquemment, il serait très facile de gagner en précision en ayant recours à une
moyenne pondérée en fonction de la proximité du centre de l’image de chaque caméra.
Pour ce faire, il faut tenir compte du fait que les positions d’un élément telles que
détectées d’une caméra à l’autre ne seront pas les mêmes. Ainsi pour une zone de
recouvrement de largeur L, ladite zone se situe de part et d’autre de la droite y = 0. Elle
débute donc à y = -L/2 soit dans la zone couverte par la caméra #2 et se termine à y =
+L/2 qui se trouve dans la zone couverte par la caméra #1. Supposons que les caméras se
situent toutes deux à x = 0 et posons (x1,y1) comme étant la position en y d’un élément
telle que détectée par la caméra #1 et (x2,y2) la position telle que détectée par la caméra
#2. La précision de l’information provenant de la caméra #1 est alors inversement
proportionnelle à la distance entre (x1, y1) et (0, L/2) alors que la précision de celle
provenant de la caméra #2, est inversement proportionnelle à la distance entre (x2,y2) et
(0,-L/2).
Posons d1 = ( x12 + (L/2 - y1)2 )1/2 et d2 = ( x2
2 + y2 – (-L/2)2 )1/2 :
Valeurmoy = (1 – d1/(d2 +d1) ) * Valeurcam1 + (1 – d2/(d2 +d1) ) * Valeurcam2
Au coût de quelques calculs supplémentaires, on gagnerait sans aucun doute en précision
en privilégiant cette moyenne pondérée à la moyenne géométrique utilisée présentement.
55
Bibliographie
[1] Watt Alan, Policarpo Fabio, (1998) The Computer Image, ACM Press, New-York & Addison-Wesley Longman Ltd., New-York, Chap. 9 à 13, pages 217 à 323 [2] James Bruce, (2000), Real Time Machine Vision Perception and Prediction, Carnegie Mellon Univesity, Pittsburg http://www-2.cs.cmu.edu/~jbruce/cmvision/papers/JBThesis00.pdf [3] Pressman Roger S., (2001) Software Engineering A Practitioner’s Approach, 5th ed., McGraw-Hill, Boston IL [4] Gamma E., Helm R., Johnson R. et Vlissides, J., (1995)Design Patterns - Elements of Reusable Object-Oriented Software. Addison-Wesley, New-York [5] http://www.ai.polytml.ca [6] http://www.exploits.org/v4l/ [7] http://fizbin.eecs.lehigh.edu/~rjm2/SPU-Toolbox/ [8] http://www.ai.mit.edu/people/bkph/papers/tsaiexplain.pdf
Annexe A – Description des classes
Classe FVS_FusionEngine
Attributs Descriptions
FVS_CaptureEngine* CaptureCam1 Engin de capture de la caméra #1
FVS_ImAnalyst* AnalystCam1 Objet d’analyse des images de la caméra #1
FVS_CaptureEngine* CaptureCam2 Engin de capture de la caméra #2
FVS_ImAnalyst* AnalystCam2 Objet d’analyse des images de la caméra #1
list<FVS_Robot*> FusionList Liste de tous les robots présents sur le terrain
list<FVS_Robot*> RedList Liste de tous les robots de l’équipe des rouges
présents sur le terrain
list<FVS_Robot*> BlueList Liste de tous les robots de l’équipe des bleus
présents sur le terrain
FVS_Ball* TheBall Les données relatives au ballon
int total_robots Le nombre de robot détectés à l’itération courante
int file_pipes[2] Descripteurs de fichier pour la communication
avec le processus de transmission réseau
Mediator_GuiApp* MyMedGuiApp Médiateur entre l’interface et l’application
pthread_t stream_thread Processus léger pour le traitement d’image en
continu
FVS_FusionEngine(Mediator_GuiApp* m = 0)
Constructeur par défaut qui permet d’assigner l’objet de médiation avec l’interface.
~FVS_FusionEngine()
Destructeur.
void setMedGuiApp(Mediator_GuiApp* med)
Assigne le paramètre med à l’attribut MyMedGuiApp.
void saveCaptureImage(const char* file, int format)
Sauvegarde l’image saisie dans le fichier file selon le format (RAW = 1, TGA = 2) .
57
FVS_ImAnalyst* get_Analyst1(void)
Retourne un pointeur vers AnalystCam1.
FVS_ImAnalyst* get_Analyst2(void)
Retourne un pointeur vers AnalystCam2.
FVS_CaptureEngine* get_CaptureCam1(void)
Retourne un pointeur vers CaptureCam1.
FVS_CaptureEngine* get_CaptureCam2(void)
Retourne un pointeur vers CaptureCam2.
FVS_Ball* get_TheBall(void)
Retourne un pointeur vers TheBall.
bool getRedIterators(list<FVS_Robot*>::iterator &beg, list<FVS_Robot*>::iterator
&fin)
Retourne vrai si RedList n’est pas vide et les paramètres beg et fin prennent
respectivement les valeurs des itérateurs de début et de fin de la liste.
bool getBlueIterators(list<FVS_Robot*>::iterator &beg,
list<FVS_Robot*>::iterator &fin)
Retourne vrai si BlueList n’est pas vide et les paramètres beg et fin prennent
respectivement les valeurs des itérateurs de début et de fin de liste.
void CaptureFrame(int CamNum)
Effectue la saisie d’une image de la caméra # CamNum.
void AnalyseFrame(int CamNum)
Effectue l’analyse complète d’une image de la caméra # CamNum.
void continuousCapture(void)
Effectue la capture d’images en continu.
void doCaptureCam1(void)
Regroupe les opérations de saisie et de traitement de l’image pour la caméra #1 et envoie
l’information au processus de transmission réseau.
void doCaptureCam2(void)
58
Regroupe les opérations de saisie et de traitement de l’image pour la caméra #2 et envoie
l’information au processus de transmission réseau.
void twinCapture(void)
Regroupe les opérations de saisie et de traitement de l’image pour les caméra #1 et #2,
fusionne l’information et l’envoie au processus de transmission réseau.
int startStreaming(void)
Démarre le thread de traitement continu et retourne 0 en cas de succès –1 en cas d’échec.
void DisplayFrame(void)
Signale à l’interface de rafraîchir son affichage de l’image filmée.
void DisplayResults()
Signale à l’interface de rafraîchir son affichage des résultats du traitement.
void mergeResults(void)
Fusionne les données en mode deux caméras.
void sortPlayers(void)
Trie les robots une fois les données fusionnées afin d’attribuer les bons numéros de
joueurs.
float calculerRecouvrement(float x11, float y11,float x12, float y12,
float x21, floaty21,float x22, float y22)
Retourne l’aire de recouvrement entre les deux boîtes d’encadrement décrites par les
paramètres.
void transmitResults(void)
Envoie les résultats du traitement au processus de transmission réseau.
void setFilePipe(int fp[])
Attitre les descripteurs de fichier pour la communication avec le processus de
transmission réseau à travers un tube de communication.
static void* streamCam1(void* me)
Fonction qu’exécute le thread de traitement continu. Le paramètre me est un pointeur
vers l’objet courant.
59
Classe FVS_CaptureEngine
Attributs Description
V4L* FrameGrabber Objet donnant accès au pilote de la carte d’acquisition
d’images
FVS_Camera* the_camera Objet de définition des paramètres de la caméra
FVS_CaptureEngine()
Constructeur par défaut.
FVS_CaptureEngine(int cam_num)
Constructeur qui permet d’attitrer une caméra et une carte de saisie à l’objet .
~FVS_CaptureEngine()
Destructeur.
bool initialize(int cam_num = 1)
Initialise l’objet et tous ses attributs en fonction de la carte et de l’objet désignés par num.
void set_CameraOffset(float x, float y)
Obtenir le décalage de l’origine de la caméra p/r à l’origine du terrain.
void get_CameraOffset(float& x, float& y)
Définir le décalage de l’origine de la caméra p/r à l’origine du terrain.
void image_coord_to_world_coord (double Xfd, double Yfd, double zw, double
&xw, double &yw)
Retourne les coordonnées réelles en mm pour une position (Xfd, Yfd) en pixel. La
hauteur en mm de l’objet doit être spécifiée dans zw.
void load_CalibParameters(char* calib_file)
Chargement des paramètres de calibration de la caméra.
void display_CalibParameters(void)
Affichage dans la console des paramètres de calibration.
void capture_ColorFrame(unsigned char* ColorFrame)
Effectuer la saisie d’une image couleur.
void save_RawFrame(const char* filename, unsigned char* ColorFrame)
Sauvegarder l’image courante dans le fichier filename en format RAW.
60
void save_TgaFrame(const char* filename, unsigned char* ColorFrame)
Sauvegarder l’image courante dans le fichier filename en format RAW.
int get_Brightness(void)
Retourne la brillance à laquelle est réglé le pilote de saisie d’image.
int get_Contrast(void)
Retourne le contraste auquel est réglé le pilote de saisie d’image.
void set_Brightness(int b)
Règle la brillance du pilote de saisie d’image à b.
void set_Contrast(int c)
Règle le contraste du pilote de saisie d’image à c.
Classe FVS_Camera
Attributs Descriptions
float offset_x Décalage selon l’axe des x de l’origine de la caméra par
rapport à l’origine du terrain.
float offset_y Décalage selon l’axe des y de l’origine de la caméra par
rapport à l’origine du terrain.
FVS_Calib* calibration Outils de calibration des images issue de cette caméra
FVS_Camera()
Constructeur par défaut.
FVS_Camera(char* calib_file, float x, float y)
Constructeur qui initialise tous les attributs de la classe
~FVS_Camera()
Destructeur
void get_OriginOffset(float& x, float& y)
Obtenir le décalage de l’origine de la caméra p/r à l’origine du terrain.
void set_OriginOffset(float x, float y)
61
Definir le décalage de l’origine de la caméra p/r à l’origine du terrain.
void image_coord_to_world_coord (double Xfd, double Yfd, double zw, double
&xw, double &yw)
Retourne le coordonnées réelles en mm pour une position (Xfd, Yfd) en pixel. La hauteur
en mm de l’objet doit être spécifiée dans zw.
void changeReferencial(double &x, double &y)
Applique la translation nécessaire au point (x,y) pour l’amener dans le référentiel du
terrain.
void load_CalibParameters(char* calib_file)
Chargement des paramètres de calibration de la caméra.
void display_CalibParameters(void)
Affichage dans la console des paramètres de calibration.
Classe FVS_Calib
Attributs Descriptions
camera_parameters cp Paramètres de la caméra
calibration_data cd Données permettant la calibration
calibration_constants cc Constantes
FVS_Calib()
Constructeur par défaut.
FVS_Calib(camera_parameters a, calibration_data b, calibration_constants c)
Constructeur qui initialise les attributs de l’objet.
~FVS_Calib()
Destructeur
void image_coord_to_world_coord (double Xfd, double Yfd, double zw, double
&xw, double &yw)
Retourne le coordonnées réelles en mm pour une position (Xfd, Yfd) en pixel. La hauteur
en mm de l’objet doit être spécifiée dans zw.
62
void distorted_to_undistorted_sensor_coord (double Xd, double Yd, double &Xu,
double &Yu)
Fonction de correction de la distortion radiale due à la lentille.
bool load_cp_cc_data (char *file_name)
Chargement des paramètres de calibration à partir d’un fichier. Retourne faux si échec.
void displayCalibrationParameters(void)
Affichage dans la console des paramètres de calibration.
Il est à noter que la classe FVS_Calib a recours à deux structures dont les attributs sont
détaillés ci-dessous.
Structure camera_parameters Attributs Descriptions
double Ncx Nombre de senseurs selon l’axe des x du ccd [sel]
double Nfx Nombre de pixels selon l’axe des x du frame grabber [pix]
double dx Largeur des cellules photosensibles du ccd [mm/sel]
double dy Hauteur des cellules photosensibles du ccd [mm/sel]
double dpx Dimension en X des pixels du frame grabber [mm/pix]
double dpy Dimension en Y des pixels du frame grabber [mm/pix]
double Cx Intersection entre l’Axe des z et le système de coordonné de la caméra
double Cy Intersection entre l’Axe des z et le système de coordonné de la caméra
double sx Facteur d’échelle pour compenser les erreurs en dpx
Structure calibration_constants
Attributs Descriptions
double f foyer [mm]
double kappa1 distorsion radiale [1/mm^2]
double p1 [1/mm]
double p2 [1/mm]
double Tx Translation en x p/r à l’origine [mm]
double Ty Translation en y p/r à l’origine [mm]
63
double Tz Translation en z p/r à l’origine [mm]
double Rx Rotation par rapport à l’axe des x d’un système de coordonnés dont
l’axe des z serait perpendiculaire à la lentille de la caméra [rad]
double Ry Rotation par rapport à l’axe des y [rad]
double Rz Rotation par rapport à l’axe des z [rad]
Classe FVS_ImAnalyst : public CMVision
Attributs Description
int nbr_robs Le nombre de robots détectés à l’itération courante.
nbr_ball Le nombre de ballon détectés à l’itération courante.
FVS_Robot* RobotRef Un robot de référence pour fins de comparaison.
FVS_Ball* BallRef Un ballon de référence pour fins de comparaison.
FVS_Robot** RobotList Un tableau des robots détectés à l’itération courante.
FVS_Robot** RobotListPrev Un tableau des robots détectés à l’itération précédente.
FVS_Ball* theBall Le ballon détecté à l’itération courante.
FVS_Field* Terrain Le terrain sur lequel évoluent les robots
FVS_Image* MyImage L’image qui contient le résultat de la saisie.
CMVision* aimed Un outil CMV pour le traitement des marqueurs
d'orientation
FVS_Element* Spotted Un élément pour le traitement des marqueurs
d’orientation
FVS_ImAnalyst()
Construteur
virtual ~FVS_ImAnalyst()
Destructeur virtuel car la classe hérite de CMVision.
void Init(int w, int h, int nbrRob)
Initialisation des attributs doit être appelée avant la 1ere utilisation.
64
FVS_Robot** getRobotList(void)
Retourne un pointeur vers le tableau de robots détectés à l’itération courante.
FVS_Robot** getRobotListPrev(void)
Retourne un pointeur vers le tableau de robots détectés à l’itération précédente.
FVS_Ball* getBall(void)
Retourne un pointeur vers le ballon détecté à l’itération courante.
FVS_Field* getField(void)
Retourne un pointeur vers le terrain.
FVS_Robot* getRobotRef(void)
Retourne un pointeur vers le robot de référence.
FVS_Ball* getBallRef(void)
Retourne un pointeur vers le ballon de référence.
FVS_Image* getImage(void)
Retourne un pointeur vers l’image qui contient le résultat de la saisie.
void setRobotRef(float dd)
Ajuste le diamètre du robot de référence.
void setBallRef(float dd)
Ajuste le diamètre du ballon de référence.
int getNbrRobots(void)
Retourne le nombre de robots détectés à l’itération courante.
int getNbrBall(void)
Retourne le nombre de ballons détectés à l’itération courante.
float setRobotRef(void)
Calcule le diamètre d’un robot isolé à l’écran et assigne son diamètre au robot de
référence.
float setBallRef(void)
Calcule le diamètre d’un ballon isolé à l’écran et assigne son diamètre au ballon de
référence.
void swapLists(void)
65
Permutation des liste de l’itération précédente et de l’itération courante. Précède chaque
nouvelle analyse.
int processRegions(int color_id)
Traite les régions d’une même couleur. En ce qui nous concerne le color_id du blanc est
0.
void Identification(void)
Identifie par une analyse de couleur toutes les régions considérées comme des robots.
void getColorSample(int x, int y, int side, unsigned& B, unsigned& G, unsigned& R)
Extrait un échantillon moyen de couleur dans la région de largeur 2*side autout du pixel
(x,y) et retourne le résultat dans les trois composantes de couleur B, G, R.
void changeReferential(bool cam1)
Actualise toutes les positions en fonction du référentiel de la caméra concernée.
Caméra #1 si cam1 = true, Caméra #2 sinon.
int Orientation(FVS_Robot*)
Calcule l’orientation du robot reçu en paramètre par une détection de ses marqueurs.
int allOrientations(void)
Calcule l’orientation de tous les robots détectés à l’itération courante.
int minCosine(float cosine1, float cosine2, float cosine3)
Retourne l’indice 1,2 ,3 du plus faible des trois cosinus reçus en paramètre.
void normaliseVector(FVS_Vect vect[])
Normalisation des vecteurs contenus dans le tableau reçu en paramètre.
void CosinesBetweenVects(FVS_Vect vect[],float &, float &, float &)
Calcule le cosinus entre les trois vecteurs contenus dans le tableau reçu en paramètre.
void isolate(unsigned* isolated_region, FVS_Robot* leRobot)
Extrait dans une image la région qui contient le Robot et en copie la négation dans
isolated_region.
void registerOrientation(FVS_Vect *vector, float cosorient, float &orientation)
Calcule l’orientation à partir du cosinus que fait le vecteur par rapport à l’axe des y
négatif de l’image.
66
Classe FVS_Image
Attributs Définitions
int im_width Largeur de l’image
int im_height Hauteur de l’image
int bytes_per_pix Nombre d’octet par pixel
int bytes_per_line Nombre d’octet par ligne = bytes_per_pix * im_width
int data_offset Décalage des données dans une image .pnm = taille de
l’entête
float binarisation_limit Limite de seuillage
int clip_lines[4] Rectangle de délimitation. Tout ce qui se trouve à
l’extérieur dans l’image n’est pas traité.
unsigned char* ColorImage Image saisie en couleur transformée en .pnm pour
affichage.
unsigned char* BwImage Image binarisée transformée en .pnm pour affichage
unsigned char* ColorFrame Contenu de l’image couleur sans l’entête.
Adresse = &ColorImage[0] + data_offset.
unsigned char* BwFrame Contenu de l’image binarisée sans l’entête.
Adresse = &BwImage[0] + data_offset.
unsigned* CMV_Map Tableau d’entier non signées qui désigne les régions dans
l’image. Un pixel allumé = 1 et un pixel éteint = 0.
int* HistInfo Nombre de pixels en fct. de l’intensité
FVS_Image()
Constructeur.
~FVS_Image()
Destructeur.
void initialize(int width, int height, float limit)
67
Fonction d’initialisation qui doit être appelée avant la première utilisation d’un objet
FVS_Image.
void Binarisation(bool Hist)
Binarise l’image et génère l’information relative à l’histogramme de l’intensité dans
HistInfo si Hist = true.
bool getColorPixel(int x, int y, unsigned& B, unsigned& G, unsigned& R)
Retourne les trois composantes de couleur B,G,R pour le pixel (x,y)
int get_ColorImageLen(void)
Retourne la taille de l’image en octets.
int get_Width(void)
Retourne la largeur de l’image.
int get_Height(void)
Retourne la hauteur de l’image.
unsigned* get_CMV_Map(void)
Retourne un pointeur vers l’attribut CMV_Map.
unsigned char* get_ColorImage(void)
Retourne un pointeur vers l’attribut ColorImage.
unsigned char* get_ColorFrame(void)
Retourne un pointeur vers l’attribut ColorFrame.
unsigned char* get_BwImage(void)
Retourne un pointeur vers l’attribut BwImage.
unsigned char* get_BwFrame(void)
Retourne un pointeur vers l’attribut BwFrame.
void set_BinarisationLimit(float lim)
Ajuste la limite de seuillage représentée par l’attribut binarisation_limit.
float get_BinarisationLimit(void)
Retourne la valeur de binarisation_limit.
int* getHistInfo(void)
Retourne un pointeur vers l’attribut HistInfo
void get_ClipLines(int lines[])
68
Retourne la valeur du rectangle de délimitation.
void set_ClipLines(int lines[])
Ajuste les coins du rectangle de délimitation.
void set_ClipLines(int x1, int y1, int x2, int y2)
Surcharge de la fonction précédente.
Classe FVS_Element
Attributs Définitions
int pixposx, pixposy Position du centre du robot en pixel
int pixposx, pixposy Position réelle du centre du robot en ce que vous voulez.
float boundx1, boundy1 Coin inférieur gauche de la boîte qui contient l’élément.
float boundx2,boundy2 Coin supérieur droit de la boîte qui contient l’élément.
float diameter Diamètre du robot en pixel
float height Hauteur réelle du robot en mm
FVS_Element()
Constructeur.
virtual ~FVS_Element()
Destructeur.
void set_Position(float x, float y)
Ajuste la position réelle de l’élément.
void get_Position(float& x, float& y)
Retourne la position réelle de l’élément.
void set_PixPosition(int x, int y)
Ajuste la position en pixel dans l’image de l’élément.
void get_PixPosition(int& x, int& y)
Retourne la position en pixel dans l’image de l’élément.
float get_PixPosX(void)
Retourne la composante en x de la position en pixel dans l’image de l’élément.
69
float get_PixPosY(void)
Retourne la composante en y de la position en pixel dans l’image de l’élément.
float get_Posx(void)
Retourne la composante en x de la position réelle de l’élément.
float get_Posy(void)
Retourne la composante en y de la position réelle de l’élément.
void set_BBox(float,float,float,float)
Ajuste les 4 coins de la boîte qui contient l’élément.
void get_BBox(float& x1,float& y1,float& x2,float& y2)
Retourne les 4 coins de la boîte qui contient l’élément.
float get_BBoxWidth(void)
Retourne la largeur de la boîte qui contient l’élément.
float get_BBoxHeight(void)
Retourne la hauteur de la boîte qui contient l’élément.
void get_BBoxCorner(float& x, float& y )
Retourne le coin inférieur gauche de la boîte qui contient l’élément.
float getRatio(void)
Retourne le ratio hauteur/largeur de l’élément qu’on peut calculer avec la boîte.
float calculateDiameter(void)
Retourne et calcule le diamètre de l’élément à partir de la taille de la boîte qui le contient.
void set_Diameter(float d)
Ajuste le diamètre de l’élément.
float get_Diameter(void)
Retourne et calcule le diamètre de l’élément.
void set_Height(float h )
Ajuste la hauteur réelle de l’élément en mm.
float get_Height(void)
Retourne la hauteur réelle de l’élément en mm.
70
Classe FVS_Robot: public FVS_Element
Attributs Définition
float orientation Orientation du robot
float green_amount Composante verte de l’identificateur du robot. Sert à identifier le
joueur.
int team L’équipe à laquelle appartient le robot.(1 = rouge, 2 = bleu)
int player Le joueur (0,1,2)
FVS_Robot()
Constructeur.
virtual ~FVS_Robot()
Destructeur virtuel car il y a héritage.
void set_Team(int t)
Ajuster l’équipe d’appartenance du robot en mettant team = t.
void set_Player(int p)
Ajuste player à p.
int get_Team(void)
Retourne l’équipe d’appartenance du robot.
int get_Player(void)
Retourne le numéro de joueur du robot.
void set_Orientation(float o)
Ajuste l’orientation du robot.
float get_Orientation(void)
Retourne l’orientation du robot.
void set_GreenAmount(float g)
Ajuste la composante verte de l’identificateur du robot.
float get_GreenAmount(void)
Retourne la valeur de la composante vertes de l’identificateur du robot.
71
Classe FVS_Field
Attributs Définitions
int NbrRobots NbrRed + NbrBlue
int NbrRed Nombre de robots de l’équipe des rouges présents sur le terrain.
int NbrBlue Nombre de robots de l’équipe des bleus présents sur le terrain.
int NbrBall Nombre de ballons sur le terrain
float field_width Largeur du terrain (3m dans notre cas)
float field_height Hauteur du terrain (6m dans notre cas)
int originX Position en x en pixels de l'origine dans l'image
int originY Position en y en pixels de l'origine dans l'image
FVS_Field()
Constructeur.
~FVS_Field()
Destructeur.
void setOrigin(int x, int y)
Ajuste la position en pixels du centre du terrain.
void getOrigin(int &, int &)
Retourne la position en pixels du centre du terrain.
void setDimension(float w, float h)
Ajuste les dimension du terrain en faisant field_width = w et field_heigth = h.
void getDimension(float &, float &)
Retourne les dimensions du terrain
void setNbrRobots(int blue, int red)
Ajuste le nombre de robots rouges, bleus et total.
void getNbrRobots(int &b, int &r, int &t)
Retourne le nombre de robots bleus, rouges et total.
void setNbrBalls(int b)
Ajuste le nombre de ballons sur le terrain.
72
int getNbrBalls(void)
Retourne le nombre de ballons sur le terrain.
void setNbrRobots(int total)
Ajuste le nombre total de robots.
void setNbrRed(int red)
Ajuste le nombre de robots rouges.
void setNbrBlue(int blue)
Ajuste le nombre de robots bleus.
int getNbrRed(void)
Retourne le nombre de robots rouges.
int getNbrBlue(void)
Retourne le nombre de robots bleus.
int getNbrRobots(void)
Retourne le nombre total de robots.
73
Classe FVS_Interface : public QDialog
Attributs Description
Hist_Widget* Histogram Instance de la classe Hist_Widget qui permet
d’ajuster le seuil et d’afficher l’histogramme du
nombre de pixels en fonction de l’intensité.
ContextWidget* ContextButtons Instance de la classe ContextWidget qui affiche les
boutons appropriés en fonction du contexte
d’utilisation de saisie continue ou ponctuelle.
SettingsWidget* SettingsPanel Fenêtre de configuration du système.
MainScreen* DisplayWindow Écran de visualisation des images saisies.
QSignal* refreshScreen Signal émis lorsque DisplayWindow doit être
rafraîchie.
QSignal* refreshData Signal émis lorsque les données de l’analyse
d’image doivent être rafraîchies
Mediator_GuiApp* MyMedGuiApp Médiateur entre l’interface et l’instance de la classe
FVS_FusionEngine.
FVS_Interface( QWidget* parent = 0, const char* name = 0, bool modal = FALSE,
WFlags fl = 0 )
Constructeur par défaut, à appeler tel quel.
~FVS_Interface()
Destructeur.
void setMedGuiApp(Mediator_GuiApp* med)
Ajuste le pointeur MyMedGuiApp vers l’objet pointé par med.
bool colorDisplay(void)
Retourne vrai si on désire afficher en couleur.
bool monitorCam1(void)
Retourne vrai si la caméra #1 est monitorée.
bool displayResults(void)
Retourne vrai si on souhaite afficher les résultats d’analyse.
bool displayHist(void)
74
Retourne vrai si on désire afficher l’histogramme des intensités.
bool displayImage(void)
Retourne vrai si on désire afficher l’image.
bool stillStreaming(void)
Retourne vrai si la capture en continue est en marche.
bool fusionEnabled(void)
Retourne vrai si les informations des deux caméras doivent être fusionnées.
void resetLCD(void)
Réinitialise les cellules d’affichage de l’information d’analyse.
void resetLCD(int team, int player)
Réinitialise les cellules d’affichage de l’information d’analyse concernant le joueur
player de l’équiper team.
void updateLCD(int team, int player, float posx, float posy, float orient)
Rafraîchi l’affichage de l’information des cellules du joueur player de l’équiper team en
y insérant l’information reçue en paramètres.
void adjustSliders(int bright, int contrast, int bin)
Ajuste la position des boutons glissoirs de luminosité, de contraste et du seuil de
binarisation.
void popErrorMessage(char* message, char* directive)
Fait surgir une fenêtre modale qui affiche le message d’erreur message et suggère
directive.
void signalScreen(void)
Signale à l’interface qu’elle doit rafraîchir l’image affichée.
void signalData(void)
Signale à l’interface qu’elle doit rafraîchir les données affichée.
void slot_quitter(void)
Termine le programme.
void slot_toCapture(void)
Indique à ContextButtons d’afficher les boutons contextuels propres à la capture
ponctuelle d’images.
75
void slot_toStreaming(void)
Indique à ContextButtons d’afficher les boutons contextuels propres à la capture continue
d’images.
void slot_displayLCD(void)
Fait apparaître les cellules d’affichage de l’information d’analyse.
void slot_displayHist(void)
Fait apparaître l’histogramme d’intensité.
void slot_displayImage(void)
Fait apparaître l’écran d’affichage de l’image saisie.
void slot_adjustBright(int)
Indique au médiateur qu’on désire changer la luminosité pour la valeur passée en
paramètre.
void slot_adjustCont(int)
Indique au médiateur qu’on désire changer le contraste pour la valeur passée en
paramètre.
void slot_adjustBinarisation(int)
Indique au médiateur qu’on désire changer le seuil de binarisation pour la valeur passée
en paramètre.
void slot_RobotRef(void)
Indique à l’application qu’elle doit régler sa référence d’un robot comme étant celle de
l’unique élément qu’on retrouve à l’écran.
void slot_BallRef(void)
Indique à l’application qu’elle doit régler sa référence d’un ballon comme étant celle de
l’unique élément qu’on retrouve à l’écran.
void slot_showOrigin(void)
Affiche des lignes partant de l’origine selon les axes X et Y. (Non implémentée)
void slot_displayDetection(void)
Affiche une croix au centre des objets détectés. (Non implémentée)
void slot_imageFusion(void)
Indique à l’application que la fusion d’information est activée.
76
void slot_captureImage(void)
Indique à l’application de saisir un image.
void slot_saveImage(void)
Indique à l’application de sauvegarder l’image.
void slot_startStreaming(void)
Démarre la saisie d’images en continu.
void slot_stopStreaming(void)
Arrête la saisie d’images.
void slot_ClipImage(int lines[4])
Indique à l’application qu’elle ne doit pas tenir compte de l’information se situant à
l’extérieur de la boîte de délimitation définie par lines pour la caméra qui est
présentement monitorée.
void slot_DisplayResults()
Affiche les résultats d’analyse.
void slot_DisplayFrame(void)
Affiche l’image saisie.
void slot_EditSettings()
Fait apparaître la fenêtre de configuration du système.
void slot_connection()
Indique à l’application qu’elle doit transmettre l’information d’analyse au serveur de
match.
void slot_disconnection()
Indique à l’application qu’elle doit cesser de transmettre l’information d’analyse au
serveur de match.
77
Classe ContextWidget : public Qwidget
Attributs Description
QPushButton* CaptureButton Signale à l’application de saisir une image.
QPushButton* SaveButton Signale à l’application de sauvegarder une image
préalablement saisie.
QPushButton* StartButton Signale à l’application de démarrer la saisie d’images en
continu.
QPushButton* StopButton Signale à l’application de d’arrêter la saisie d’images en
continu.
FVS_Interface* my_parent Pointeur vers l’interface mère.
ContextWidget( FVS_Interface* parent = 0, const char* name = 0, WFlags fl = 0 )
Constructeur par défaut. Le paramètre parent doit correspondre à un pointeur vers
l’interface mère, en l’occurrence, l’instance de la classe FVS_Interface.
~ContextWidget()
Destructeur
void switchContext(int cont)
Si cont = 0 affiche les boutons du contexte de capture ponctuelle. Si cont = 1 affiche les
boutons du contexte de capture en continu.
void captureOneFrame(void)
Indique à l’application d’effectuer une saisie et un traitement d’image.
void saveImage(void)
Indique à l’application de sauvegarder l’image préalablement saisie.
void startStreaming(void)
Indique à l’application de démarrer la saisie et le traitement d’image en continu.
void stopStreaming(void)
Indique à l’application d’arrêter la saisie et le traitement d’image en continu.
bool isStartEnabled(void)
Retourne vrai si le bouton Start est enfoncé.
78
Classe Hist_Widget : public Qwidget
Attributs Description
QSlider* Slider3 Bouton glissoir qui permet d’ajuster le seuil de binarisation.
QFrame* Line4 Axe d’abscisse du diagramme.
QFrame* Line1 Axe d’ordonnée du diagramme
QFrame* Frame Cadre d’affichage de l’histogramme
FVS_Interface *father Pointeur vers l’interface mère.
Hist_Widget( FVS_Interface* parent = 0, const char* name = 0, WFlags fl = 0 )
Constructeur par défaut. Le paramètre parent doit correspondre à un pointeur vers
l’interface mère, en l’occurrence, l’instance de la classe FVS_Interface.
~Hist_Widget()
Destructeur.
void drawHistogram(int* data)
Affiche l’histogramme des données pointées par data.
void slot_adjustBin(int bin)
Indique à l’application d’ajuster son seuil de binarisation à bin pour l’image monitorée.
79
Classe MainScreen : public QWidget
Attributs Description
int* clip_lines Les coordonnée de la boîte de délimitation.
int* clip_lines_temp Les coordonnée temporaires de la boîte de délimitation.
QPen* pen Défini la couleur des lignes qu’on trace sur l’écran .
QPainter* paint Permet de dessiner sur le cadre d’affichage.
QPixmap* frame Cadre d’affichage.
FVS_Interface* my_parent Pointeur vres l’interface mère
MainScreen( FVS_Interface* parent, const char* name )
Constructeur par défaut. Le paramètre parent doit correspondre à un pointeur vers
l’interface mère, en l’occurrence, l’instance de la classe FVS_Interface.
~MainScreen( )
Destructeur.
void mousePressEvent( QMouseEvent* )
Sauvegarde la position du curseur de la souris dans l’écran lorsque le bouton gauche est
enfoncé.
void mouseMoveEvent( QMouseEvent* )
Sauvegarde la position du curseur de la souris dans l’écran lorsque celui-ci est déplacé
avec le bouton gauche enfoncé.
void mouseReleaseEvent( QMouseEvent* )
Sauvegarde la position du curseur de la souris dans l’écran lorsque le bouton gauche est
relâché. Appelle resetClip_Lines() si c’est le bouton droit qui est relâché.
void enableClipping(void)
Active la boîte de délimitation de l’image.
void disableClipping(void)
Désactive la boîte de délimitation de l’image.
void clipImage(int* boudaries)
Coupe l’image en fonction de la boîte de délimitation définie par boundaries.
80
void resetClip_Lines(void)
Ajuste la boîte de délimitation à tout l’écran.
void refresh(void)
Rafraîchi l’affichage de l’image saisie.
Classe SettingsWidget : public Qwidget
Attributs Description
QPushButton* OKButton Bouton OK, signale à l’application d’appliquer la
configuration et ferme la fenêtre de configuration.
QPushButton* CancelButton Bouton Cancel, ferme la fenêtre de configuration sans tenir
compte des changements.
QPushButton* ApplyButton Bouton Apply, signale à l’application d’appliquer la
configuration.
FVS_Interface* my_parent Pointeur vers l’interface mère.
SettingsWidget( QWidget* parent = 0, const char* name = 0, WFlags fl = 0 )
Constructeur par défaut. Le paramètre parent doit correspondre à un pointeur vers
l’interface mère, en l’occurrence, l’instance de la classe FVS_Interface.
~SettingsWidget()
Destructeur.
void setParent(FVS_Interface* p)
Ajuste le pointeur my_parent vers l’objet pointé par p.
void slot_apply(void)
Indique à l’application d’appliquer les nouveaux paramètres de configuration. (Non
Implémenté)
void slot_ok(void)
81
Indique à l’application d’appliquer les nouveaux paramètres de configuration et ferme la
fenêtre de configuration. (Non Implémenté)
void slot_cancel(void)
Ferme la fenêtre de configuration sans tenir compte des nouveaux paramètres. (Non
Implémenté)
Classe Mediator_GuiApp
Attributs Description
FVS_Interface* my_gui Pointeur vers l’interface.
FVS_FusionEngine* my_fusion Pointeur vers l’engin de fusion.
QApplication* my_app Pointeur vers l’application QT. C’est l’application qui
affiche l’interface.
Mediator_GuiApp(FVS_Interface *inter = 0)
Constructeur par défaut. Le paramètre parent doit correspondre à un pointeur vers
l’interface mère, en l’occurrence, l’instance de la classe FVS_Interface.
~Mediator_GuiApp()
Destructeur.
void setInterfacePointer(FVS_Interface *inter)
Ajuste le pointeur my_gui vers l’interface pointée par inter.
void setApplicationPointer(QApplication *app)
Ajuste le pointeur my_app vers l’application QT pointée par app.
void setFusionPointer(FVS_FusionEngine* fus)
Ajuste le pointeur my_fusion vers l’engin de fusion pointé par fus.
FVS_Interface* get_Gui()
Retourne un pointeur vers my_gui.
82
FVS_FusionEngine* get_Fusion()
Retourne un pointeur vers my_fusion.
void Capture()
Transmet le message à l’engin de fusion d’effectuer une capture.
void saveImage(const char* file, int format)
Transmet le message à l’engin de fusion de sauvegarder l’image dans le fichier file en
format 0 = .raw ou 1 = .tga.
void ClipImage(int box[4])
Transmet le message à l’engin de fusion qu’il doit appliquer la zone de délimitation
définie par box aux images provenant de la caméra qui est présentement monitorée.
void startStreaming()
Transmet le message à l’engin de fusion qu’il doit démarrer la saisie en mode continu.
void getClipLines(int lines[4])
Retourne la boite de délimitation telle que définie dans l’engin de fusion pour la caméra
courante.
void setRobotRef(void)
Indique à l’engin de fusion qu’il doit ajuster sa référence d’un robot comme étant celle de
l’unique élément qu’on retrouve à l’écran.
void setBallRef(void)
Indique à l’engin de fusion qu’il doit ajuster sa référence d’un ballon comme étant celle
de l’unique élément qu’on retrouve à l’écran.
void setBinarisation(float limit)
Indique à l’engin de fusion qu’il doit ajuster le seuil de binarisation de l’image à la valeur
passée en paramètre.
void setBrightness(int B)
Indique à l’engin de fusion qu’il doit ajuster la brillance de l’image à la valeur passée en
paramètre.
void setContrast(int C)
Indique à l’engin de fusion qu’il doit ajuster le contraste de l’image à la valeur passée en
paramètre.
83
void quit(void)
Termine le programme.
bool stillStreaming()
Retourne vrai si on est toujours en saisie continue.
void signalScreenRefresh(void)
Active le signal de l’interface qui met en branle la procédure de rafraîchissement de
l’écran d’affichage de l’image.
void signalDataRefresh(void)
Active le signal de l’interface qui met en branle la procédure de rafraîchissement de
l’affichage des données d’analyse.
unsigned char* get_ColorImage(int num)
Retourne un pointeur vers l’image couleur de la caméra désignée par num.
unsigned char* get_BwImage(int num)
Retourne un pointeur vers l’image binarisée de la caméra désignée par num.
int get_ImLen(int num)
Retourne la taille d’une image.