Dans certains cas, l’ajout d’un système de vision à un robot s’avère un élément essentiel à son contrôle. Cependant, l’implantation des techniques d’analyse de l’image peut exiger une programmation complexe ou l’usage de technologies spécialisées. L’article qui suit traite du développement d’un programme de traitement vidéo sous Linux - ou plus précisément de l’étape de capture de l’image - un choix qui, vous l’aurez deviné, allie performance, stabilité et facilité de mise en oeuvre.
Voir en ligne : Programme de test effectué selon les explications de cet article
Sommaire
Avant toute chose, assurez-vous d’avoir à la fois Video For Linux installé sur votre système ainsi que le pilote en charge de votre camera web utilisée pour ce programme. S’il vous faut faire un choix concernant l’achat de matériel, vous pouvez opter simplement pour la Quickcam Express de Logitech, peu coûteuse et bien supportée par le SE. À ce sujet, consultez l’article de ce site « Installation de la Quickcam Express sous Linux » pour obtenir des informations sur son installation. Pour ce qui est de V4L (Video For Linux), il serait fort étonnant que votre distribution ne l’intègre pas dans son noyau. Si toutefois tout semble indiquer que ce support est absent de votre système, la dernière version est disponible à l’adresse http://linux.bytesex.org/v4l2/
Ouverture de la caméra
Considérant que la caméra que nous souhaitons utiliser se situe en /dev/videoX, son ouverture se fera par un appel à la fonction open(const char *chemin, int flags) avec ce chemin en paramètre ainsi qu’un drapeau indiquant le mode d’accès.
|
Si l’opération est réussie, la fonction open retournera le descripteur du fichier ouvert. Dans le cas contraire, un message d’erreur s’affichera. Les causes peuvent être multiples, mais la plupart du temps, le problème proviendra des permissions accordées à sur ce dispositif.
Fermeture de la caméra
Intuitivement, la fermeture de la caméra se fera par une fonction close, prenant en paramètre le descripteur de fichier obtenu par la fonction open.
|
Requête sur le dispositif
De manière à rendre l’application plus flexible devant le matériel utilisé, nous allons d’abord nous informer de ses possibilités. Cette opération se fera en effectuant un appel de type ioctl VIDIOCGCAP qui retournera le résultat dans une structure video_capability.
|
Les informations que contiendra la structure vidcap sont les suivantes :
| struct video_capability | ||
|---|---|---|
| Nom | Description | Commentaires |
| name[32] | Nom[32] | |
| type | Type | Supporte la capture vidéo ou non |
| channels | Le nombre de canals | Si applicable (télévision, radio) |
| audios | Audio | Son disponible |
| maxheight | Hauteur maximale (pixels) | |
| maxwidth | Largeur maximale (pixels) | |
| minheight | Hauteur minimale (pixels) | |
| minwidth | Largeur minimale (pixels) |
Pour nous assurer d’avoir accès à un dispositif supportant la saisie d’images, nous allons utiliser un drapeau spécialement défini dans video for linux pour le comparer au champs type.
|
D’autres conditions pourraient être testées pour s’assurer du bon fonctionnement du programme. Pour ce faire, V4L offre beaucoup d’autres drapeaux (flags) qu’on a d’ailleurs documentés adéquatement. [1]
Paramètres de l’image
La zone de capture doit également être contenue dans une structure, cette fois, de type video_window. VIDIOCSWIN servira à fixer la valeur de ses champs. Nous nous intéresserons seulement qu’à ceux-là :
| struct video_window | |
|---|---|
| Champs | Commentaire |
| x | Position en X |
| y | Position en Y |
| width | Largeur de l’image |
| height | Hauteur de l’image |
|
Si VIDIOCSWIN a pu s’exécuter, cela ne signifie pas pour autant que les valeurs passées ont été supportées. N’oubliez pas de vérifier le résultat de l’opération ! Pour connaître la valeur des paramètres qui y ont été définis, nous appelleront VIDIOCGWIN par ioctl de nouveau.
|
Aspect de l’image
Tout comme la fonction VIDIOCSWIN permet de régler certains paramètres de l’image, VIDIOCSPICT déterminera l’ajustement et son aspect : contraste, couleur, profondeur etc. Voyons l’organisation de la structure correspondante :
| struct video_picture | |
|---|---|
| Champs | Commentaire |
| brightness | Intensité |
| hue | |
| color | |
| contrast | |
| whiteness | Réglage des blancs |
| depth | Profondeur |
| palette | Mode de représentation des couleurs |
Le code qui permettra de modifier ces valeurs sera court :
|
Comme expliqué plus-haut, nous nous assurerons d’avoir pu imposer ces valeurs avec la fonction VIDIOCGPICT :
|
Par la suite, l’affichage des valeurs chargées peut se faire simplement ainsi :
|
Capture en tampon double
Nous voilà finalement rendu à l’étape quasi finale du processus : l’obtention de l’image depuis le pilote de la caméra. Comme le temps d’occupation du processeur est une denrée préciseuse en informatique, nous tacherons ici à optimiser les opérations en implantant un système d’espace mémoire à tampon double de manière à éviter de perdre des images. Notez aussi que les données ne transiteront pas ici directement depuis le framebuffer de la carte vidéo mais passeront plutôt par un espace tampon.
L’idée du principe de capture à tampons multiples est de fournir en tout temps au pilote du périphérique un espace mémoire pour déposer son image. Cela se fait donc d’abord en exécutant une série de requêtes VIDIOCMCAPTURE qui seront mises en file par le pilote. Un appel VIDIOCSYNC permettra ensuite d’attendre jusqu’à la libération de l’image. La séquence des requêtes, placée dans un boucle infinie, devrait être la suivante :
|
L’image peut ensuite être retrouvée en mémoire en effectuant la somme du pointeur sur la MMAP plus l’élément offsets de la sturcture video_mbuf.
Ex :
|
Saisie des images et copie dans un "buffer"
La fonction présentée ci-dessous tire partie d’un système à base de pointeurs de fonction. En effet, un pointeur sur une fonction capable d’effectuer le traitement de l’image sera passé en argument. Ce pointeur pourra ensuite être utilisé pour appeller la fonction appropriée lors du passage de l’image au programme.
Puisque nous utilisons l’interface MMAP, nous devrons d’abord obtenir des informations sur la taille du buffer en MMAP et la position des images dans cet espace.
|
Nous obtiendrons effectivement cet espace en MMAP par la suite de cette manière :
|
Nous voyons donc ici, plus-haut, que l’élément size de la structure mbuf informée plus tôt par l’appel VIDIOCGMBUF est utilisé pour déterminer l’espace nécessaire pour un tampon accessible en lecture et en écriture sur notre périphérique, déterminé par descrpFichier.
Vient maitenant une étape nécessaire avant d’effectuer nos appels aux fonctions de capture de V4L : nous devons renseigner une structure de type video_mmap dans ses champs height, width, et format. Cette étape est sans commentaires spéciaux, à l’exception du conseil suivant : il est profitable pour une question d’efficacité d’utiliser des macros (defines) pour donner la valeur à certains paramètres tels que la taille de l’image, le format etc. Ainsi, les mots en majuscules dans le bout de code suivant sont définis dans le fichier d’entête par les valeurs souhaitées.
|
Comme expliqué dans la section « capture en tampon double », nous effecturons une série d’appels VIDIOCMCAPTURE selon le nombre de buffers supportés par le pilote. Ceux-ci seront placés en file avant d’être synchronisés par la fonction VIDIOCSYNC.
|
La variable image, aura été déclarée plus-haut pour indiquer le nombre d’images pouvant être capturés par le pilote : c’est l’indicateur du nombre de buffers. La valeur de cette varible est ensuite changée à 0 car nous la réutiliserons comme argument à la fonction VIDIOCSYNC. Dans une boucle, nous mettons en application le principe expliqué dans le paragraphe précédent :
|
Nous effectuons d’abord dans un premier passage la synchronisation de l’image 0 avec VIDIOCSYNC placé dans une boucle conditionelle qui vérifie que la fonction soit bel et bien parvenue à effectuer sa tâche sans avoir été interrompue par un signal ou un problème quelconque. Nous pouvons alors ensuite recueillir notre première image par le simple calcul suivant :
|
Suite à cette opération, le pointeur de fonction utilisé en paramètre de la fonction de capture peut être utilisé de la sorte :
|
Nous pouvons maintenant remettre le buffer courant à la disposition du driver en utilisant de nouveau VIDIOCMCAPTURE.
|
Le champs frame de la structure mapbuf de type video_mmap est défini à la l’indicateur de l’image venant d’être utilisée. Finalement, la dernière ligne s’assure de remettre la valeur de image à 0 si l’on a dépassé le nombre d’images en attente supporté.
Lecture des données de l'image RGB et écriture d'un fichier PPM
Une image saisie en format RGB24 peut être facilement interprétée : un pixel étant décrit par un triplet de valeurs dans l’ordre BGR. Le pointeur de notre image, appelons-le posImg, pointe donc sur la valeur B du premier pixel. Pour effectuer cette opération sur la totalité de l’image, deux boucle for seront utilisées : une première lisant tous les pixels de 1 à n pour une ligne et une seconde boucle passant d’une ligne à l’autre.
|
Ce code montre l’ouverture d’un fichier de type PPM [2] et de la scrutation de l’image en mémoire par une double boucle copiant les valeurs RGB dans l’ordre inverse dans les variables correspondantes de type unsigned char. Portez attention ici au prototype de cette fonction qui respecte la déclaration du pointeur de fonctions dans l’étape de capture de l’image.
Qu'est-ce qu'est la MMAP ?
MMAP signifie "memory map" en langue anglaise. Cette fonction sert à représenter de manière localisée (ou "projetter") un fichier dans une zone mémoire selon une indication de longueur de l’espace requis et de positionnement par rapport au descripteur d’un fichier. Vous remarquerez donc ici qu’en la définition de "fichier" sous système UNIX, nous entendons également "périphérique". La MMAP est donc un moyen de recuillir les données d’un certains flux dans une zone mémoire de manière organisée.
Documents joints
-
camera.c (C source - 5.5 ko)Librairie de fonctions utilisées dans cet article. Pierre-Luc Bacon, 2005. GNU/GPL
-
Fichier d’entête (C header - 1.7 ko)Fichier d’entête de camera.c
Notes
[1] Voir Video4Linux Kernel API Reference. Une version du document est accessible sur ce site : www.aqra.ca/pierre-luc/camapp/API.html
[2] Pour plus de renseignements sur la manipulation d’images en format PPM, référez-vous à l’article 35 sur ce site intitulé "Conversion d’images couleur en niveaux de gris". http://www.aqra.ca/article.php3 ?id_article=35




Répondre à l'auteur: