Scan 3D

De Wiki de Projets IMA

Introduction

Dans le cadre de la cinquième année nous avons pour consigne de réaliser un projet en rapport avec notre formation. Nous avons choisi de travailler sur le projet du Scan 3D car nous sommes tous les deux intéressé par l'utilisation des capacités de la Kinect.

Ce projet est un projet industriel en lien avec la société Oxylane. Au sein de cette dernière, beaucoup de prototypes ont été réalisés sans passer préalablement par une phase de conception 3D. Ce sont des prototypes uniques, des objets difficilement duplicables. De plus en plus de concepteurs, de designers et de chercheurs aimeraient pouvoir continuer à travailler sur ces objets physiques dans le monde virtuel. Oxylane cherche donc un moyen de scanner ces objets sans passer par des équipements très coûteux.

Présentation du projet

Ce projet consiste donc de réaliser un prototype de scanner 3D en utilisant la Kinect, permettant de transformer des objets réels en forme 3D. Les besoins les plus forts concernent actuellement les casques de vélo et les chaussures.

Cependant avant de se lancer directement dans le scan 3D, nous devons tout d'abord étudier ce qu'il est possible de faire actuellement avec la Kinect. De nombreux documents sont là pour nous aider ainsi qu'une base de logiciel permettant le scan 3D : Kinect Fusion (KinFu).

Etat de l'art

De nos jours, la volonté de reconstruire la géométrie à l'aide de capteurs actifs, de caméras passives ou d'images en ligne sont des points très étudiés dans la recherche en informatique graphique et vision. L'utilisation de caméra à infrarouges est très étendue et de nombreuses sociétés créent leur propre caméra utilisant cette technologie (Microsoft avec la Kinect, Asus avec son Asus Xtion, ou encore Leap de Leap Motion). Alors que les caméras de profondeur ne sont pas totalement nouvelles, Kinect a fait de ces capteurs, des capteurs accessibles à tous. La qualité de la détection de profondeur, étant donné la nature à faible coût et en temps réel de l'appareil, est convaincante et en a fait un capteur populaire auprès des chercheurs et des amateurs. La Kinect de Microsoft est donc l'une des plus populaires et des plus abordables.


Microsoft a eu la volonté d'améliorer les compétences de sa Kinect et il s'est attardé sur la possibilité, avec KinectFusion, de créer rapidement et en temps réel une reconstruction 3D d'une scène d'intérieur. Pour ce faire, la caméra Kinect utilise une technique structurée de la lumière pour générer des cartes de profondeur en temps réel contenant des mesures de distances discrètes de la scène physique. Ces données peuvent être projetées comme un ensemble de points discrets 3D (ou nuage de points). Même si les données de profondeur Kinect sont convaincantes, en particulier par rapport aux autres appareils de profondeur disponibles dans le commerce, il existe toujours du bruit. Les mesures de profondeur fluctuent souvent et les cartes de profondeur contiennent de nombreux «trous» où la lecture n'a pas été obtenue.

Pour des systèmes simples, comme les jeux vidéo, ce bruit, ces trous peuvent être éliminés en faisant la moyenne des points qui les entourent. Pour des objectifs plus complexes comme un modèle 3D, il est nécessaire de capturer plusieurs vues de la scène physique et de les fusionnées pour en faire une seule représentation. C'est pour ces travaux plus complexes que le programme Kinect Fusion a été inventé.

Installations, Découverte de Kinect Fusion

Lors des 4 premières séances de projets que nous avons pu faire, nous nous sommes intéressé à l'installation et à l'utilisation des OpenSources de Kinect Fusion. Voici les différents outils que nous avons eu besoin d'installer pour faire fonctionner la Kinect et l'Open Source sur un Linux.

