Projet image 2012 : Détection du Touché sur une surface Multi-Touch 3D

De Ensiwiki
Aller à : navigation, rechercher

Mycomputer.png  Deuxième Année  CDROM.png  Informatique  Mathematiques.png  Mathématiques 


Project schedule.png
Titre du projet Détection du Touché sur une surface Multi-Touch 3D
Cadre Projets de spécialité
Page principale Projet de spécialité

Encadrants François Berard


L'équipe

Projet de Spécialité 2012 Détection du Touché sur une surface Multi-Touch 3D
Equipe Kévin Boury (ISI), Téo Mazars (MMIS-IRVM), Kévin Polisano (MMIS-IRVM), Victor Sabatier (MMIS-IRVM)
Encadrant François Berard
École Grenoble INP - Ensimag
Date Juin 2012

Contexte

Introduction

Vous l'aurez surement remarqué, dans le monde des nouvelles technologies, la mode est au tactile ! Iphone et autres téléphones portables, ordinateurs tactiles, tables tactiles en développement dans les entreprises, écrans tactiles dans les musées, gares, aéroports, banques, etc. Par ailleurs les progrès réalisés en hardware sur la puissance des ordinateurs ont favorisé l'émergence de la 3D (dans les jeux, le cinéma, la réalité virtuelle augmentée, etc). Pouvoir manipuler des objets virtuels en 3D avec les mains de manière interactive est donc devenue indispensable. Cependant les surfaces tactiles 2D que l'on trouve actuellement sur le marché se prêtent assez mal à cet exercice. C'est pourquoi d'autres types de surfaces, possédant une dimension supplémentaire ont récemment vue le jour et permettent à l'utilisateur de manipuler plus naturellement des objets en 3D.

Le cubtile

Le cubtile (cliquez sur l'image pour voir la vidéo)
Les 5 faces vues du dessous par la caméra

Le cubtile, un dispositif développé par la société Immersion, s'inscrit dans cette lignée, et pourrait être une solution.

Principe de fonctionnement :

Il s'agit d'un cube dont cinq de ses faces sont "sensibles" au touché. Une caméra infrarouge est équipée d'une lentille de type "Fish-Eye" permettant d'observer les cinq faces du Cubtile depuis l'intérieur du dispositif. L'image ci-dessous illustre un exemple d'image capturée par la caméra. Sur cette image, on voit que trois doigts sont entrés en contact avec les faces supérieure, frontale et arrière du cube : ce sont les halos blancs.

Le logiciel du Cubtile se charge de traiter le flux vidéo en provenance de la caméra. Le traitement consiste à détecter les halos clairs correspondant aux contacts des doigts sur les surface, puis à transformer les coordonnées de ces halos afin de corriger la déformation due à la lentille. La détection des halos consiste à appliquer un seuil sur la luminosité de l'image et à calculer le barycentre des pixels connexes qui passent le seuil.

Identification du problème

L'approche adoptée par la société Immersion est cependant imprécise et source d'instabilité, et d'autre part présente des problèmes de latence.

Objectifs du projet :

  • Reproduire de A à Z un logiciel similaire à celui développé par Immersion.
  • Améliorer la précision et la stabilité de la détection de la position des doigts en contact avec les surfaces.
  • Diminuer la latence introduite par le traitement vidéo (descendre sous la barre des 50 ms de réaction).
  • Mettre en place une interface homme machine et une base de tests permettant de rendre compte qualitativement et quantitativement de la qualité de notre produit.

Chaine de traitement

En entrée, nous disposons des frames provenant de la caméra. Nous voulons en sortie générer des événements correspondant aux actions effectuées par les doigts sur la surface du cubtile. Nous avons segmenter le problème en plusieurs étapes que nous décrivons dans la chaîne de traitement ci-dessous. Les sections suivantes présentent en détails chacune de ces étapes en justifiant les choix d'algorithmes et d'implémentations.

Chaine de compilation à traiter pour la génération d’événements

Traitement du flux vidéo

Transformation

Principe de la transformation
Mapping non-uniforme
  • En entrée : l'image des 5 faces déformée par la lentille.
  • En sortie : les 5 faces redressées en de "vrais" carrés et stockées indépendamment.

Nous avons pu implémenter le redressement perspectif (2 ème étape), mais n'ayant pas accès aux paramètres intrinsèques de la caméra, il nous était impossible de déterminer mathématiquement la transformation optique inverse du fisheye (1 ère étape). C'est pourquoi nous avons du changer de stratégie en transformant directement l'image par mapping puis texturing.

L'idée consiste donc à prélever n^2 points sur la surface déformée (voir image de droite), qui correspondent à une grille carrée à n\times n noeuds, que l'on texture ensuite via OpenGL pour remplir par interpolation le carré complet. La répartition des points doit être faite intelligemment. C'est-à-dire qu'il faut placer plus de points là où plus d'information est nécessaire (typiquement en haut de la surface). Ainsi, à cet endroit, les points doivent être plus resserrés.

  • Comment effectuer ce mapping ?
Génération des points du mapping

On approche les deux bords courbés extérieurs par des arcs de cercles (en rouge sur le graphique) et les deux bords droits par des droites (en noir) qui délimitent la surface à "mapper". Puis on fait varier un arc de cercle intermédiaire (en bleu) entre les arcs de cercle rouge, et une droite verte entre les deux droites bleues. Les points du mapping résultent de l'intersection entre le cercle bleu et la droite verte.

Tout le problème réside dans le fait de savoir comment faire varier l'arc de cercle bleu (de façon à avoir davantage d'intersections en haut). Pour répondre à cette problématique, nous avons effectué des mesures empiriques.


