ELECINF344/381

Partie interactive du site pédagogique ELECINF344/ELECINF381 de Télécom ParisTech (occurrence 2011).

Catégories

[Casper] Face tracking

We now have our face tracking algorithm running on BeagleBoard. Since a tracking only based on face detection was to slow and not very intuitive (you always have to look the camera), we decided to use a blob tracking algorithm, which we initialize with the face detection algorithm.

First, Casper looks for a face. When it finds one, it learns the associated color histogram. After what it tracks the histogram (with the OpenCV Camshift function), for a few tens of frames. If it does not find a face again during the blob tracking, it stops at the end of the frames. Otherwise, it keeps tracking the « blob » face.

We adopt a multithread program : a thread looks for a face every second, and a thread is responsible for blob tracking when a face is found. The first thread is used to set a counter which is decremented by the second thread.

 

[CASPER] Today’s news

We progressed in different fields today.

Alain designed a small extension PCB for the beagleboard. This board will include the necessary elements for audio amplification in and out, and for level shifting between the beagleboard’s output and the motors’ input.

At the same time, we worked with Thomas to build a first tracking system demo, by placing the webcam on top of casper’s body, connecting it to the beagleboard and then connecting the serial link to drive the motors. This demo gave some first results tonight, and will be kept under improvement.

Finally, we managed to create a custom language model and dictionary, which combined with the pocketsphinx engine’s data now allow the beagleboard to understand french vocal commands.

[Casper] Flash, Screen and Pictures…

We’ve been working these last few days on the PCB, to display pictures and to save and load them from flash.

First, we developped a set of functions to erase, write and read the flash memory, using a SPI protocol. After testing it with text strings we displayed on the screen, we tried with pictures. However, the STM32 RAM is not big enough to handle a whole picture : we have at most 20kbytes RAM, and one picture takes 25kbytes (132*132 pixels of 12 bits, 4 for each RGB channel). So we read the flash per 256 bytes blocks that we send to the LCD screen, until transfer completion. Similarly, we write flash per 256 bytes blocks when receiving a picture from the UART connection.

In order to have a simple protocol for writing pictures, we do not allow two pictures to share a same memory sector (smallest erasable area). Since each sector is 4 kbytes wide, we use 7 sectors for each picture : that’s about 3 kbytes too large. However, this allows to store 146 pictures in the flash, which should be enough for our project. We did not work yet on the possibility of storing smaller pictures which could be used to refresh a small screen area. It may be useful for animations.

Finally, we use the screen configuration options to rotate pictures by 90, 180 or 270 degrees, changing the way the screen controller reads the RAM.

Moreover, we wrote a small program which uses OpenCV library (which is already used on the beagleboard for face detection and recognition) and converts a picture (jpeg, png, bmp,…) in a 132*132 12 bits picture and saves it in a file that can be sent to the PCB by UART.

[CASPER] Demo de vendredi et API RS232

Voici dans ce post un bilan de la démonstration de Vendredi, ainsi qu’un bref état des lieux des avancées d’aujourd’hui concernant la programmation série en C sous linux.

 

Démonstration de vendredi

Nous avons Vendredi fait état de nos dernières avancées.

Nous avons débuté la démonstration par la présentation du PCB que nous avions réalisé et qu’Alexis nous avait remis il y a peu. Alain a, comme il l’a montré dans un post précédent, réussi à piloter l’écran LCD et afficher une animation simple comportant des rectangles de couleur et du texte.
Reste maintenant à réaliser l’interface série entre la carte et un ordinateur, puis programmer la mémoire flash embarquée.

Nous avons poursuivi par la démonstration de Thomas qui a piloté par l’intermédiaire de la carte de TP STM32 l’un des servomoteurs que nous allons utiliser. Grâce à son programme, nous sommes capables de piloter ces moteurs en leur fournissant une consigne angulaire.
Reste désormais à piloter le prototype en installant trois servomoteurs dans sa base.

