K▹IN

Pilotage

Pour le moment, le processus C++ et le processus Java n'ont aucun lien. Le plus simple est de lancer l'application C++ depuis l'application Java. Cela permet de lancer le client et le serveur dans l'ordre, de relancer le client en cas de crash ou de déconnexion du Kinect.

L'application doit être lancée avec des droits élevés. Pour éviter d'avoir à renseigner le mot de passe de l'utilisateur


	sudo visudo
			

Dans la section "# Cmnd alias specification", ajouter


	Cmnd_Alias KINECT_CMD = /chemin/vers/libfreenect2/build/bin/Protonect
			

A la fin du fichier, ajouter


	 ALL=(ALL) NOPASSWD: KINECT_CMD
			

Le processus peut alors être piloté depuis java


	ProcessBuilder pb = new ProcessBuilder("/bin/bash","-c","sudo ./Protonect");
	pb.directory(new File("/chemin/vers/libfreenect2/build/bin"));
	Process p = pb.start();		

	// code

	p.waitFor();
			

Une temporisation est nécessaire en cas de relance.

Flux

Mon objectif est de pouvoir identifier les objets situés devant le Kinect en éliminant l'arrière-plan. Le flux brut issu du Kinect nécessite plusieurs traitements pour atteindre cet objectif.

Flux brut

Flux brut issu du Kinect Chaque image de profondeur retournée par le Kinect est en 512x424 avec 4 octets par point. Chaque trame fait donc 512x424x4 = 868352 octets.

Décodage du flux

Toutes les données renvoyées par le Kinect ne sont pas nécessaires (Pas besoin de valeurs fines). J'ai retenu les données suivantes Bit de poids faible du 4ème octet suivi du 3ème octet

Soit en Java


	val = (((int)(source[idx + 3] & 1)) << 8) + (source[idx + 2] & 0xFF);
			

Ce qui donne le résultat suivant Flux Kinect décodé La valeur obtenue est proportionnelle à la distance. Dans la capture, plus le point est proche du capteur, plus le pixel est blanc.

Mise à plat

Il suffit d'éliminer les valeurs trop grandes. Comme le relief n'a aucun intérêt, l'information peut être encodée sous forme de tableau de booléen (présent/absent) Flux Kinect à plat Deux éléments à noter : la présence d'artéfacts à l'arrière-plan et le découpage de la main au premier plan. Ce découpage est dû au décalage entre les leds et la caméra infra-rouge du Kinect, qui entraîne la formation d'une zone d'ombre.

Identification de groupes

Un algorithme très simple permet de regrouper les points appartenant à une forme.

Les groupes sont identifiés par un entier (En pratique, un int[] sera associé au boolean[] obtenu à l'étape précédente).

Un tableau de liens permet de suivre les rattachements entre les groupes. Le lien va toujours dans le sens de l'identifiant le plus grand vers l'identifiant le plus petit. Un groupe (source) ne peut être rattaché qu'à un seul groupe (cible). Si deux liens existent pour la même source, le lien vers le plus petit identifiant est conservé. Un nouveau lien est créé entre la cible éliminée et la cible conservée.

Etape 1 - Associer chaque point actif à un groupe temporaire

Le parcours est réalisé ligne par ligne, de haut en bas et de gauche à droite. Pour chaque point actif :

Deux approches possibles en Java

  • Implémentation "Objet", propre mais qui entraîne la création de nombreux objets à très courte durée de vie, et peut mettre la pression sur le garbage collector.
  • Implémentation "Tableau". De grands tableaux sont initialisés une seule fois pour stocker les différents éléments
Les deux implémentations sont disponibles dans le code source

Etape 2 - Simplifier le tableau des liens

La cible d'un lien peut elle-même être la source d'un autre lien.

Cette étape consiste à parcourir les liens afin de ne plus avoir que des destinations finales (Groupe cible n'étant source d'aucun lien)

Etape 3 - Affectation du groupe final

Il suffit ensuite de parcourir les groupes temporaires. Si le groupe est source d'un lien, remplacer par sa cible. Identification de groupes

Avec cette méthode, 97 groupes sont identifiés, dont la plupart ne font que quelques pixels.

Traitement sur les groupes

A partir du groupe, il est très simple d'éliminer les artéfacts, en supprimant les groupes ayant un nombre de points inférieur à un seuil donné.

De la même façon, il est possible de calculer rapidement le centre de gravité de chaque groupe.

Pourquoi calculer le centre de gravité?

Le centre de gravité a plusieurs usages :
  • Il permet de retrouver rapidement les objets d'une trame à l'autre
  • Il permet de définir un point de fuite pour la collision avec des particules (Utilisé à la prochaine étape)

A la fin du traitement, il ne reste que deux groupes dans l'exemple (rouge et orange). Le centre de gravité est représenté par une petite croix blanche. Traitement sur les groupes