Leap Motion : présentation et utilisation

Porteur du projet : Mélodie Souty

Date : 01/2017

Licence : libre !

Lien : Site Leap Motion

Github

Le Leap Motion est un périphérique permettant la reconnaissance des mains. Il est utilisable avec des applications ou des jeux disponibles sur le “Leap Motion App Home”, mais il est également possible de l'utiliser sur différent logiciels pour l'intégrer à des projets. Il est possible de l'utiliser très simplement avec Unity, uniquement sur Windows, les tutoriels sont fournis sur le site du Leap Motion. Il peut, par exemple, être utilisé en complément d'un casque de réalité virtuel.

Comment cela fonctionne ?

Le coeur de l'appareil se compose de deux caméras et trois LED infrarouges. Les lentilles des caméras sont des lentilles grand angle, et les LED infrarouge permettent de capter jusqu'à 60cm au dessus de l'appareil. Il fonctionne de la même manière qu'une Kinect, avec une grille de point comme le montre l'image ci-dessous.
Plus d'informations techniques ici

Avec Processing

J'ai utilisé le Leap Motion avec Processing 2 et la librairie Leap Motion for Processing. Avec cette librairie est fourni 3 exemples, nous allons décortiquer le premier pour apprendre à en utiliser les méthodes. Le nom de l'exemple est LM_1_Basics, et on peut le trouver dans l'application Processing dans l'onglet Files>Exemples>Contributed Librairies>Leap Motion for Processing.
Voici le résultat que l'on obtient à la lecture du programme :
Le début du code est courant, il faut importer la librairie et créer l'objet Leap Motion.

import de.voidplus.leapmotion.*; // Importation de la librairie
LeapMotion leap; // Déclaration de l'objet
void setup() {
size(800, 500); // Taille de la fenêtre
background(255); // Le fond est blanc
//Remarque : ici le background ne sert à rien, il est répété dans la partie draw, là où il est sensé être normalment.
leap = new LeapMotion(this); // Création de l'objet leap
}

Ensuite, il y a une partie qui sert au débugage afin de savoir si le Leap Motion est branché, ou non, ou en train de s'initialiser etc. Les messages relatifs à l'état du Leap Motion seront écris dans la partie console.

void leapOnInit() {
// println("Leap Motion Init");
}
void leapOnConnect() {
// println("Leap Motion Connect");
}
void leapOnFrame() {
// println("Leap Motion Frame");
}
void leapOnDisconnect() {
// println("Leap Motion Disconnect");
}
void leapOnExit() {
// println("Leap Motion Exit");
}

Dans le Void draw(), on a une liste de toutes les données qui sont récupérable.
En premier on trouve le fps (frame per second, image par seconde) du Leap Motion. La donnée est stockée dans une variable entière grâce à la fonction leap.getFrameRate().

int fps = leap.getFrameRate();

Les mains

Ensuite, on peux récupérer les données relative aux mains. Pour cela il faut utiliser une boucle for un peu particulière. Sans cette boucle for, le programme ne peux pas aller récupérer les données. Elle semble crée un objet “hand” dans lequel serait stocké les données relatives à la main.

for (Hand hand : leap.getHands ()) {
int handId = hand.getId();
PVector handPosition = hand.getPosition();
PVector handStabilized = hand.getStabilizedPosition();
PVector handDirection = hand.getDirection();
PVector handDynamics = hand.getDynamics();
float handRoll = hand.getRoll();
float handPitch = hand.getPitch();
float handYaw = hand.getYaw();
boolean handIsLeft = hand.isLeft();
boolean handIsRight = hand.isRight();
float handGrab = hand.getGrabStrength();
float handPinch = hand.getPinchStrength();
float handTime = hand.getTimeVisible();
PVector spherePosition = hand.getSpherePosition();
float sphereRadius = hand.getSphereRadius();

On a donc ici des variables dans lequelles sont stockées respectivement :

l'identifiant de la main (qui augmente à chaque apparition de là main et cela depuis le branchement du Leap Motion).

Un vecteur (variable avec trois coordonnées x, y et z) correspondants aux coordonnées de la paume de la main.

Un vecteur “StabilizedPosition”. Les coordonnées de la position et de stabilized position sont sensiblement les mêmes. Cela semble être les coordonnées de la main après la correction de l'image du Leap Motion qui est naturellement bombée et donc déformé. (À confirmer)

Un vecteur Dynamics qui contiendrais les “angles de la main”. La coordonnées x serait “roll”, le y “pitch” et le z “yaw”. À éclaircir.

Chacune de ces valeurs sont aussi disponible indépendamment dans une variable float.

Des booléens nous permettent de savoir si le Leap Motion capte la main droite ou gauche.

La variable handGrab est une valeur comprise entre 0 et 1. Elle augment au fur et à mesure que le poing se referme.

La variable handPinch est de la même manière comprise entre 0 et 1, elle semble être égale à 1 pour un mouvement correspondant à un pincement.

La variable “handTime” compte le temps écoulé en seconde depuis l'apparition d'une main. Intéresser si on veux créer une application avec un temps de prise en main et de découverte de l'interface d'une trentaine de seconde avant de débuter les actions.

“spherePosition” et “sphereRadius”. Je ne sais pas à quoi correspond cette sphère ! Si on permet la 3D dans le sketch avec l'attribut P3D, pn peux la faire s'afficher avec le code ci-dessous. Son rayon n'est d'ailleurs jamais le même.

pushMatrix(); // Début de la transformation
translate(spherePosition.x, spherePosition.y, spherePosition.z); // déplacement en x, y et z aux mêmes coordonnées que celles de la paume de la main
sphere(30); // Création de la sphèré
popMatrix(); // Fin de la transformation

Ce sont donc les données que nous pouvons récupérer avec la main. Ensuite viendrons les données de l'avant-bras, des doigts etc. Cependant, la boucle for correspondant à la main ne doit pas être fermé !! Car elle permet également de récupérer les autres données.
On remarque ensuite la présence d'une méthode permettant le dessin de la main :

hand.draw();

Cette méthode a donc déjà été pré-établie pour créer le dessin de la main, de l'avant bras, des phalanges etc. que l'on vois lorsqu'on lance le programme. En claire, si on veux juste un programme qui dessine la main, il suffit juste d'écrire :

import de.voidplus.leapmotion.*;
LeapMotion leap;
void setup() {
size(800, 500);
leap = new LeapMotion(this);
}
void draw() {
background(255);
int fps = leap.getFrameRate();
for (Hand hand : leap.getHands ()) {
hand.draw();
}
}

L'avant-bras

Ici, le programme nécessite une condition pour récupérer les données du bras.

if (hand.hasArm()) {
// Création d'un objet Arm avec les données relatives au bras contenues dans la main.
Arm arm = hand.getArm();
float armWidth = arm.getWidth();
PVector armWristPos = arm.getWristPosition();
PVector armElbowPos = arm.getElbowPosition();
}

Ici on récupère donc les données suivantes :

La longueur du bras dans une variable float

Un vecteur avec la position du poignet

Un autre contenant la position du coude.

Les doigts

Dans un premier temps, le programme nous montre comment on crée les objets relatifs à tout les doigts. Chaque doigt peut être crée de trois manières différentes :

Finger fingerThumb = hand.getThumb();
// ou hand.getFinger("thumb");
// ou hand.getFinger(0);
Finger fingerIndex = hand.getIndexFinger();
// ou hand.getFinger("index");
// ou hand.getFinger(1);
Finger fingerMiddle = hand.getMiddleFinger();
// ou hand.getFinger("middle");
// ou hand.getFinger(2);
Finger fingerRing = hand.getRingFinger();
// ou hand.getFinger("ring");
// ou hand.getFinger(3);
Finger fingerPink = hand.getPinkyFinger();
// ou hand.getFinger("pinky");
// ou hand.getFinger(4);

Ensuite, comme pour la main, il faut utiliser une boucle for pour obtenir les différentes données. Cette même boucle for peut être écrite de trois manières différentes.

for (Finger finger : hand.getFingers()) {
// or hand.getOutstretchedFingers();
// or hand.getOutstretchedFingersByAngle();
int fingerId = finger.getId();
PVector fingerPosition = finger.getPosition();
PVector fingerStabilized = finger.getStabilizedPosition();
PVector fingerVelocity = finger.getVelocity();
PVector fingerDirection = finger.getDirection();
float fingerTime = finger.getTimeVisible();

On récupère donc respectivement :

Un numéro identifiant les doigts. À éclaircir.

La position des doigts. Les cinq à la suite.

“fingerStabilized” vraisemblablement la position des doigts corrigée.

La “rapidité” des doigts. Donne un chiffre qui semble correspondre à une certaine unité de vitesse lors d'un déplacement des doigts sur les trois axes.

La direction des doigts. Semble indiquer un chiffre entre 0 et 1 correspondant à un déplacement des doigts les trois axes.

Le temps écoulé en seconde depuis la captation des doigts.

Il y a ensuite trois méthodes pour dessiner les doigts :

finger.drawBones(); dessine le squelette des doigts

finger.drawJoints(); dessine les phalanges et les jonctions des doigts avec la main

finger.draw(); exécute les deux méthode précédentes.

À rappeler : la fonction hand.draw() dessine déjà le squelette et les phalanges.

La suite reste floue...

IL semblerait que l'on puisse récupérer les identifiants de chaque os. Plus d'informations ici.
La suite du programme contient aussi des variables semblant correspondre au “survol” eu au “toucher”. Je n'ai pas encore éclaircie cette partie. La partie “outil” n'est pas encore éclaircie non plus. Des informations sont surement disponible ici.
Dans la partie Devices, on peux obtenir des informations sur notre appareil, comme les angles de vues horizontaux ou verticaux.

La suite au prochain épisode ?

Il reste encore des points à éclaircir sur l'utilisation par Processing du Leap Motion. Cet exemple nous permet déjà d'utiliser des données essentielles, traitable facilement. Il semble y avoir avec cette librairie une liste de gestuelles reconnaissable. C'est surement cela le prochain chantier.
Enfin j'ai utilisé cette librairie, mais il en existe une deuxième dont je ne connais pas l'utilisation, ni ce qu'elle permet de récupérer. J'utilise aussi Processing 2, je n'ai pas testé sa compatibilité avec Processing 3.