Nous avons ensuite effectué une démonstration logicielle qui rassemblait les « helloworlds » que nous avions réalisés avec les différentes bibliothèques. Nous avons ainsi pu piloter à la voix l’ordinateur, lui demander de faire l’apprentissage de deux visages, puis de passer en mode reconnaissance. Une fois en mode reconnaissance, le moteur de synthèse vocale interfacé pour le moment avec pulseaudio a salué les visages connus en les nommant par leurs prénoms.

 

Comme Thomas l’a signalé dans son billet, nous avons pour le moment mis de côté le développement de drivers, pour nous concentrer essentiellement sur la mécanique, la programmation du PCB, et le port de nos applications sur la beagleboard.

Afin de préciser notre démarche, nous publierons bientôt sur ce site une liste actualisée de nos PSCC et des responsables associés.

 

Avancées de la journée : API RS232

De mon côté, je me suis penché sur la programmation du port série en C sous linux. J’ai trouvé à ce sujet une excellente source de documentation, qui m’a permis de comprendre rapidement l’interface posix permettant d’en effectuer la configuration. Vous retrouverez ce guide ici.

J’ai créé une interface de plus haut niveau permettant de lire et d’écrire sur un nombre indéfini de ports série, et de rentre transparente la gestion des lectures et écritures avec tampon.

Il suffit en effet pour utiliser un port série d’en demander l’ouverture en précisant le fichier /dev/tty* associé, et de donner en argument la fonction que l’on souhaite être appelée pour traiter les données.

L’API se charge ensuite d’appeler cette fonction lorsque de nouvelles données sont disponibles, ainsi que d’écrire les données stockées dans des tampons chainés lorsque le matériel est prêt.

L’utilisateur peut donc utiliser des fonctions non bloquantes pour écrire, et utiliser ses propres fonctions pour lire.

Pour finir, bien que cela ne soit pas encore implémenté, il est possible d’ajouter à cette API les sockets en plus des ports série. Cela permettrait de gérer par le biais d’une interface unique toutes les transmissions de la beagleboard, que ce soit par réseau ou avec le PCB.

Copterix : état des choses pour ce vendredi soir

I2C, et PCB en général

Samuel et moi-même avons pu finalement communiquer avec les gyroscopes de notre PCB, non sans mal (cf le post d’hier soir). Nous avons donc été en mesure de montrer un exemple de récupération des données des gyroscopes, accéléromètres et magnétomètres en temps réel lors des démonstrations de cet après-midi. Le programme de ce weekend de ce côté-là serait donc de discuter à présent avec les moteurs.

Communication avec le PCB

Loïc a fait une petite démonstration de sa gestion des erreurs lors des transmissions de paquets entre le PCB et un PC. Certains points restent à éclaircir, comme notamment le compte des erreurs et la gestion des coupures.

Tracking

La démonstration du tracking ne s’est pas vraiment bien passée : effectivement, nous n’avons pas défini de protocole de test rigoureux, ce qui fait que nous avons une très mauvaise estimation des capacités réelles de notre tracking à l’heure actuelle. De plus, à cause de fuites de mémoires dans openCV non encore résolues, le programme tourne pendant 3 minutes avant de devoir s’arrêter faute de RAM. Un gros effort reste donc à fournir de ce côté-ci, mais cette fonctionnalité n’étant pas vitale pour faire voler l’hélicoptère, elle n’est pas en haut de la liste des priorités.

Kalman

Notre implémentation du filtre du Kalman en test avec les données d’une IMU gentiment fournie par Samuel Tardieu n’a pas fait une grande impression sur le jury, le fait qu’il était facile de l’affoler en secouant un tout petit peu la carte ne devant pas y être étranger. Une explication possible mise en avant par Alexis serait que nous avons mal pris en compte l’orientation des gyroscopes : je vais donc m’y pencher dès que possible pour essayer de résoudre ce problème, qui lui est vital pour la bonne marche du projet.

[Casper] OpenCV et Beagleboard

Aujourd’hui j’ai porté les algorithmes de détection et reconnaissance faciale sur Beagleboard, sans trop de soucis. Comme nous n’avons pas encore reçu la webcam, je me suis contenté de les tester sur des images jpeg. Les temps de traitement sont deux fois plus longs sur Beagleboard que sur mon PC, et nous allons donc certainement jouer sur la taille des images pour avoir un temps de traitement convenable.

Je me suis également penché sur le projet d’optimisation d’OpenCV utilisant le DSP de la beagleboard, mais un benchmark disponible sur le site du projet montre que le gain en performances est plus que relatif. Le seul intérêt pourrait être de décharger le processeur de certains traitements. Nous reviendrons donc vers ce projet uniquement si le besoin s’en fait réellement sentir…

Nous avons de plus reçu notre carte aujourd’hui et nous commençons donc sa prise en main.

[CASPER] Beagleboard, pilotes et pwm

Voici un petit compte rendu de ce que Thomas et moi-même avons réalisé hier et aujourd’hui.

 

Bootstrap

Partant de ce que Thomas avait réalisé précédemment, nous avons automatisé l’installation de la carte SD pour la beagleboard. En effet, celle-ci doit contenir dans une première partition FAT les fichiers du noyau nécessaires au démarrage, et sur une deuxième partition du format de notre choix la racine du système de fichiers.

Afin de pouvoir choisir plus finement quel noyau et quel paquets nous souhaitons installer sur notre beagleboard, et pour pouvoir la placer rapidement dans une configuration « prête à utiliser » lors d’une éventuelle réinitialisation, nous avons choisi de ne pas utiliser les images de rootfs proposées sur internet par la communauté de développeurs beagleboard.

Nous avons donc construit notre propre image rootfs à l’aide de l’outil debootstrap couplé à l’émulateur qemu, ce qui permet de créer sur un ordinateur portable classique une distribution pour une architecture arm, par exemple. Nous avons inclus de nombreux paquets tels que la bibliothèque opencv qui nous sert pour le traitement de l’image, et SVOX pico, qui nous sert pour la synthèse vocale.

Nous avons ensuite configuré la distribution afin d’obtenir une console sur le port série et paramétré la distribution afin de la rendre directement utilisable.

Ces étapes ont été totalement automatisées dans un script, ce qui nous permettrait éventuellement de regénérer tout ceci très rapidement, tout en faisant évoluer nos paramètres.

Nous avons ensuite généré les fichiers de boot à partir du noyau de sorte qu’il supporte le système de fichiers nilfs2¹ (Le garbage collector du nilfs2 sera lancé automatiquement, dès lors que les paquets nilfs-tools et nilfs2-tools sont installés sur le système. Il faut donc les ajouter dans le script debootstrap_init.sh).

 

Le système de fichiers nilfs2 offre en résumé deux avantages : sa structure garantit l’intégrité des fichiers écrits ce qui évite la corruption de la carte en cas de coupure de courant ou de plantage et il offre d’excellentes performances sur la carte SD en comparaison avec l’ext2 par exemple.

Cela est certainement dû à sa structure circulaire, et à son mode de fonctionnement avec garbage collector. En effet, les fichiers supprimés ne sont pas effacés immédiatement, ce qui aurait pour effet de ralentir les opérations. Ces effacements ne sont réalisés que beaucoup plus tard, à la fin d’un compte à rebours ou lorsque les segments propres sont en nombre insuffisant. Ainsi, l’écriture est rapide puisque sans effacement, et l’effacement est retardé ce qui à nouveau permet de gagner beaucoup en vitesse de fonctionnement. (L’installation de paquets logiciels est aussi rapide que sur un ordinateur moderne avec nilfs2, ce qui était loin d’être le cas avec ext2 puisqu’en fonction des dépendances, il fallait entre 15 et 60 min)

 