Installation de OpenNi, Nite, SensorKinect

  • Installer OpenNi Unstable
    • Pré-requis
       Obligatoires :
               1) GCC 4.x
                 apt-get install g++
               2) Python 2.6+/3.x
                apt-get install python
               3) LibUSB 1.0.x
                apt-get install libusb-1.0-0-dev
               4) FreeGLUT3
                apt-get install freeglut3-dev
               5) JDK 6.0
                apt-get install openjdk-6-jdk
       Optionel (Pour la documentation):
               1) Doxygen
                 apt-get install doxygen
               2) GraphViz
                  apt-get install graphviz
    • Installation
       cd ~/OpenNi/Platform/Linux/CreateRedist
       chmod +x RedistMaker
       ./RedistMaker
       cd ~/OpenNi/Platform/Linux/Redist/OpenNI-Bin-Dev-Linux-x64-v1.5.4.0
       su
       ./install.sh
  • Installation de SensorKinect :
       cd ~/SensorKinect/Platform/Linux/CreateRedist
       chmod +x RedistMaker
       ./RedistMaker
       cd ~/SensorKinect/Platform/Linux/Redist/Sensor-Bin-Linux-x64-v5.1.2.1
       ./install.sh

Installation de la PCL Expérimentale

Obligatoire :

  • cmake
apt-get install cmake
  • Boost ≥ 1.46
apt-get install libboost-all-dev
  • Eigen ≥ 3.0
apt-get install libeigen3-dev
  • FLANN ≥ 1.7.1
apt-get install libflann-dev
  • VTK ≥ 5.6
apt-get install libvtk5-dev


Installation

cd ~Pcl/trunk
mkdir build && cd build && cmake ..
make
make install

Utilisation de KinFu LargeScale

  • d'après le tutoriel :

http://pointclouds.org/documentation/tutorials/using_kinfu_large_scale.php

  • ./bin/pcl_kinfu_largeScale -r -et
  • ./bin/pcl_kinfu_largeScale_mesh_output world.pcd
  • Fusionner les mesh générés avec MeshLab et l'exporter dans KinFuSnapshots
  • ./bin/pcl_kinfu_largeScale_texture_output KinFuSnapshots/merged_mesh.ply

Utilisation de KinFu App

Nous nous sommes ensuite attardé sur cette partie de KinFu et nous nous sommes rendu-compte qu'elle permet de scanner un objet en 3 dimensions et d'en faire facilement le tour. Nous récupérons ensuite le scan dans un fichier .ply exploitable par le logiciel MeshLab. Voici les commandes que nous devons taper pour le faire fonctionner :

  • cd ~/trunk/build/bin
  • ./kinfu_app
  • Une fois le programme lancé, voici les trois fenêtres qui s'ouvrent :

Application KinFu

  • On peut observer dans la fenêtre View3D from ray tracing le mesh 3D en cours de la Kinect
  • Appuyer succéssivement sur A dans la fenêtre Scene Cloud Viewer pour ajouter le mesh en cours au mesh que l'on souhaite exporter.
  • Appuyer sur 7 pour exporter le mesh de la fenêtre Scene Cloud Viewer dans un fichier PLY


Plusieurs options sont disponibles dans kinfu_app, notamment l'option -volume_size <size_in_meters> qui permet de réduire le champ de vision de la kinect en profondeur

Réunion du 12 novembre avec Oxylane

Nous avons rencontré lors de cette réunion le responsable du service innovation de Oxylane. Nous lui avons montré nos avancements dans les tests de Kinect Fusion et nous nous sommes mis d'accord sur les trois points d'études suivants :

  • Etude des limites du programme Kinect Fusion (avantages, inconvénients, ajouts de fonctionnalités possibles).

Etudier le principe de fonctionnement de l'Open Source KinFu de Kinect Fusion et se rendre compte de ce qu'il est possible de faire ou de ne pas faire avec le programme (textures, couleurs ...)

  • Tests avec la Kinect de bureau pour améliorer la précision.

Pouvoir donner une idée de que l'on peut faire et ce que l'on peut améliorer avec une Kinect de bureau plutôt que la Kinect Xbox.

  • Tests pour la création d'un scénario complet de scan d'un casque de vélo.

Ce test permettrait de mettre l'accent sur les points bloquants lors d'un scan d'un objet quelconque (éventualité d'isoler l'objet de son environnement par exemple). Ce test nous permettra aussi de prendre du recul sur les outils disponibles et sur la réalité des compétences qu'ont besoin d'avoir ceux qui voudraient utiliser une kinect pour faire du scan 3D.

Réalisations

Etude appronfondie du fonctionnment de Kinect Fusion

Une fois les différents premiers tests effectués, nous avons voulu savoir comment fonctionner KinFu. Pour cela, nous avons tout d'abord cherché sur Internet quelques recherches et nous sommes tombés sur ce site expliquant de manière globale le fonctionnement de Kinect Fusion : [http://www.tumblr.com/tagged/kinect+fusion ]

Afin de détecter la profondeur des objets présents dans la scène, Kinect Fusion utilise la caméra infra-rouge de la kinect. Un projecteur infrarouge projette une lumière invisible sur la scène. Il a été spécialement conçu pour projeter les points à la manière d'un laser de telle sorte que les points ne se dilatent pas avec la distance. Cette lumière est lu par la caméra infrarouge. Une fois que ce schéma est lu par la caméra infrarouge, le programme Kinect Fusion recherche des corrélations. Si il en trouve,le processeur dans le kinect est alors en mesure d'utiliser cette information pour trianguler la position 3D des points.

Réunion du Mercredi 5 décembre avec Oxylane

Oxylane et son pôle Innovation (IT Pole "Oxylane brands") organise chaque année, les "IT Days Oxylane". Il s'agit d'un salon où chaque pôle de recherche présente ses différents projets en cours. Il se déroulera le Mercredi 12 décembre à Décathlon Campus.

Notre tuteur entreprise M. Jean VANBERSELAERT, nous a proposé d'y participer pour présenter nos travaux. Nous nous sommes donc vus en réunion pour discuter de ce que nous allons présenter lors de ce salon. Comme nous ne sommes disponibles que le mercredi après-midi, nous allons nous y rendre la veille pour préparer notre stand et installer sur une de leur machine les différents éléments nécessaires pour pouvoir utiliser la Kinect et le programme Kinect Fusion. M. VANBERSELAERT a également pensé de nous filmer pour avoir une explication de notre projet à présenter le matin du salon.

Lors de cette réunion, on nous a fourni un rouleau de papier fluorescent ainsi qu'un casque de vélo pour faire des tests avec la Kinect. En effet, nous pensions que ce type de couleur absorerait les rayons infra-rouges et nous permettrait d'isoler un élément à scanner de son environnement. Nous avons fait quelques tests après la réunion et nous nous sommes rendu compte que cela ne fonctionnait pas. Nous avons alors essayer de poser le casque sur une boite en plastique transparent et nous obtenons le résultat suivant :

Image du scan d'un casque de vélo

Le "IT Day Oxylane"

Oxylane et son pôle Innovation (IT Pole "Oxylane brands") organise chaque année, le "IT Day Oxylane". Il s'agit d'un salon où chaque pôle de recherche présente ses différents projets en cours. Il s’est déroulé le Mercredi 12 décembre à Décathlon Campus. Notre tuteur entreprise M. Jean VANBERSELAERT, nous a proposé d'y participer pour présenter nos travaux. Nous nous sommes donc vus en réunion pour discuter de ce que nous allions présenter lors de ce salon. Comme nous n’étions disponibles que le mercredi après-midi, nous nous y sommes rendu la veille pour préparer notre stand et installer sur une de leur machine les différents éléments nécessaires pour pouvoir utiliser la Kinect et le programme Kinect Fusion. Cependant l’installation de KinFu sur leur machine fut plus difficile que prévu. En effet, la carte graphique de la machine ne correspondait pas aux besoins que demande Kinect Fusion, par conséquent l’installation faisait une erreur au bout de 35%. Afin d’avoir tout de même quelque chose à présenter lors du salon, nous avons installé sur une machine Windows le logiciel ReconstructMe. Sur la machine Linux, nous avons tenté de mettre à jour les différents drivers de la carte graphique et nous avons recommencé l’installation de KinFu le mercredi après-midi. Cette fois ci l’installation s’est arrêtée à 75%. Nous avons lors du make de l’installation l’option « –i » qui ignore les erreurs et cela à fonctionner. Nous avons pu montrons alors notre réel travail.

Voici quelques photos de notre stand :

Image 1 de notre stand

Image 2 de notre stand

Image 3 de notre stand

Vous pouvez voir sur la machine de gauche le logiciel ReconstructMe et sur celle de gauche Kinfu. Cet évènement, nous aura permis de nous rendre compte que l’installation de KinFu dépend également de la machine de travail. En effet, à Polytech’Lille nous avons des machines puissantes et mises à jour et ce n’est pas forcément le cas chez les industriels.