En découpant une feuille en "créneaux" réguliers de même taille que l'on a ensuite placé sur le cubtile, on visualise l'effet de la déformation et on peut mesurer la taille des créneaux sur l'image déformée (image n°1 de la galerie ci-dessus). Puis en reportant ces données dans Maple nous avons pu les approximer par un polynôme quadratique (image n°2). En utilisant cette fonction pour répartir des points sur un segment, on s'aperçoit (image n°3) que la répartition n'est pas uniforme mais plus resserrée en bas et plus espacée en haut (projection sur les ordonnées), ce que l'on désirait.

Nous avons utiliser cette répartition pour discrétiser les 3 axes principaux de la surface déformée (image n°1 de la galerie ci-dessous). Puis pour chaque triplet de points (un pris sur chaque axe) on fait passer un cercle (image n°1 et 2). Et si on zoom (image n°3) on voit comme des lignes de niveau sur la surface déformée, qui une fois intersectées par la droite variante (verte) donne lieu aux points du mapping.

  • Implémentation utilisant le processeur graphique

Pour minimiser les temps de calculs et donc la latence, nous utilisons la puissance du GPU via OpenGL. Les frames de la vidéo sont transférées dans la mémoire de la carte graphique pour être traitées comme des textures. Ces textures sont "mappées" selon les calculs précédents sur une surface plane. Le texture mapping exploitant directement les fonctionnalités de base d'OpenGL, le rendu est quasiment immédiat.

Le seul coût notable de cette solution est le transfert des données vers la carte graphique ainsi que le transfert inverse.


Pour accélérer encore la transformation, notre implémentation utilise deux Vertex Buffer Object. Cette possibilité permet de stocker les coordonnées de mapping directement sur la carte graphique. Ainsi, les deux VBO sont remplis une bonne fois pour toute à l'initialisation, c'est à dire en début d'exécution du programme, l'un avec les coordonnées du mapping, l'autre avec un quadrillage régulier. Ainsi, à chaque itération, l'appel à glDrawArray() demande à la carte graphique de parcourir directement les deux tableaux contenu dans ça mémoire, sans intervention du CPU.

transformation via GPU


Le schéma ci-contre décrit notre implémentation :


0) Initialisation des Vertex Buffer Object :

Puis à chaque itération :

1) Acquisition de la frame en mémoire RAM

2) Transfert de la frame en mémoire GPU via glTexture2D()

3) Mapping de la texture par glDrawArray()

4) Transfert du rendu en RAM via glReadPixel()

5) Le traitement continu avec le CPU ...




Sélection des candidats

Une fois l'image transformée, il faut être capable de détecter les doigts présents sur les différentes faces.

Comme dans tout signal, il existe du bruit, qui peut être de plusieurs types :

  • bruit lié au matériel : la caméra peut être bruitée. Une solution est d'appliquer un filtre gaussien à l'image pour le diminuer.
  • bruit lié à l'homme : si jamais la main est en contact ou se rapproche d'une des faces du cubtile, celle-ci peut être détectée comme un doigt.

Pour mieux comprendre ce qu'il peut se passer, partons de l'image suivante.

Niveau de gris de l'image brut avec un doigt posé sur une face

On voit de manière très claire le doigt, mais on voit aussi qu'autour du doigt le niveau de gris n'est pas uniforme. Un des moyens les plus naturels pour trouver la position de ce doigt est de procéder à un seuillage avec un seuil bien choisi. Ce seuil est adaptatif selon la face où on est.

  • Dans un premier temps lors de la phase de calibrage, le maximum de niveau de gris de chaque face ( précédemment filtrée avec un filtre gaussien ) est calculé.

Pour la face du centre, le seuil est fixé est max+50;

  • Pour les faces de côté, il s'agit d'un seuil adaptatif en fonction de la hauteur du point. En effet le niveau de gris de l'image est dépendant de la quantité de lumière reçue par la caméra et donc directement de l'angle.

Nous avons donc fixé un niveau de seuil pour que la détection fonctionne en bas de la face et un autre niveau de seuil, puis nous avons interpolé linéairement entre ces deux points.


Il se peut néanmoins que nous arrivions à la situation suivante :


Image après seuillage