Ensuite, un autre script que nous avons réalisé automatise la génération d’une archive tarball rootfs.

Une version adaptée du script setup_sdcard.sh (http://github.com/RobertCNelson/omap-image-builder/blob/master/tools/setup_sdcard.sh) nous permet ensuite, là encore de manière automatisée, de formater la carte mémoire et de créer les partitions, de générer les fichiers uImage et uBoot, et enfin de copier les fichiers de boot et d’extraire le tarball rootfs sur les partitions correspondantes.

Nous avons de plus écrit une notice détaillant l’utilisation de ces scripts en vue de générer rapidement une installation pleinement fonctionnelle et incluant tous les paquets logiciels nécessaires sur la carte SD.

 

¹ Merci PHH pour les conseils !

 

 

Pilotes et PWM

Thomas continue de se pencher sur la question des pilotes. Il a réalisé un helloworld que nous ne pouvions malheureusement tester sur la beagleboard, du fait que celle-ci était immobilisée par les opérations de préparation de la carte SD. Maintenant que celle-ci est prête, nous allons pouvoir tester la compilation et l’installation dynamique de ce module de communication helloworld dans le noyau.

Étant donné que la beagleboard n’était pas prête, et outre sa participation à la création de la nouvelle distribution au travers de son expérience précédente avec la première installation que nous avions réalisée avec le script setup_sdcard.sh, Thomas a continué de se documenter sur la réalisation de pilotes et sur l’utilisation des modules PWM sur la beagleboard.

[CASPER] Reconnaissance faciale

Nous avons implémenté la détection et la reconnaissance de visages à l’aide de la bibliothèque OpenCV. Celle-ci utilise l’algorithme de Viola-Jones pour la détection et l’algorithme des eigenfaces dont nous avons déjà parlé dans ce billet pour la reconnaissance.

Nous allons donc ici expliquer uniquement l’algorithme de Viola-Jones.

Algorithme de Viola-Jones

Cet algorithme est un algorithme de boosting, c’est-à-dire qu’il classifie une zone de l’image comme visage ou non-visage à partir de plusieurs classifieurs faibles (c’est-à-dire ayant un taux de bonne classification légèrement meilleur qu’un classifieur aléatoire). Ces classifieurs faibles, inspirés des ondelettes de Haar, consistent à sommer des pixels sur certaines zones (rectangulaires) de l’image et à les soustraire sur d’autres (on trouve ainsi par exemple un classifieur faible dont le but est de détecter des yeux en sommant sur les yeux et en soustrayant entre). Afin de réduire le coût computationnel de ces sommations, Viola & Jones ont introduit les « images intégrales » : celles-ci consistent à recueillir dans chaque pixel la somme des pixels du rectangle qu’il délimite avec le pixel origine. Les classifieurs faibles sont ensuite agrégés à l’aide de l’algorithme AdaBoost.

Afin d’accélérer le traitement, l’algorithme de Viola-Jones utilise plusieurs classifieurs « forts » en cascade, et les agrège par unanimité : dès qu’un classifieur classifie une zone de l’image comme non-visage, le traitement de cette zone s’arrête et celle-ci est classifiée comme non-visage.

Un des problèmes que soulève cette méthode est que les classifieurs faibles (et donc les classifieurs forts) sont définis pour une taille de visage donnée. Or en pratique les visages susceptibles d’apparaître sur une image ont une taille quelconque. Le traitement est donc réalisé de manière pyramidale.

Un deuxième problème est l’agrégation des résultats. En effet, en faisant glisser une fenêtre de détection sur l’image, le même visage est susceptible d’être détecté plusieurs fois, pour des décalages de quelques pixels de la fenêtre. Afin de palier ce problème, l’algorithme regroupe les fenêtres se chevauchant de plus d’une certaine proportion, et en retourne une fenêtre « moyenne ».

Une des principales limitations de cet algorithme est qu’il n’est pas invariant pas rotation, ce qui impliquera de faire un prétraitement pour redresser l’image de la caméra selon la position de notre robot avant de lancer l’algorithme.

Viola-Jones et OpenCV

Plusieurs bases de classifieurs sont fournies par défaut avec OpenCV, notamment pour détecter des visages de face ou de profil. Deux bases détectent les visages de face, les bases « haarcascade_frontalface_default.xml » et « haarcascade_frontalface_alt.xml ». Nous utilisons la deuxième, car la détection est plus rapide (de l’ordre de 50%).

Nous utilisons plusieurs paramétrages fournis par OpenCV, notamment le fait de s’arrêter dès qu’un visage a été détecté, et de commencer par rechercher les visages les plus grands.

Ceci permet d’avoir des temps de détection acceptables (de l’ordre de 50ms sur un PC portable vieux de deux ans à base d’Athlon X2) quand un visage est présent dans l’image, mais beaucoup plus longs si aucun visage n’est présent (de l’ordre de la seconde). Nous pouvons donc envisager d’arrêter la recherche dès que celle-ci dépasse la centaine de millisecondes. Nous attendons cependant le portage sur beagleboard pour évaluer les temps de calcul en conditions réelles. Il existe de plus un projet d’optimisation d’OpenCV utilisant le DSP présent dans l’OMAP de la beagleboard, qu’il sera intéressant de tester.

Algorithme complet

L’algorithme complet de détection et reconnaissance donne des résultats intéressants sur PC portable, la prochaine étape étant de les tester sur beagleboard. Nous rencontrons de même un problème de latence sur OpenCV : l’algorithme se comporte en effet comme s’il existait un buffer de quatre images qui introduit un retard sur les images traitées, le problème étant d’autant plus perceptible en cas d’absence de visage lorsque le traitement de chaque image prend une seconde… Nous n’avons cependant pas encore mené de recherches approfondies sur ce problème.

[CASPER] Premiers contacts avec PocketSphinx et OpenCV

Aujourd’hui nous avons poursuivi l’exploration des bibliothèques de traitement vidéo et audio.

Partie Audio : La bibliothèque que nous utilisons s’appelle PocketSphinx. Nous sommes aujourd’hui capable de reconnaître des mots ou des phrases en anglais et de les associer à des commandes (appui sur une touche clavier ou ouverture d’un fichier par exemple). La prochaine étape est de faire fonctionner un synthétiseur vocal.

Partie Vidéo : La bibliothèque que nous utilisons s’appelle OpenCV. Nous avons écrit un programme qui récupère un flux vidéo de la webcam et détecte dans chaque frame la présence d’un visage ou non. Si il en trouve un, il l’encadre. On peut observer la détection dans une fenêtre qui affiche les frames au fur et à mesure de leur traitement. La prochaine étape est d’implémenter l’apprentissage et la reconnaissance de visages.

Enfin, nous avons préparé la soutenance intermédiaire de demain.

Copterix : vision et autres avancements

OS:

On a laissé tomber angström pour ubuntu et on l’a installé sur la carte.

Tracking:

La caméra a la mauvaise habitude de rendre des images en « fish eye », j’ai donc utilisé OpenCV pour arranger tout ça, et voici les résultats:

À gauche, l’image telle qu’elle est reçue par la caméra et à droite après application d’OpenCV.

On a aussi compilé mon code qui renvoie le vecteur déplacement détecté sur la Gumstix et on l’a testé, mais on tourne à une image par seconde…
Après test via Cheese, il s’avère que la résolution de la caméra est trop élevée, ce qui explique son si faible débit, je m’apprête donc à y remédier.

Physique:

On a continué à réfléchir, on a vu Wahba et Kalman. Samuel veut coder le FQA, qui résout le problème de Wahba. On aura un post sur la physique demain plus complet.