Planning pour les mois de Janvier et de Février

Afin de gérer au mieux les deux derniers mois de projet, nous avons choisi de faire un planning. En effet, il nous reste 5 tâches à effectuer :

  • Test avec la Kinect de bureau ou le zoom Nyko
  • Isolation de l'objet par rapport à son environnement
  • Comprendre le fonctionnement de cmake => build d’un projet PCL + Qt dans KDevelop4
  • Créer une interface graphique permettant à l'utilisateur d'utiliser facilement KinFu
  • Ajouter la texture et les couleurs au Mesh

Voici donc le planning que nous avons élaboré :

Planning

Compréhension du fonctionnement de cmake et de Qt dans KDevelop

  • cmake est un générateur de Makefile. Son processus de génération est entièrement contrôlé par un fichier de configuration : CMakeLists.txt

La PCL utilise ce générateur de makefile. Voici les commandes que nous utilisons :

mkdir build && cd build
cmake ..
make kinfu_app

Nous ne cherchons ici qu'à compiler notre application : kinfu_app

  • Pour créer notre interface graphique, le fait de développer en c++ nous a immédiatement fait penser à utiliser le framework Qt.

Ce framework dispose lui aussi d'un générateur de Makefile : qmake. Cependant, qmake est destiné aux projets fortement qui utilisent fortement Qt, or notre projet est un projet déjà conséquent n'utilisant ni Qt ni qmake. Heureusement, cmake est capable de gérer Qt. Nous avons donc recherché les macros permettant de compiler nos fenêtre écrites en Qt.

On remarque que les fichiers sources sont compilés normalement, mais que les fichiers d'en-tête, formulaire utilisateur (.ui) et fichiers ressources (.qrc) subissent une étape intermédiaire.

    • Les fichiers h sont générés par moc
    • Les fichiers ui sont générés par uic
    • Les fichiers qrc sont générés par rcc
  • Voici la partie du CMakeLists.txt que nous avons modifié :
FIND_PACKAGE(Qt4 REQUIRED)
set(the_target kinfu_app)
set(srcs kinfu_app.cpp appthreadkinect.cpp kinectinterface.cpp capture.cpp evaluation.cpp parameterdialog.cpp)
set(rscs resources.qrc)
QT4_WRAP_CPP(mocsqt appthreadkinect.h parameterdialog.h kinectinterface.h)
QT4_ADD_RESOURCES(rccqt ${rscs})
INCLUDE(${QT_USE_FILE})
ADD_DEFINITIONS(${QT_DEFINITIONS})
source_group("Source Files" FILES ${srcs} )
PCL_ADD_EXECUTABLE(${the_target} ${SUBSYS_NAME} ${srcs} ${hdrs} ${mocsqt} ${rccqt})
target_link_libraries(${the_target} pcl_common pcl_io ${OPENNI_LIBRARIES} pcl_visualization pcl_gpu_kinfu  ${QT_LIBRARIES})

En résumé :

  • On attribut a la variable srcs nos fichiers cpp, et à rscs le fichier de ressources indiquant où se trouvent nos images.
set(srcs kinfu_app.cpp appthreadkinect.cpp kinectinterface.cpp capture.cpp evaluation.cpp parameterdialog.cpp)
set(rscs resources.qrc)
  • Pour appeler moc, la macro QT4_WRAP_CPP est utilisée sur uniquement les fichiers h utilisant Qt. Les fichiers sources seront stockés dans la variable mocsqt. C'est le même principe pour les fichiers de ressources.
QT4_WRAP_CPP(mocsqt appthreadkinect.h parameterdialog.h kinectinterface.h)
QT4_ADD_RESOURCES(rccqt ${rscs})
  • Pour compiler une application Qt, les répertoires include de Qt doivent être ajoutés et un ensemble de paramètres doit être défini via :
INCLUDE(${QT_USE_FILE})
ADD_DEFINITIONS(${QT_DEFINITIONS})
  • Enfin, on définit le nom de l'exécutable, ainsi que les bibliothèques qui doivent être liées.
PCL_ADD_EXECUTABLE(${the_target} ${SUBSYS_NAME} ${srcs} ${hdrs} ${mocsqt} ${rccqt})
target_link_libraries(${the_target} pcl_common pcl_io ${OPENNI_LIBRARIES} pcl_visualization pcl_gpu_kinfu  ${QT_LIBRARIES})

