Scansioni 3D effettuate con Tablet Project Tango ed RTAB-MAP con visualizzazione in MeshLab
L'aspetto interessante di utilizzare RTAB-MAP e' che non e' necessario utilizzare una ripresa statica da cavelletto ma si puo' muovere la camera perche' viene gestito il motion tracking. Questo permette di riprendere anche zone che possono risultare "in ombra" da una ripresa frontale
Mentre stavamo parlando dell'uso di Kinect per realizzare modelli 3D un amico mi ha parlato di fare la stessa cosa usando una comune macchina fotografica e la fotogrammetria. Di istinto ero un po' scettico ma ho comunque voluto dare un'occhiata a cosa trovavo su Internet
La mia attenzione e' stata catturata da VisualFSM un programma opensource che funziona su Windows, Mac e Linux (per gli ultimi si deve partire dai sorgenti mentre per Windows si puo' scaricare il compilato direttamente da qui o qui
Per semplicita' ho provato la versione Windows ATTENZIONE: per funzionare il programma ha bisogno delle librerie di CMVS che non sono comprese nel pacchetto (si devono scaricare i compilati da questo link e porre i file cmvs.exe, genOption.exe e pmvs2.exe nel path di Windows ..io non per fare prima li ho messi direttamente in c:\windows\) ed i file ed i programmi devono essere messi all'interno di directory con nomi privi di caratteri speciali...C:\Documents and Settings\ non va bene)
Detto cio' ho fatto una decina di foto a questo edificio da diverse angolazioni
Le operazioni con VisualFSM sono molto semplici
1) Prima si importano le foto da File/Open Multi Image
2) Si effettua il confronto a coppie delle immagini con SfM/Pariwise Matching/Compute Missing Matching
3) SfM/Reconstruct Sparse
4) SfM/Reconstruct Dense (viene chiesto dove salvare un file .nvm
come si osserva non si fornisce nessuna informazioni geometrica
Dopo un po' di calcoli e se le immagini sono sufficienti per la ricostruzione viene creati una serie di file che saranno poi gestiti mediante Meshlab (per riferimento si vada a questo link)3
Questa e' la ricostruzione. La nuvola dei punti non e' molto densa ma per essere il primo tentativo non e' male (si veda per confronto la prima foto)
Ruotando l'immagine si osserva che l'angolo dell'edificio e' stato ricostruito in modo corretto con un angolo molto prossimo ai 90°
Un aspetto interessante e' che questo approccio puo' essere utilizzato anche con immagini riprese da droni
Una volta acquisita una nuvola di punti con Kinect e' necessario processarla per ripulire i dati anomali e passare da una nuvola di punti (PointCloud) ad una superficie (Mesh)
Sono disponibili un paio di software OpenSource
Il primo e' CloudCompare (disponibile per vari OS)
Ricostruzione della superficie con CloudCompare
La superficie reale scansionata
Per la versione Ubuntu si installa mediante PPA con la seguente procedura sudo add-apt-repository ppa:romain-janvier/cloudcompare apt-get update
apt-get cloudcompare
vengono installati due software CloudCompare (il vero e proprio software di elaborazione ed analisi.attenzione alle maiuscole!!) e ccViewer (il solo visualizzatore)
La procedura per generare una mesh da una nuvola di punti in CloudCompare prevede
dal DBTree selezionare la Cloud di interesse
Edit/Normal/Compute
Edit/Mesh/Delanauy 2D
Edit/Color
eventualmente si puo' dare smoothing con
Edit/Mesh/Smooth (Laplacian)
L'alternativa e' Meshlab che si trova direttamente nei repository apt-get install meshlab
anche se in una versione piu' vecchia della corrispondente versione Windows
La stessa nuvola dei punti vista prima ma elaborata in Meshlav
Con Meshlab si ha a disposizione un comodo strumento di misura ma non sono mai riuscito a portare a termine la conversione di una PointCloud in una Mesh perche' il programma crasha (sembra che il numero dei punti sia troppo elevato)
In ogni caso la procedura dovrebbe essere
dal menu Filters Sampling/Possoin Disk sampling /check Base Mesh Subsampling Normals,Curvatures/Compute Normals for Point Sets Point Set/Poisson Reconstruction Cleaning and Repairing/Remove isolated Pieces (wrt face num)
Per completare i testi con il Kinect ho provato a creare uno scanner 3D.
L'oggetto e' stata la caffettiera sotto riportata il cui centro di rotazione e' stato posto a 65 cm dal Kinect ed e' stato ripreso da 4 fotogrammi ruotando ogni volta l'oggetto di 90°
Ovviamente e' stata una prova casalinga e ci sono forti errori di allineamento tra il sensore Kinect e l'asse di rotazione.
L'oggetto reale
La sua scansione (da notare che era posto sopra una scatola)
Per l'acquisizione e' stato usato il seguente script
------------------------------------------------- from openni import * import time import pickle import numpy as np import Image import scipy ctx = Context() ctx.init() # Create a depth generator depth = DepthGenerator() depth.create(ctx) # Set it to VGA maps at 30 FPS depth.set_resolution_preset(RES_VGA) depth.fps = 30 # Start generating ctx.start_generating_all() # Update to next frame nRetVal = ctx.wait_one_update_all(depth) depthMap = depth.map depthMap2 = np.array(depthMap) f = open("ca_2700.txt","w+b") pickle.dump(depthMap2,f) f.close()
-------------------------------------------------
i vari file salvati con pickle sono stati poi trattati con i seguenti programmi (uno ogni 90°, di fatto l'immagine viene centrata e vengono filtrati solo i dati > 0 ed inferiori a 70 cm)
-------------------------------- #!/usr/bin/python import pickle import numpy as np import Image f = open("ca_000.txt") data = pickle.load(f) f.close() t = 0 for y in range(0,480): for x in range (0,640): if ((data[t] < 700) and (data[t]>0)): print str(x-320)+","+str(y-240)+","+str(660-data[t]) t = t + 1
-------------------------------- #!/usr/bin/python import pickle import numpy as np import Image f = open("ca_180.txt") data = pickle.load(f) f.close() t = 0 for y in range(0,480): for x in range (0,640): if ((data[t] < 700) and (data[t]>0)): print str(x-320)+","+str(y-240)+","+str(-(660-data[t])) t = t + 1
-------------------------------- #!/usr/bin/python import pickle import numpy as np import Image f = open("ca_090.txt") data = pickle.load(f) f.close() t = 0 for y in range(0,480): for x in range (0,640): if ((data[t] < 700) and (data[t]>0)): print str(660-data[t]) + "," + str(y-240) + "," + str(x-320) #non funziona t = t + 1
-------------------------------- #!/usr/bin/python import pickle import numpy as np import Image f = open("ca_090.txt") data = pickle.load(f) f.close() t = 0 for y in range(0,480): for x in range (0,640): if ((data[t] < 700) and (data[t]>0)): print str(-(660-data[t])) + "," + str(y-240) + "," + str(x-320) t = t + 1
--------------------------------
L'output e' stato dirottato su file testo che poi sono importati in Meshlab.
Su richiesta di un amico, ho provato ad usare il Kinect per fare un modello 3D del viso
Il lavoro e' diviso in due parti. In fase di acquisizione vengono salvati i dati del sensore di distanza del Kinect ogni 5 secondi (il Kinect genera una mappa di 640x480 punti per ogni immagini ed i dati acquisiti da PyOpenNi sono espressi direttamente in millimetri)
Successivamente si lancia lo script di lettura.py come
python lettura.py > dati.asc
il file .asc viene poi utilizzato dal programma Meshlab (presenti anche repository di Ubuntu) per visualizzare la nuvola dei punti. (Nell'esempio sono stati i punti a distanza maggiore di 1 metro per selezionare solo i punti del volto)