On reconnait très bien le doigt ( en haut à droite de l'image ) mais d'autres formes ont été détectées.


Pour éliminer ces formes, nous avons mis en place deux mécanismes :

  • associer à un doigt un rayon minimal et un rayon maximal ( calculés empiriquement ) pour pouvoir éviter les trop gros halos.


Image après élimination des composantes connexes trop grandes


  • Après cette étape, il restera néanmoins une autre tâche dont le rayon vérifie bien la contrainte précédente.

Un moyen de l'éliminer est de faire la constatation suivante : la tâche du doigt (cf. image) est très marquée et présente une variation d'intensité très faible, on peut donc procéder à un seuillage du gradient. On obtient alors en sortie l'image seuillée avec uniquement le bon doigt.


Image après élimination des composantes connexes dont le gradient est trop faible


Pour récapituler le traitement :


Récapitulatif de la chaine


Extraction

Après avoir procéder à cette première étape de sélection des bons candidats, il nous faut déterminer à une précision subpixel (c'est-à-dire connaître la position du doigt en des coordonnées flottantes), où se situe le doigt avec une contrainte de stabilité


Remarque importante : l'objectif de cette partie n'est pas d'avoir une parfaite correspondance entre la position du doigt sur le cubtile et la position du doigt sur l'image générée (l'utilisateur ne verrait pas de changement si il y avait une différence de quelques pixels) par contre il est sensible au fait que si son doigt ne bouge pas alors l'objet manipulé ne doigt pas bouger.


On veut donc pour deux tâches identiques, pouvoir affirmer avec une probabilité de plus de 95% que le doigt se situe dans un tel rayon. Pour valider ceci, nous avons supposé que la distribution des différents centres d'une même tâche est gaussienne et donc que nous avons en notant  \sigma l'écart type de notre distribution que 95% des valeurs de trouve dans l'intervalle  [m-2\sigma,m+2\sigma] !!

Nous sommes donc en mesure d'extraire les composantes connexes représentant les différents doigts de l'image. Nous choisissons ensuite de travailler sur une région autour de cette composante connexe dont le centre est le point le plus éloigné des bords de la composante connexe, et nous fixons la taille de la région à de 14 pixels.


Pour comprendre les approches possibles à la résolution subpixel, il faut comprendre à partir de quelles données nous pouvons, à priori, travailler :

  • l'image en niveau de gris
  • l'image seuillée
  • le gradient de l'image
Taches.png


Fort de ces images, plusieurs pistes semblent envisageables :

  • Très simplement dire que le centre est le point le plus éloigné des bords de la composante connexe définie en image2.
  • calcul d'un barycentre classique, mais le barycentre est sensible aux valeurs extrêmes.
  • Un calcul du centre comme le médian semble plus raisonnable mais ne peut être satisfaisant dans le cadre de ce projet car cela nous donne pas de résultat subpixel.
  • calcul d'un barycentre pondéré par l'intensité des pixels, la distribution d'intensité pouvant être assimilée à une gaussienne, les valeurs extrêmes auront peu d'influence sur le résultat final.
  • De la même façon, si la distribution n'est pas exactement gaussienne, nous pouvons partir de l'image seuillée et lui appliquer un masque parfaitement gaussien et faire un barycentre sur l'image résultante
  • Empiriquement la forme du doigt se rapproche d'une ellipse, nous pourrions donc trouver la meilleure ellipse (en terme de moindre carré) qui approche ce doigt.
  • le gradient de ce doigt (voir image 3) semble pouvoir être approché par un cercle, il faut donc trouver le meilleur cercle qui approche ce contour

Ces deux dernières approches se basent sur un algorithme dit de "block-matching" : Nous avons un pattern (dans ce cas l'ellipse ou le disque) que nous essayons de faire au mieux correspondre avec une tâche.

Un des gros problèmes de cette approche est le choix de la graine (sid) qui détermine la complexité de l'algorithme. De façon générale, un algorithme de block-matching est relativement coûteux mais offre dans notre cas des résultats satisfaisants.

Pour calculer l'erreur quadratique moyenne en subpixel, nous avons du pondérer les intensités des pixels par l'aire de l'image qu'il recouvrait.

Calcul de l'erreur quadratique moyenne en subpixel

Afin de comparer les différentes méthodes, nous avons procédé au test suivant :

  • un morceau de patafix a été posé sur le cube (afin de limiter le bruit du au doigt humain), et nous avons enregistrer les différentes positions des centres détectés. Puis nous avons calculé la variance de chacun de ces échantillons.

Le résultat est le suivant:

Variance en fonction de la méthode implémentée


Nous avons donc deux algorithmes qui marchent tout particulièrement bien :

  • Le barycentre pondéré par la valeur des intensités des pixels
  • Le fitting du meilleur disque avec un algorithme de block matching.

Pour l'algorithme de block matching se pose la question du choix du pattern, ici ce fut un cercle, mais encore fallait-il choisir le plus judicieusement possible le rayon de ce cercle. Encore dans un souci de précision et non de justesse : l'important ce n'est pas qu'il y ait correspondance parfaite entre la position du doigt sur le cubtile et celle sur l'image en sortie mais que cette position soit stable si jamais l'utilisateur ne bouge pas, nous avons fait varier le rayon du disque de block-matching.

Variance en fonction du rayon du disque

Nous avons donc fixé le paramètre de ce rayon à 4 pour la suite.

Identification

De manière générale, une surface tactile génère trois types primitifs différents :

- Apparition d'un doigt - Déplacement d'un doigt - Disparition d'un doigt.

Ce sont ces trois évenements qui seront envoyé aux applications (ihm ou autre). Ainsi, il est nécessaire d'identifier les doigts. Pour cela, à chaque nouvelle frame et pour chaque faces, il faut comparer les nouvelles positions des doigts avec les anciennes et :

- Les apparitions correspondent aux nouvelles positions qui ne sont proches d'aucune ancienne positions - Les déplacements correspondent aux nouvelles positions proches d'une ancienne position - Les disparitions sont les anciennes positions qui ne sont proches d'aucune nouvelles positions.

Cette approche ne fonctionne que si la distance entre deux positions successives d'un même doigt est inférieure au rayon du doigt. En effet, si la distance est plus grande alors deux doigts collés ne pourraient pas être identifiés correctements. Notre algorithme tournant à environ 70 images par secondes, la distance est bien inférieur à notre au rayon du doigt.

Ainsi chaque doigt est identifié par un numéro ce qui permet une utilisation simple pour les applications qui recevront les évenements en questions.

Interface Homme Machine

Dans le cadre de notre projet, il est important de montrer que le cubtile peut être un outil suffisamment efficace et précis. Une batterie de tests permet de montrer mathématiquement que l'on a bien ce que l'on veut. Mais, une application directe des performances du cubtile est essentielle pour véritablement "sentir" ces améliorations.

Nous nous sommes ainsi lancé dans l'élaboration d'une Interface Homme-Machine.


Architecture globale

Très rapidement nous est venue une question : comment rendre l'IHM indépendante de toute la partie traitement des données ? En effet, tous les traitements sont lourds et couteux : faire fonctionner une application supplémentaire pourrait surcharger l'ordinateur et saturer les performances.

Une architecture réseau client-serveur nous a permis de faire communiquer le cubtile et l'IHM sur deux ordinateurs différents si nécessaire. (travailler sur le même ordinateur est tout à fait possible en utilisant l'option "localhost")


Le client, côté cubtile, reçoit les informations et les envoie sous forme de paquets de type UDP. Lorsque les évènements sont générés par la partie cubtile, l'ensemble des informations est transmise au client sous la forme d'une structure de données. Après s'être créé sa socket réseau, le client envoie la structure de données sous forme de paquets UDP à l'adresse du serveur donnée en argument du programme principale.

Le serveur, côté IHM, reçoit les paquets et les transmet aux couches supérieures. Il décompose le paquet UDP reçu et en extrait les informations sous la même forme que lorsqu'elles furent empactées côté client. Ensuite, concrètement, une fonction de l'IHM est appelée avec pour paramètre cette structure de données. C'est l'IHM qui prend ensuite le relai et traite les informations à sa convenance.

Schéma de l'architecture

Architecture IHM

Après avoir réfléchi à différents types d'application (graphique (2D et 3D) et musicale) une application graphique en 3D nous est apparu comme la plus judicieuse. En effet, elle permettrait d'exploiter et mettre en avant la précision et la stabilité du traitement cubtile dans un environnement qui colle au mieux à l'utilité première du cubtile : manipuler intuitivement dans l'espace 3D.


Néanmoins au cours du développement, il a été nécessaire de développer une IHM minimale en 2D qui nous a permis de mettre en place toute l'architecture logiciel et le "pont" entre les deux parties traitement et IHM.

Screenshot de l'IHM 2D

Cette application affiche les cinq faces ainsi que les doigts détectés sur chacune des faces. Basique, elle a permis pourtant de mettre en place toute l'architecture globale ainsi que l'architecture de l'IHM en elle-même.

Le programme principale est composé du serveur qui est placé sur un thread (processus léger) qui fonctionne donc en parallèle de l'application principale. Cette dernière est elle-même composée d'un observateur, d'une (ou plusieurs) scène(s) et d'une vue. Cette architecture est clairement basée sur un patron de conception de type Modèle-Vue-Contrôleur.


Schéma de l'architecture

Le programme qui gère le serveur reçoit en argument l'adresse de l'observateur. Il lui envoie ainsi directement toutes les informations nécessaires. L'observateur (contrôleur) traite les données et modifie sa scène (modèle). Par demande de l'observateur (contrôleur), l'interface graphique (vue) met ensuite à jour sa "vision" de la scène (modèle).

IHM 3D

QGLViewer

Pour l'application de manipulation 3D, un environnement basé sur le framework QGLViewer a été mis en place. Ce framework, lui-même basé sur l'API openGL, inclue de base toute la gestion d'une scène 3D. Repaint automatique, gestion de la caméra et animations prédéfinies.

Screenshot de l'IHM 3D
Mouvements

Après avoir défini un objet dans la scène, notre but était de pouvoir le manipuler le plus intuitivement possible. Nous voulions vraiment éviter d'avoir une manipulation typée "bouton" avec un rendu peu semblable à la réalité.

Ainsi, chaque doigt posé sur le cubtile agit sur l'objet de la scène 3D. Le principe est simple : chaque mouvement effectué par l'objet, rotation ou translation, est décomposable en plusieurs mouvements basiques de rotation. Soient deux doigts posés sur une face (nous verrons plus tard, que les doigts peuvent être posés n'importe où sur le cube), lorsque l'on fait un mouvement, l'IHM va recevoir de façon asynchrone les évènements. A chaque réception d'un évènement, un seul doigt bouge.

On aura donc un point fixe (C), un point à un instant t (A) et un autre point à un instant t+1 (A'). Il faut ensuite trouver l'angle \alpha entre les segments [CA] et [CA'] pour pouvoir appliquer la rotation d'angle \alpha et d'axe la normale au plan défini par les trois points.


Décomposition minimale d'un déplacement à 2 doigts


Ceci fonctionne très bien pour la rotation et pour la translation. En effet pour la translation c'est successivement le point A qui va devenir le point A' puis le point C qui deviendra le point C' et ainsi de suite. Il est vrai que l'objet avance en "boitant", mais étant donné que l'on a des dizaines d'évènements par seconde, l'illusion de la translation est parfaite.

Ce qui rend aussi signicativement intéressant cette approche, c'est que les trois points peuvent être placé n'importe où dans l'espace et donc sur le cubtile. L'utilisateur peut ainsi effectuer des rotations et des translations où bon lui semble.

Déformations

Pour aller plus loin, l'option de rescaling a été implémenté. En se servant de trois doigts à la fois, on peut redimensionner l'objet de la scène. Les trois points forment un triangle dans l'espace. Lorsque l'on bouge un ou plusieurs des doigts, le triangle se déforme. C'est la variation d'aire entre ces deux triangles qui va définir la variation de la taille de l'objet de la scène.

Le problème du docking

A présent que différents types d'actions sont possibles, un petit jeu a été implémenté pour prouver que notre traitement permet une manipulation suffisamment fluide. Le principe est simple : placer un objet dans une certaine position à un certain endroit en un minimum de temps. Ainsi le dock, qui correspond au but à atteindre est placé dans la scène. L'utilisateur doit ensuite se débrouiller pour déplacer, orienter et redimensionner l'objet de la bonne manière.

Le docking

Mesures des performances

Precision

Pour chaque algorithme, la précision est mesurée en calculant la position d'un "faux doigt" statique sur un grand nombre de frames successives.

Les différentes positions sont enregistrées et une étude statistique permet de déduire la précision de l'algorithme utilisé :

Un test de Shapiro permet tout d'abord de s'assurer que les données récupérées forment un échantillon de type Gaussien. Or le modèle Gaussien possède la propriété suivante que plus de 95% de la population se trouve dans le disque centré en la moyenne et de rayon 2*ecart-type.


En calculant l'écart-type résultant de l'analyse statistique des échantillons, on peut donc extraire pour chaque algorithme une discrétisation de la surface tactile sur laquelle la position d'un doigt statique sera stable et immobile,le but étant d'avoir la discrétisation la plus fine possible comme illustré dans le schéma :


Comparaison des grilles

Ci-dessous sont reportées les performances atteintes par les deux meilleurs algorithmes qui sont le block-matching par un disque et le barycentre pondéré par l'intensité des pixels.

Ecart-type des distance à la moyenne


Dans le cas du barycentre, la meilleure discrétisation stable possède donc un pas de  4*0,37 = 1,28 pixels et dans le cas du block-matching, nous atteignons une discrétisation de pas 0,8 pixels, donc une précision sub-pixel.


Latence

La latence est mesurée est calculée de la manière suivante :

Un marqueur de temps est positionné via un appel système dès que la frame à traiter est disponible en RAM. Un second marqueur de temps est positionné dès la fin du traitement de cette frame. En faisant la différence et en répétant l'opération un grand nombre de fois, on peut mesurer le temps moyen qui s'écoule entre le début et la fin du traitement.

Il faut ajouter au temps obtenu le temps de transfert de l'image de la camera vers la RAM. Cette donnée est inconnue, mais le framerate étant important (>80fps), on peut supposer que le temps de tranfert est inférieur au temps qui sépare deux frames successives et donc bien inférieur à 10ms...

Les résultats sont représentés ci-dessous, le temps étant découpé selon les étapes de la chaine de traitement :

Temps de traitements moyens par cycle en millisecondes


Pour interpréter correctement les résultats il y a plusieurs éléments à prendre en compte :

- La machine sur laquelle s'éxécute le programme influe très fortement sur les résultats. Dans notre cas il s'agit d'un MacBook Pro muni d'un processeur Intel i5 cadencé à 2,3Ghz et muni de RAM DDR3 véloce, la carte graphique étant une carte intégrée Intel HD Graphics 3000 avec mémoire partagée en RAM...

- Le temps "d'attente" ne rentre pas dans la latence. En effet, il s'agit du temps que passe le programme à attendre l'arrivée de la frame suivante tout en ayant terminé le traitement la frame courante.

- Un GPU plus puissant ne fournira probablement aucun gain significatif, en effet, la latence est surtout induite par les transfert des données de la mémoire RAM vers celle du GPU et vice versa. A l'inverse, une carte graphique "Intégrée" au processeur permet justement d'éviter ces temps de transfert et donc d'éviter cette latence.

- Les mesures ont été effectuées avec 2x2 doigts positionnés sur deux faces.


Au final nous atteignons un framerate d'environ 70 images/secondes et une latence entre 14 et 18 millisecondes selon l'algorithme. Même en ajoutant le temps (<10ms) induit par le transfert des données de la camera en RAM, nous sommes bien en dessous des 50ms à partir desquelles l'utilisateur commence à percevoir la latence.

Analyse critique

Nous énumérons ici les limitations techniques que nous avons rencontrées :

  • Vision par ordinateur
    1. Non uniformité des données : introduite par l'environnement (éclairage par exemple), soit inhérente au matériel (angles de vue de la caméra présentée précédemment)
    2. Calibrage fastidieux et crucial : conséquence du point précédent.
  • Techniquement
    1. Résolution de la camera faible : image de taille initiale 494x656 puis après découpe faces de taille 206x206, soit assez peu de pixels pour faire un fiting correct (un doigt fait une quizaine de pixels de rayon).
    2. En pratique, nivellement par le bas. En effet, pour avoir des performances uniformes sur l'ensemble du cubtile, il est nécessaire de réduire les performances issus de certaines zones bien exposées du cubtile pour obtenir les même performances que celles des zones mal exposées.
    3. Le traitement vidéo implique une quantitée de calcul importante, est-ce vraiment une bonne approche pour obtenir des surfaces tactiles ? Les surfaces capacitives sont selon nous probablement plus adaptées.