Création de l'interface graphique

Comme vu au paragraphe précédent, nous savons maintenant modifier le programme KinFu et nous savons également développer en Qt. Grâce à cela, nous avons pu créer une interface graphique afin qu'un utilisateur "lambda" puisse utiliser facilement le programme KinFu sans devoir taper sur des touches (A pour scanner et 7 pour sauvegarder).

Nous avions tout d'abord essayer de rajouter notre interface dans l'application KinFu_app mais nous nous sommes rendu compte que le programme affichait d'abord notre interface puis nous devions la fermer pour avoir les trois fenêtres de l'application. Par conséquent, nous avons choisi de faire tourner les deux interfaces en parallèle grâce au threads.

Nous avons donc créer l'interface graphique dans une classe qui lui est propre et nous appelons cette classe dans le "main" de l'application KinFu de la manière suivante :

QApplication qtApp(argc, argv);
KinectInterface kinectInterface;//= new KinectInterface;
AppThreadKinect thread(&kinectInterface);
thread.setArgc(argc);
thread.setArgv(argv);

La classe "KinectInterface" utilise la bibliothèque graphique Qt et fait appel aux différentes fonctions de sauvegarde ou de scan du programme KinFu.

Voici à quoi ressemble notre interface :

  • L'utilisateur doit tout d'abord saisir la distance maximale en mètre qu'il veut scanner

Démarrage de l'application

  • Ensuite ces différentes fenêtres apparaissent :

Application avec interface

On se rend compte que nous deux applications tournent en parallèle. Il suffit maintenant à l'utilisateur de choisir l'intervalle en secondes entre deux ajouts, de ce que la caméra scanne, au mesh. Puis il appuie sur "scanner" et lorsque son scan est terminé il clique sur le bouton "Sauver au format ply", son travail est alors enregistré et l'application se ferme.

Intégration des couleurs au mesh

Une fois que nous avons réalisé une base d'interface graphique, nous avons voulu ajouter la texture (la couleur) à nos scan. Pour cela nous nous sommes basés sur le fonctionnement de l'application KinFu LargeScale qui possédait déjà l'intégration des couleurs dans ses options grace à l'option -et (enable_texture) -r (registration) dans sa commande :

./bin/pcl_kinfu_largeScale -r -et 

KinFu_Large_Scale fonctionne de la manière suivante :

  • Au cours du scan, l'application prend différentes photos sous le format n°.png, les enregistre dans le dossier KinFuSnapshots/ et ajoute un n°.txt contenant la position de la caméra lors de la prise de la photo. L'application crée à la fin du scan un fichier world.pcd qui est dans cet état inutilisable.
  • Une fois le scan terminé, l'utilisateur doit transformer le .pcd en .ply grâce à la commmande :
./bin/pcl_kinfu_largeScale_mesh_output world.pcd 

Cette commande crée alors plusieurs fichiers .ply en fonction de la durée du scan. Il faut que l'utilisateur fusionne les différents fichiers .ply et enregistre cette fusion dans le dossier KinFuSnapshots/ contenant déjà les différentes photos.

  • Enfin, il doit lancer sur son terminal la commande suivante qui associe les différentes photos au mesh fusionné :
./bin/pcl_kinfu_largeScale_texture_output KinFuSnapshots/merged_mesh.ply 

Les photos sont correctement placées sur le mesh grâce aux différents fichiers .txt qui possèdent les différentes positions

Nous, nous utilisons l'application KinFu_App qui ne contient pas l'option d'intégration des couleurs au mesh. Par conséquent, nous l'avons modifié pour d'une certaine manière fusionner les options -r et -et de KinFu LargeScale avec l'application KinFu_App.

Pour ce faire, nous avons tout d'abord ajouter la prise des photos à notre application. Nous nous sommes rendus compte qu'il existait dans KinFu_Large_Scale une classe "Screenshot_manager" qui permet de prendre et d'enregistrer les photos mais aussi d'enregistrer la position de la caméra. Par conséquent, nous avons ajouter cette classe à KinFu_App.

Nous avons laissé le choix à l'utilisateur d'activer ou pas la prise de ces photos. Nous avons donc ajouté un checkbox au lancement de l'application permettant à l'utilisateur d'activer ou pas cette option. Voici à quoi notre nouvelle interface ressemble :

Ajout de l'option texture

Grâce à cette option, nous appelons la classe "Screenshot_manager" que si elle a été sélectionnée.

Nous nous également rendus compte que KinFu_App crée directement, à la fin du scan, un et un seul fichier .ply. Par conséquent les étapes nécessaires dans KinFu_LargeScale :

./bin/pcl_kinfu_largeScale_mesh_output world.pcd  
./bin/pcl_kinfu_largeScale_texture_output KinFuSnapshots/merged_mesh.ply 

ne sont plus à réaliser dans notre situation. Par conséquent, l'utilisateur ne doit plus que réaliser la commande suivante (dans le dossier KinFuSnapshots/) :

../bin/pcl_kinfu_largeScale_texture_output mesh.ply 

et son mesh possédera la couleur.

Amélioration de la précision

Suite à cela, nous nous sommes replongé dans le code pour essayer de trouver un moyen d'améliorer la précision du scan. En effet, nous nous étions rendus compte lors du "IT Day" que la précision était encore faible et que par exemple, les différents trous qu'il peut y avoir dans un casque n'était pas assez prononcés.

Nous avons trouvé dans la classe kinfu_app.cpp de l'application le paramètre de la fonction setTsdfTruncDist(), qui nous permet en mètre de définir la distance de troncature à partir de laquelle la TSDF (outil qui permet d'assigner une valeur de profondeur à chaque pixel de la grille vue par la caméra, et la compare avec la grille de l’itération précédente) va corriger, approximer les erreurs de scan. Initialement, elle était à 30cm et c'est pour cette raison que la précision restait faible. Nous avons mis cette valeur à 3cm et voici ce que nous obtenons :

Casque précis

On se rend bien compte que les trous du casque sont beaucoup plus prononcés et que la couleur a bien été ajoutée au mesh.

Réunion du lundi 11 février avec Oxylane

Suite à ces différentes avancées, nous avons décidé de fixer un rendez-vous avec Oxylane afin de leur montrer nos travaux. Cet entretien a eu lieu le lundi 11 février.

Lors de ce dernier, Oxylane a pu constater avec joie que nous travaux avaient très bien avancés et ils semblaient de plus en plus satisfait par la qualité des différents scan que nous leur avons montrés. Lors de cette réunion, ils nous ont fournis un zoom Nyko et une Kinect For Windows afin que nous continuons d'essayer d'améliorer la précision.

Test du zoom Nyko et de la Kinect For Windows

Suite à la réunion avec Oxylane, nous avons tout d'abord essayé le zoom Nyko. L'installation fut facile et aucun paramètre dans l'application a dû être modifié. Cependant le résultat que nous obtenons n'a pas répondu à nos attentes. En effet, le zoom Nyko produit un effet de loupe, "d'oeil de poisson" sur la scène et donc la déforme. Voici une comparaison des images capturées par la Kinect sans et avec le zoom Nyko :

Capture sans le zoom Nyko

Capture avec le zoom Nyko

En ce qui concerne la Kinect For Windows, nous n'avons aucune difficulté à l'utiliser sur Linux, les drivers de la Kinect pour Xbox 360 ont suffit. Cependant, nous n'avons pas vu de différences flagrantes entre les deux Kinect.

Amélioration de notre interface graphique

Afin de rendre l'interface plus ergonomique, nous avons décidé de remplacer les boutons "texte" par des boutons icônes. De plus, en améliorant cette interface nous avons ajouté plusieurs fonctions.

  • Le bouton start permet de lancer le scan. Il est transformé en bouton pause lorsqu'il est actionné.
  • Le bouton power permet d'arrêter à tout instant l'application
  • Le bouton reset permet d'effacer toutes les différentes captures qui ont déjà été effectuées (mesh et photos)
  • Le bouton stop devrait être supprimé à moins que nous lui trouvions une utilité
  • Le bouton info permettra d'obtenir des informations sur l'application et éventuellement une aide
  • Le bouton enregistrer permet d'enregistrer le mes au format ply. Nous envisageons d'ajouter des options pour le format d'enregistrement.

Voici à quoi ressemble notre interface :

Notre nouvelle interface