Ho provato a mettere alla prova il Tablet di Project Tango con il Kinect sulle Mura Etrusche a Fiesole gia' utilizzate come bersaglio in questo post
Pur ammettendo una giornata piovosa la prova con il tablet Tango e' stata disastrosa. Il sensore di profondita' e' riuscito ad acquisire al massimo 1100 punti da una distanza compresa tra 1.0 e 1.5 m; allontanandosi non veniva effettuata nessuna acquisizione mediante il software ParaView.
L'idea che mi sono fatto e' che il sensore di profondita' del tablet Tango non risulta avere una potenza di emissione cosi' elevata da avere riflessioni significative su superfici non omogenee e poco riflettenti.
In buona sostanza non e' possibile farne un utilizzo "in campagna" per scopi geologici. Il suo mondo e' il rilevamento di interni
Visualizzazione post con etichetta Kinect. Mostra tutti i post
Visualizzazione post con etichetta Kinect. Mostra tutti i post
mercoledì 11 aprile 2018
giovedì 5 aprile 2018
Project Tango
Visto che il Progetto Tango di Google e' stato dismesso a Marzo 2018 i prezzi dei dispositivi Tango sono scesi ad un livello umano e mi sono preso un Project Tango Tablet Development Kit. In estrema sintesi si tratta di una tablet Android NVidia con processore Tegra K1 e 128 Giga di memoria dotato di sensori simili a quelli del Kinect per il calcolo della distanza degli oggetti inquadrati
Il nome in codice del tablet e' Yellowstone altrimenti conosciuto con la sigla NX-74751 (in Star Trek la nave USS Yellowstone ha il codice NX-74751) ed e' stato sviluppato internamente da Google presso Google's ATAP (Advanced Technology and Projects). Per sapere quale hardware c'e' dentro si rimanda a questo link
Attualmente la documentazione delle API di Tango sono sparite dal sito sviluppatori di Google ma sono sempre recuperabili su Archive.org mentre il codice di esempio e' stato spostato qui. Al momento non sono riuscito a trovare una immagine del firmware da poter scaricare
Il sensore di profondita' e' un OV4682 con una matrice di 320x180 pixels (risoluzione molto lontana dal Kinect) ed ha funzione anche di camera RGB. Ci sono inoltre una camera standard da 4 Megapixels piu' una camera fisheye da 120° ed una da 180° (in totale di sono 4 camere)
Viene riportato che il sensore della bussola non sia funzionante
Il tablet viene fornito con un dock che funziona da ricarica ed ha una porta USB. La porta USB serve solo per connettere eventuali USB drive o simili, non funziona come canale Adb. Inoltre il tablet e' talmente assetato di risorse che se si connette il solo cavo USB (e non l'alimentazione del dock, 12V 2A con connettore positivo al centro del jack) il dispositivo si scarica invece di caricarsi)
Alcune applicazioni gia' pronte risultano essere
Il nome in codice del tablet e' Yellowstone altrimenti conosciuto con la sigla NX-74751 (in Star Trek la nave USS Yellowstone ha il codice NX-74751) ed e' stato sviluppato internamente da Google presso Google's ATAP (Advanced Technology and Projects). Per sapere quale hardware c'e' dentro si rimanda a questo link
Attualmente la documentazione delle API di Tango sono sparite dal sito sviluppatori di Google ma sono sempre recuperabili su Archive.org mentre il codice di esempio e' stato spostato qui. Al momento non sono riuscito a trovare una immagine del firmware da poter scaricare
Il sensore di profondita' e' un OV4682 con una matrice di 320x180 pixels (risoluzione molto lontana dal Kinect) ed ha funzione anche di camera RGB. Ci sono inoltre una camera standard da 4 Megapixels piu' una camera fisheye da 120° ed una da 180° (in totale di sono 4 camere)
OS | Android™ 4.4 (KitKat®) |
Screen | 7.02” 1920x1200 HD IPS display (323 ppi) |
Scratch-resistant Corning® glass | |
Camera | 1 MP front facing, fixed focus |
4 MP 2µm RGB-IR pixel sensor | |
Size | 119.77 x 196.33 x 15.36 mm |
Weight | 0.82 lbs (370 g) |
Battery | 4960 mAH cell (2 x 2480 cells) |
Processor | NVIDIA Tegra K1 with 192 CUDA cores |
Network/Wireless | 4G LTE¹ |
Dual-band Wi-Fi (2.4GHz/5GHz) WiFi 802.11 a/b/g/n | |
Bluetooth 4.0 | |
NFC (reader and peer to peer modes) | |
Memory | 128 GB internal storage (actual formatted capacity will be less) |
4 GB RAM | |
Connectivity | Micro HDMI |
USB 3.0 host via dock connector² | |
Micro SD card | |
Nano SIM slot | |
Sensors | Motion tracking camera |
3D depth sensing | |
Accelerometer | |
Ambient light | |
Barometer | |
Compass | |
aGPS | |
Gyroscope | |
Audio Output | Dual stereo speakers |
3.5 mm audio connector (OMTP) |
Viene riportato che il sensore della bussola non sia funzionante
Il tablet viene fornito con un dock che funziona da ricarica ed ha una porta USB. La porta USB serve solo per connettere eventuali USB drive o simili, non funziona come canale Adb. Inoltre il tablet e' talmente assetato di risorse che se si connette il solo cavo USB (e non l'alimentazione del dock, 12V 2A con connettore positivo al centro del jack) il dispositivo si scarica invece di caricarsi)
Alcune applicazioni gia' pronte risultano essere
- App Discovery Project Tango
- Room Scanner
- RTAB-Map (permette esportazione in ply)
- Tango Scan View (converte i file OBJ in PLY)
- ADF Tools
- Tango Explorer
- Java Point Cloud Example (dagli esempi Java)
Scansione con RTAB-Map visualizzata con MeshLab |
Per ottenere i permessi di root si usa TangoRoot e ChainFireSU (io non sono riuscito ad eseguire il root perche' Android continua a dire che e' TangoRoot e' una applicazione pericolosa e non la mette in esecuzione)
I dati delle immagini di profondita' vengono immagazzinati di default in formato super compresso binario proprietario ADF che risulta poco documentato. In ogni caso ci sono applicazione di terze parti che esportano in formati piu' comuni come PLY. La directory di salvataggio dei file ADF e' mutata nel tempo ma in ogni caso sembra richiedere i permessi di root
I dati delle immagini di profondita' vengono immagazzinati di default in formato super compresso binario proprietario ADF che risulta poco documentato. In ogni caso ci sono applicazione di terze parti che esportano in formati piu' comuni come PLY. La directory di salvataggio dei file ADF e' mutata nel tempo ma in ogni caso sembra richiedere i permessi di root
lunedì 26 marzo 2018
Vettore normale su nuvola di punti
Il problema e' questo : data una nuvola di punti, generata da un sensore come Kinect, determinare i vettori normali delle superfici triangolari che hanno come vertici i punti della nuvola stessa.
Il sistema di coordinate ha l'asse Z orientato come la distanza dal sensore, X ed Y invece sono lungo la dimensione della matrice di acquisizione
Presi tre punti nello spazio (x1,y1,z1),(x2,y2,z2),(x3,y3,z3) non allineati (questa condizione visto che i dati vengono da uno strumento di misura reale diciamo che e' soddisfatta a priori) per calcolare l'equazione del piano si deve calcolare il determinante della seguente matrice con la condizione che sia uguale a zero
(x-x1, y-y1, z-z1,
x2-x1, y2-y1, z2-z1,
x3-x2, y3-y2, z3-z2)
con la formula di Laplace per il determinante si ha che (x,y,z sono le variabili)
(x-x1)[(y2-y1)(z3-z1)-(y3-y1)(z2-z2)] - (y-y1)[(x2-x1)(z3-z1)-(x3-x1)(z2-z1)]+ (z-z1)[(x2-x1)(y3-y1)-(x3-x1)(y2-y1)]= 0
si ha cosi' un risultato nella forma
Il sistema di coordinate ha l'asse Z orientato come la distanza dal sensore, X ed Y invece sono lungo la dimensione della matrice di acquisizione
Presi tre punti nello spazio (x1,y1,z1),(x2,y2,z2),(x3,y3,z3) non allineati (questa condizione visto che i dati vengono da uno strumento di misura reale diciamo che e' soddisfatta a priori) per calcolare l'equazione del piano si deve calcolare il determinante della seguente matrice con la condizione che sia uguale a zero
(x-x1, y-y1, z-z1,
x2-x1, y2-y1, z2-z1,
x3-x2, y3-y2, z3-z2)
con la formula di Laplace per il determinante si ha che (x,y,z sono le variabili)
(x-x1)[(y2-y1)(z3-z1)-(y3-y1)(z2-z2)] - (y-y1)[(x2-x1)(z3-z1)-(x3-x1)(z2-z1)]+ (z-z1)[(x2-x1)(y3-y1)-(x3-x1)(y2-y1)]= 0
si ha cosi' un risultato nella forma
ax+by+cz = 0
una volta calcolato il piano si deve calcolare la normale (nx,ny,nz)si calcola la derivata parziale
F = ax +by+cz
nx = dF/dx, ny = dF/dy, nz = dF/dz.
Visto che si tratta di un piano la derivata parziale e' banale e le componenti del vettore normale sono (a,b,c)
-----------------------------------------------------------
Un metodo alternativo (che non prevede di calcolare prima l'equazione di un piano) e' quella di calcolare il prodotto vettoriale tra i due del triangolo). Per esempio dati sempre i tre punti (x1,y1,z1),(x2,y2,z2),(x3,y3,z3) si prendono due vettori
v = (x2-x1, y2-y1, z2-z1)
w = (x3-x1, y3-y1, y3-y1)
il vettore normale e' dato dal determinante della matrice
(x,y,z
v1 ,v2 ,v3,
w1,w2,w2)
n = u X v = (v2w3-v3w2)x+(v3w1-v1w3)y+(v1w2-v2w1)z
Adesso c'e il problema e' di normali ce ne sono due essendo la superficie orientata (brutalmente una sotto ed una sopra al piano) oppure nel prodotto vettoriale dipende dall'ordine con cui si pongono i vettori (vXw e' diverso da wXv)
A questo punto si puo' procedere normalizzando il vettore.
nn1 = n1/sqrt(n1n1+n2n2+n3n3)
nn2 = n2/sqrt(n1n1+n2n2+n3n3)
nn3 = n3/sqrt(n1n1+n2n2+n3n3)
il passaggio da coordinate cartesiane a coordinate.
A questo punto si puo' procedere normalizzando il vettore.
nn1 = n1/sqrt(n1n1+n2n2+n3n3)
nn2 = n2/sqrt(n1n1+n2n2+n3n3)
nn3 = n3/sqrt(n1n1+n2n2+n3n3)
il passaggio da coordinate cartesiane a coordinate.
Se si guarda la libreria PCL la ricostruzione della normale ad una superficie viene effettuata mediante il calcolo delle componenti principali che permette anche di gestire anche che l'orientazione delle normali sia coerente
giovedì 26 marzo 2015
Kinect v1 vs Kinect v2
Un po' di considerazioni sulla differenza tra Kinect 1 e Kinect2
Le maggiori differenze sono a livello dell'immagine RGB, passata da 640x480 a 1920x1080, ed IR, molto migliorata perche' e' presente in K2 un illuminatore infrarosso che rende la scena leggibile anche nel buio completo.
Per quanto riguarda il sensore di profondita' in K2 la matrice e' passata da 320x240 a 514x424 ma a causa dell'aumento dell'angolo di vista la densita' di punti per grado angolare e' solo passata da 5x5 pixel/grado a 7x7 pixel grado. Rimangono i problemi di acquisire la profondita' su oggetti molto scuri o di materiali particolari per cui la scena di profondita' puo' presentare dei buchi
Per prova ho ripreso in profondita' questi due oggetti, in particolare ero interessato a vedere se Kinect 2 riesce a vedere meglio i pulsanti del telecomando
Le maggiori differenze sono a livello dell'immagine RGB, passata da 640x480 a 1920x1080, ed IR, molto migliorata perche' e' presente in K2 un illuminatore infrarosso che rende la scena leggibile anche nel buio completo.
Per quanto riguarda il sensore di profondita' in K2 la matrice e' passata da 320x240 a 514x424 ma a causa dell'aumento dell'angolo di vista la densita' di punti per grado angolare e' solo passata da 5x5 pixel/grado a 7x7 pixel grado. Rimangono i problemi di acquisire la profondita' su oggetti molto scuri o di materiali particolari per cui la scena di profondita' puo' presentare dei buchi
Per prova ho ripreso in profondita' questi due oggetti, in particolare ero interessato a vedere se Kinect 2 riesce a vedere meglio i pulsanti del telecomando
Questa e' la visione di profondita' di K1
mentre questa e' la visione di profondita' di K2
Non ci sono sensibili miglioramenti a parte il fatto che K2 produce una mappa piu' smussata perche' registra anche i decimi di millimetro
martedì 17 marzo 2015
CloudCompare e Kinect
Dopo un anno e qualcosa a cercare di installare tutti i pacchetti per usare Kinect su Linux ed oggi ho scoperto che installando CloudCompare tramite ppa su Ubuntu 14.04 viene inserito anche un comodo plugin per pilotare Kinect e per ottenere direttamente la nuvola dei punti gia' registrata con l'immagine RGB
saperlo prima era qualche mal di testa di meno...
giovedì 26 febbraio 2015
Da Kinect a Stampante 3D per paleontologia
Grazie ad un amico sono riuscito ad utilizzare una stampante a 3D.
Lo scopo era quello di, partendo da un fossile, effettuare una scansione 3D con Kinect e poi ottenere nuovamente un modello fisico mediante la stampante 3D
Kinect non e' molto adatto a questo scopo perche' ha un precisione sull'asse verticale di 1 mm e non per modelli piccoli si perde molta risoluzione
Inoltre, dato che la plastica per la stampa 3D e' costosa, mi e' stato concessa una prova su un modello molto ridotto ed alla risoluzione peggiore
La stampa e' durata una 40 (video in tempo estremamente accelerato)
Lo scopo era quello di, partendo da un fossile, effettuare una scansione 3D con Kinect e poi ottenere nuovamente un modello fisico mediante la stampante 3D
Kinect non e' molto adatto a questo scopo perche' ha un precisione sull'asse verticale di 1 mm e non per modelli piccoli si perde molta risoluzione
Inoltre, dato che la plastica per la stampa 3D e' costosa, mi e' stato concessa una prova su un modello molto ridotto ed alla risoluzione peggiore
La stampa e' durata una 40 (video in tempo estremamente accelerato)
venerdì 2 gennaio 2015
Skanect
Un po' di tempo fa avevo fatto degli esperimenti con Freenect (qui, qui e qui) ma cio' che mancava era la fusione tra il dato di profondita' e quello della foto
Mi e' stato segnalato il softwareSkanect (disponibile su Windows, Mac e Linux) che fa esattamente quanto richiesto (un esempio nel video soprastante, il soggetto e' quello che e'......)
Il programma e' costoso ma per un uso semiprofessionale puo' valere la spesa.
Mi e' stato segnalato il softwareSkanect (disponibile su Windows, Mac e Linux) che fa esattamente quanto richiesto (un esempio nel video soprastante, il soggetto e' quello che e'......)
Il programma e' costoso ma per un uso semiprofessionale puo' valere la spesa.
giovedì 5 giugno 2014
Kinect per paleontologia
Continuando la serie delle prove di Kinect come scanner 3D, e' stata provata una applicazione per paleontologia. L'oggetto scansionato e' un corno di cervo (piuttosto malridotto) parzialmente ancora inglobato in matrice argillosa
La scansione e' molto ravvicinata (circa 80 cm) e la scena e' stata tagliata per estrarre il solo dettaglio di interesse
Il colore blu indica le zone piu' vicine al sensore mentre il rosso/arancione sono le zone piu' lontane (ovvero il piano di appoggio)
Il file originale puo' essere scaricato a questo indirizzo
La scansione e' molto ravvicinata (circa 80 cm) e la scena e' stata tagliata per estrarre il solo dettaglio di interesse
Il colore blu indica le zone piu' vicine al sensore mentre il rosso/arancione sono le zone piu' lontane (ovvero il piano di appoggio)
Il file originale puo' essere scaricato a questo indirizzo
giovedì 22 maggio 2014
Visualizzare PointCloud via Web
Sempre giocando con Kinect mi sono imbattuto in Point Cloud Web Viewer, uno strumeno in WebGL che gestisce anche file di generose dimensioni
Per poter utilizzare e visualizzare i propri dati le uniche impostazioni importanti sono quelle relative alla posizione della telecamera (un cattivo orientamento della telecamera risultera' in uno schermo nero) che si trova alle righe 35,36 del file index.html
L'immagine e' navigabile via mouse o tastiera per cambiare l'orientazione
Per poter utilizzare e visualizzare i propri dati le uniche impostazioni importanti sono quelle relative alla posizione della telecamera (un cattivo orientamento della telecamera risultera' in uno schermo nero) che si trova alle righe 35,36 del file index.html
L'immagine e' navigabile via mouse o tastiera per cambiare l'orientazione
mercoledì 7 maggio 2014
Kinect per Belle Arti
Come si puo' osservare i risultati sono buoni (anche se un po' rumorosi) e le scansioni permettono si osservare dettagli anche molto fini
Fregio 1
Immagine di profondita' |
Immagine RGB (da fotocamera) |
Fregio 2
Immagine di profondita' |
Immagine RGB da Kinect |
mercoledì 23 aprile 2014
Accuratezza del sensore di distanza di Kinect (3)
Sempre per cercare di capire quale sono i limiti del Kinect ho provato a riprendere un muro il piu' possibile in modo perpendicolare
Il risultato e' chiaramente visibile nell'immagine. Anche si tratta di uno zoom piuttosto estremo si vede che l'immagine e' rumorosa con valori anche di +/-2,3 mm millimetri rispetto al valore medio
Il risultato e' chiaramente visibile nell'immagine. Anche si tratta di uno zoom piuttosto estremo si vede che l'immagine e' rumorosa con valori anche di +/-2,3 mm millimetri rispetto al valore medio
martedì 22 aprile 2014
Prova Kinect sulle Mura Etrusche di Fiesole
Con lo stesso sistema del precedente post ho provato a scansionare le Mura Etrusche di Fiesole
Link ai dati
Di seguito i risultati (decisamente incoraggianti) con il confronto tra l'immagine RGB e la Mesh dei dati di profondita' (elaborati con CloudCompare)
Link ai dati
Kinect per geologia
Attrezzatura da campagna |
Visto che il Kinect ha necessita' di una alimentazione esterna ho preso un inverter della Belkin da 130 W che ha svolto egregiamente il proprio lavoro (il portatile era alimentato mediante la propria batteria)
Le misure sono state effettuate in condizioni di pioggia battente ed affioramenti bagnati (tanto per rendere le condizioni di misura estreme). E' stato verificato che oltre il metro di distanza i risultati erano scarsi probabilmente perche' la roccia bagnata assorbe molto di piu' il laser che in condizioni asciutte e quindi non permette di calcolare la distanza
Foto ad alta risoluzione da cellulare del primo affioramento |
Confronto tra immagine RGB e Mesh |
E' stato effettuato un altro rilievo in condizioni ancora peggiori perche' la superficie di affioramento non era ortogonale ma molto inclinata rispetto alla verticale
Immagine RGB da Kinect |
Elaborazione Mesh della CloudPoint da Kinect |
Qui si possono scaricare i dati originali (per un problema di acquisizione le immagini RGB sono specchiate lungo l'asse maggiore, nel post le immagini sono state corrette)
lunedì 21 aprile 2014
Programma completo per Kinect
Utilizzando tutte le esperienze precedenti (1,2) ho scritto questo programmino che salva in un colpo solo tutti i parametri di Kinect
lo script deve essere lanciato con una stringa argomento che diventa il nome del progetto.
per esempio
./acquisizione test
genera poi i file
test_angolo.txt
test_rgb.jpg
test_cloud.asc
test_cloud.txt
nel file _angolo.txt sono salvati gli angolo di pitch, roll, la distanza al centro dell'immagine ed il numero di punti della nuvola che risultano corretti (non tutti i pixel di una ascquisizione con il laser risultano corretti, valori attorno al 70% sono gia' ottimali
nel file _rgb.rgb viene salvata una fotografia della scansione. Attenzione: in alcuni casi ci sono problemi di sincronia per cui questa immagine puo' risultare tagliata o mescolata al frame precedente
nel file _cloud.asc sono riportati i valori in x,y,z in millimetri della scansione gia' pronti per essere inclusi in Meshlab o Cloudcompare
il file _cloud.txt e' l'acquisizione della nuvola dei punti pura senza elaborazione e serve nel caso ci siano problemi al punto precedente
il ritardo iniziale serve solo a dare il tempo all'operatore di mettersi in posizione con il kinect
--------------------------------------
#!/usr/bin/python
import usb.core
import usb.util
import sys
import time
import math
from openni import *
from PIL import Image
import numpy as np
import pickle
print "10 secondi alla misura"
time.sleep(5)
print "5 secondi alla misura"
time.sleep(5)
print "Inizio misura"
stringa = sys.argv[1]
print "Progetto : "+stringa
dev = usb.core.find(idVendor=0x045e, idProduct=0x02B0)
if dev is None:
raise ValueError('Device not found')
for cfg in dev:
sys.stdout.write("Configuration #"+str(cfg.bConfigurationValue) + '\n')
for intf in cfg:
sys.stdout.write('\tInterface #' + \
str(intf.bInterfaceNumber) + \
'\t, Alternate setting ' + \
str(intf.bAlternateSetting) + \
'\n')
sys.stdout.write("\tEndpoints:\n")
for ep in intf:
sys.stdout.write('\t\t' + \
str(ep.bEndpointAddress) + \
'\n')
dev.set_configuration()
ret = dev.ctrl_transfer(0xC0, 0x10, 0x0, 0x0, 1)
ret = dev.ctrl_transfer(0x40, 0x6, 0x1, 0x0, [])
#calcola l'angolo
ret = dev.ctrl_transfer(0xC0, 0x32, 0x0, 0x0, 10)
x = (ret[2] << 8) | ret[3]
x = (x + 2**15) % 2**16 - 2**15 # convert to signed 16b
y = (ret[4] << 8) | ret[5]
y = (y + 2**15) % 2**16 - 2**15 # convert to signed 16b
z = (ret[6] << 8) | ret[7]
z = (z + 2**15) % 2**16 - 2**15 # convert to signed 16b
pitch = math.atan2(y,x)*(180/3.1415926)
roll = math.atan2(y,math.sqrt((x*x)+(z*z)))*(180/3.1415926)
if (z <0):
roll = 90+(90-roll)
#immagine rgb e profondita'
ctx = Context()
ctx.init()
depth = DepthGenerator()
rgb = ImageGenerator()
depth.create(ctx)
rgb.create(ctx)
depth.set_resolution_preset(RES_VGA)
depth.fps = 30
rgb.set_resolution_preset(RES_VGA)
rgb.fps = 30
ctx.start_generating_all()
ctx.wait_one_update_all(rgb)
im = Image.fromstring('RGB',(640,480),rgb.get_raw_image_map())
im.save(stringa+"_rgb.jpg")
print "RGB salvata"
#ctx.wait_one_update_all(depth)
#de = Image.fromstring('L',(640,480),depth.get_raw_depth_map_8())
#de.save(stringa+"_depth.jpg")
#print "Depth salvata"
time.sleep(0.5)
#mappa_punti
ctx.wait_one_update_all(depth)
depthMap = depth.map
depthMap2 = np.array(depthMap)
f = open(stringa+"_cloud.txt","w")
pickle.dump(depthMap2,f)
f.close()
f = open(stringa+"_cloud.txt")
data = pickle.load(f)
f.close()
g = open(stringa+"_cloud.asc","w")
t = 0
d = 0
alfa = -0.5105088 # angolo lungo x
delta_a = 0.00159534 # delta alfa
beta = 0.397935 # angolo lungo beta
delta_b = 0.001658052 # delta beta
dis_c = data[153600] # distanza del punto centrale 320x240
print "Distanza media "+str(dis_c) + " mm"
for y in range(0,480):
alfa = -0.5105088
for x in range (0,640):
if (data[t] !=0):
g.write(str(dis_c*math.tan(alfa))+","+str(dis_c*math.tan(beta))+","+str(data[t])+"\n")
d = d + 1
t=t+1
alfa = alfa + delta_a
beta = beta - delta_b
g.close()
perc = (d/307200.0)*100
print "Nuvola dei punti salvati"
print "Punti validi : " + str(round(perc,1)) + "%"
out = open(stringa + "_angolo.txt","w")
out.write("Pitch: "+str(round(pitch,1))+", Roll : "+str(round(roll,1))+", Distanza : "+str(dis_c)+" mm, Punti validi :"+str(round(perc,1))+"% \n")
out.close()
print "Angoli salvati"
lo script deve essere lanciato con una stringa argomento che diventa il nome del progetto.
per esempio
./acquisizione test
genera poi i file
test_angolo.txt
test_rgb.jpg
test_cloud.asc
test_cloud.txt
nel file _angolo.txt sono salvati gli angolo di pitch, roll, la distanza al centro dell'immagine ed il numero di punti della nuvola che risultano corretti (non tutti i pixel di una ascquisizione con il laser risultano corretti, valori attorno al 70% sono gia' ottimali
nel file _rgb.rgb viene salvata una fotografia della scansione. Attenzione: in alcuni casi ci sono problemi di sincronia per cui questa immagine puo' risultare tagliata o mescolata al frame precedente
nel file _cloud.asc sono riportati i valori in x,y,z in millimetri della scansione gia' pronti per essere inclusi in Meshlab o Cloudcompare
il file _cloud.txt e' l'acquisizione della nuvola dei punti pura senza elaborazione e serve nel caso ci siano problemi al punto precedente
il ritardo iniziale serve solo a dare il tempo all'operatore di mettersi in posizione con il kinect
--------------------------------------
#!/usr/bin/python
import usb.core
import usb.util
import sys
import time
import math
from openni import *
from PIL import Image
import numpy as np
import pickle
print "10 secondi alla misura"
time.sleep(5)
print "5 secondi alla misura"
time.sleep(5)
print "Inizio misura"
stringa = sys.argv[1]
print "Progetto : "+stringa
dev = usb.core.find(idVendor=0x045e, idProduct=0x02B0)
if dev is None:
raise ValueError('Device not found')
for cfg in dev:
sys.stdout.write("Configuration #"+str(cfg.bConfigurationValue) + '\n')
for intf in cfg:
sys.stdout.write('\tInterface #' + \
str(intf.bInterfaceNumber) + \
'\t, Alternate setting ' + \
str(intf.bAlternateSetting) + \
'\n')
sys.stdout.write("\tEndpoints:\n")
for ep in intf:
sys.stdout.write('\t\t' + \
str(ep.bEndpointAddress) + \
'\n')
dev.set_configuration()
ret = dev.ctrl_transfer(0xC0, 0x10, 0x0, 0x0, 1)
ret = dev.ctrl_transfer(0x40, 0x6, 0x1, 0x0, [])
#calcola l'angolo
ret = dev.ctrl_transfer(0xC0, 0x32, 0x0, 0x0, 10)
x = (ret[2] << 8) | ret[3]
x = (x + 2**15) % 2**16 - 2**15 # convert to signed 16b
y = (ret[4] << 8) | ret[5]
y = (y + 2**15) % 2**16 - 2**15 # convert to signed 16b
z = (ret[6] << 8) | ret[7]
z = (z + 2**15) % 2**16 - 2**15 # convert to signed 16b
pitch = math.atan2(y,x)*(180/3.1415926)
roll = math.atan2(y,math.sqrt((x*x)+(z*z)))*(180/3.1415926)
if (z <0):
roll = 90+(90-roll)
#immagine rgb e profondita'
ctx = Context()
ctx.init()
depth = DepthGenerator()
rgb = ImageGenerator()
depth.create(ctx)
rgb.create(ctx)
depth.set_resolution_preset(RES_VGA)
depth.fps = 30
rgb.set_resolution_preset(RES_VGA)
rgb.fps = 30
ctx.start_generating_all()
ctx.wait_one_update_all(rgb)
im = Image.fromstring('RGB',(640,480),rgb.get_raw_image_map())
im.save(stringa+"_rgb.jpg")
print "RGB salvata"
#ctx.wait_one_update_all(depth)
#de = Image.fromstring('L',(640,480),depth.get_raw_depth_map_8())
#de.save(stringa+"_depth.jpg")
#print "Depth salvata"
time.sleep(0.5)
#mappa_punti
ctx.wait_one_update_all(depth)
depthMap = depth.map
depthMap2 = np.array(depthMap)
f = open(stringa+"_cloud.txt","w")
pickle.dump(depthMap2,f)
f.close()
f = open(stringa+"_cloud.txt")
data = pickle.load(f)
f.close()
g = open(stringa+"_cloud.asc","w")
t = 0
d = 0
alfa = -0.5105088 # angolo lungo x
delta_a = 0.00159534 # delta alfa
beta = 0.397935 # angolo lungo beta
delta_b = 0.001658052 # delta beta
dis_c = data[153600] # distanza del punto centrale 320x240
print "Distanza media "+str(dis_c) + " mm"
for y in range(0,480):
alfa = -0.5105088
for x in range (0,640):
if (data[t] !=0):
g.write(str(dis_c*math.tan(alfa))+","+str(dis_c*math.tan(beta))+","+str(data[t])+"\n")
d = d + 1
t=t+1
alfa = alfa + delta_a
beta = beta - delta_b
g.close()
perc = (d/307200.0)*100
print "Nuvola dei punti salvati"
print "Punti validi : " + str(round(perc,1)) + "%"
out = open(stringa + "_angolo.txt","w")
out.write("Pitch: "+str(round(pitch,1))+", Roll : "+str(round(roll,1))+", Distanza : "+str(dis_c)+" mm, Punti validi :"+str(round(perc,1))+"% \n")
out.close()
print "Angoli salvati"
FOV IR Camera di Kinect
La camera infrarossa del Kinect (che viene usata per calcolare la mappa di distanza) ha una FOV (Field of View) di 58.5°x45.6° per una risoluzione di 640x480
Tradotto in radianti (prendendo come origine degli assi il centro dell'immagine) si ha che
alfa (angolo lungo l'asse maggiore) = +/- 0.510588 rad
beta (angolo lungo l'asse minore= +/- 0.397935 rad
dividendo per la risoluzione in pixel si hanno del dimensioni di ogni pixel
delta_alfa = 0.00159534
delta_beta = 0.001658052
Per calcolare la reale dimesione di ogni pixel, considerando un caso semplice ovvero una immagine piatta e ortogonale al sensore, le misure reali si possono calcolare come
dis_c = distanza del punto centrale dell'immagine
x_reale = dis_c * tg(alfa)
y_reale = dis_c * tg(beta)
ad una distanza di 80 cm la finestra di kinect risulta essere di 130x81 cm ovvero circa 1 metro quadrato.
tradotto in Python
----------------------------------------------------------
alfa = -0.5105088 # angolo lungo x
delta_a = 0.00159534 # delta alfa
beta = 0.397935 # angolo lungo beta
delta_b = 0.001658052 # delta beta
dis_c = data[153600] # distanza del punto centrale 320x240
print "Distanza media "+str(dis_c) + " mm"
for y in range(0,480):
alfa = -0.5105088
for x in range (0,640):
if (data[t] !=0):
g.write(str(dis_c*math.tan(alfa))+","+str(dis_c*math.tan(beta))+","+str(data[t])+"\n")
t=t+1
alfa = alfa + delta_a
beta = beta - delta_b
----------------------------------------------------------
Tradotto in radianti (prendendo come origine degli assi il centro dell'immagine) si ha che
alfa (angolo lungo l'asse maggiore) = +/- 0.510588 rad
beta (angolo lungo l'asse minore= +/- 0.397935 rad
dividendo per la risoluzione in pixel si hanno del dimensioni di ogni pixel
delta_alfa = 0.00159534
delta_beta = 0.001658052
Per calcolare la reale dimesione di ogni pixel, considerando un caso semplice ovvero una immagine piatta e ortogonale al sensore, le misure reali si possono calcolare come
dis_c = distanza del punto centrale dell'immagine
x_reale = dis_c * tg(alfa)
y_reale = dis_c * tg(beta)
ad una distanza di 80 cm la finestra di kinect risulta essere di 130x81 cm ovvero circa 1 metro quadrato.
tradotto in Python
----------------------------------------------------------
alfa = -0.5105088 # angolo lungo x
delta_a = 0.00159534 # delta alfa
beta = 0.397935 # angolo lungo beta
delta_b = 0.001658052 # delta beta
dis_c = data[153600] # distanza del punto centrale 320x240
print "Distanza media "+str(dis_c) + " mm"
for y in range(0,480):
alfa = -0.5105088
for x in range (0,640):
if (data[t] !=0):
g.write(str(dis_c*math.tan(alfa))+","+str(dis_c*math.tan(beta))+","+str(data[t])+"\n")
t=t+1
alfa = alfa + delta_a
beta = beta - delta_b
----------------------------------------------------------
Per verificare che i calcoli siano corretti ho ripreso un oggetto di dimensioni conosciute ovvero un libro di 292x205 mm ad una distanza di 1342 mm (centro immagine)
Immagine RGB |
CloudP Point in Meshlab |
|
Come si deve le dimensioni misurate risultano essere 288mmx198mm a conferma di come i calcoli siano corretti
martedì 15 aprile 2014
Accelerometro su Kinect
Kinect e' fornita di un accelerometro a 3 assi che secondo quando riportato da IFixIt dovrebbe essere un modello KXSD9 di Kionix
Per leggere i dati dell'accelorometro in Python si puo' usare il seguente script (ripreso da qui)
Attenzione: per funzionare e' necessario utilizzare PyUsb alla versione unstable 1.0 e non quella stable 0.4 che normalmente e' pacchettizzata per Linux
Prima e' quindi necessario scaricare il pacchetto unstable da GitHub
(installarea con il classico python setup.py install)
Lo script e' un demo anche per muovere il motore di tilt del Kinect
------------------------------------------------------
import usb.core
import usb.util
import sys
import time
# find our device
dev = usb.core.find(idVendor=0x045e, idProduct=0x02B0)
# was it found?
if dev is None:
raise ValueError('Device not found')
for cfg in dev:
sys.stdout.write("Configuration #"+str(cfg.bConfigurationValue) + '\n')
for intf in cfg:
sys.stdout.write('\tInterface #' + \
str(intf.bInterfaceNumber) + \
'\t, Alternate setting ' + \
str(intf.bAlternateSetting) + \
'\n')
sys.stdout.write("\tEndpoints:\n")
for ep in intf:
sys.stdout.write('\t\t' + \
str(ep.bEndpointAddress) + \
'\n')
# set the active configuration. With no arguments, the first
# configuration will be the active one
dev.set_configuration()
# (bmRequestType, bmRequestType, bmRequest, wValue, wIndex, nBytes)
ret = dev.ctrl_transfer(0xC0, 0x10, 0x0, 0x0, 1)
print hex(ret[0]) # should return 0x22 but dont know why ?
# ???
ret = dev.ctrl_transfer(0x40, 0x6, 0x1, 0x0, [])
time.sleep(1.5)
# head up!
ret = dev.ctrl_transfer(0x40, 0x31, 0xfff0, 0x0, [])
time.sleep(1.5)
# bring head down
ret = dev.ctrl_transfer(0x40, 0x31, 0xffd0, 0x0, [])
time.sleep(1.5)
# up!
ret = dev.ctrl_transfer(0x40, 0x31, 0xfff0, 0x0, [])
time.sleep(1.5)
# down!
ret = dev.ctrl_transfer(0x40, 0x31, 0xffd0, 0x0, [])
time.sleep(1.5)
# up!
ret = dev.ctrl_transfer(0x40, 0x31, 0xfff0, 0x0, [])
while True:
# Get accel data
ret = dev.ctrl_transfer(0xC0, 0x32, 0x0, 0x0, 10)
#print map(hex, ret)
# bytes 0 & 1 are always zero
x = (ret[2] << 8) | ret[3]
x = (x + 2**15) % 2**16 - 2**15 # convert to signed 16b
y = (ret[4] << 8) | ret[5]
y = (y + 2**15) % 2**16 - 2**15 # convert to signed 16b
z = (ret[6] << 8) | ret[7]
z = (z + 2**15) % 2**16 - 2**15 # convert to signed 16b
print x, "\t", y, "\t", z
time.sleep(0.5)
------------------------------------------------------
(attenzione l'asse x dello script in Python coincide con l'asse Z della codifica Microsoft mentre l'asse z dello script in Python corrisponde con quello X della codifica Microsoft)
L'asse Z Microsoft mostra la rotazione destra/sinistra (mettendo di fronte al kinect appoggiato sul tavolo) e ruotando di 90° verso sinistra mostra valori positivi di 858 unita' mentre ruotando a destra di -797 unita'
L'asse X mostra la rotazione con valori di +779 unita' per posizione a 90° con i sensori che guardano lo zenith mentre di -865 unita' con i sensori che guardano nadir
Se si continua la rotazione oltre i 90° i valori tornano a decrescere verso il valore 0. Per capire se il sensore sta guardando avanti od indietro (ovvero se e' appoggiato alla sua basetta od e' appeso alla sua basetta) vengono usati i valori dell'asse Y Microsoft (y Python) che sono positivi se il Kinect guarda avanti e negativi se guarda indietro
Sembra quindi che i valori letti debbano essere confinati tra 0 ed 819 mentre le mie letture eccedono questo valore. Se si calcola il valore medio tra la misura maggiore e minore si ha che
asse Z (858+797)/2 = 827
asse X (779+865)/2=822
quindi considerando l'incertezza (vedi sotto) c'e' solo da calcolare un piccolo offset dello zero ed i valori coincidono con quelli di fabbrica
Mantenendo fermo il kinect ho effettuato oltre 14200 misure ed ho ottenuto una deviazione standard dei dati nei vari assi come segue
Per leggere i dati dell'accelorometro in Python si puo' usare il seguente script (ripreso da qui)
Attenzione: per funzionare e' necessario utilizzare PyUsb alla versione unstable 1.0 e non quella stable 0.4 che normalmente e' pacchettizzata per Linux
Prima e' quindi necessario scaricare il pacchetto unstable da GitHub
(installarea con il classico python setup.py install)
Lo script e' un demo anche per muovere il motore di tilt del Kinect
------------------------------------------------------
import usb.core
import usb.util
import sys
import time
# find our device
dev = usb.core.find(idVendor=0x045e, idProduct=0x02B0)
# was it found?
if dev is None:
raise ValueError('Device not found')
for cfg in dev:
sys.stdout.write("Configuration #"+str(cfg.bConfigurationValue) + '\n')
for intf in cfg:
sys.stdout.write('\tInterface #' + \
str(intf.bInterfaceNumber) + \
'\t, Alternate setting ' + \
str(intf.bAlternateSetting) + \
'\n')
sys.stdout.write("\tEndpoints:\n")
for ep in intf:
sys.stdout.write('\t\t' + \
str(ep.bEndpointAddress) + \
'\n')
# set the active configuration. With no arguments, the first
# configuration will be the active one
dev.set_configuration()
# (bmRequestType, bmRequestType, bmRequest, wValue, wIndex, nBytes)
ret = dev.ctrl_transfer(0xC0, 0x10, 0x0, 0x0, 1)
print hex(ret[0]) # should return 0x22 but dont know why ?
# ???
ret = dev.ctrl_transfer(0x40, 0x6, 0x1, 0x0, [])
time.sleep(1.5)
# head up!
ret = dev.ctrl_transfer(0x40, 0x31, 0xfff0, 0x0, [])
time.sleep(1.5)
# bring head down
ret = dev.ctrl_transfer(0x40, 0x31, 0xffd0, 0x0, [])
time.sleep(1.5)
# up!
ret = dev.ctrl_transfer(0x40, 0x31, 0xfff0, 0x0, [])
time.sleep(1.5)
# down!
ret = dev.ctrl_transfer(0x40, 0x31, 0xffd0, 0x0, [])
time.sleep(1.5)
# up!
ret = dev.ctrl_transfer(0x40, 0x31, 0xfff0, 0x0, [])
while True:
# Get accel data
ret = dev.ctrl_transfer(0xC0, 0x32, 0x0, 0x0, 10)
#print map(hex, ret)
# bytes 0 & 1 are always zero
x = (ret[2] << 8) | ret[3]
x = (x + 2**15) % 2**16 - 2**15 # convert to signed 16b
y = (ret[4] << 8) | ret[5]
y = (y + 2**15) % 2**16 - 2**15 # convert to signed 16b
z = (ret[6] << 8) | ret[7]
z = (z + 2**15) % 2**16 - 2**15 # convert to signed 16b
print x, "\t", y, "\t", z
time.sleep(0.5)
------------------------------------------------------
(attenzione l'asse x dello script in Python coincide con l'asse Z della codifica Microsoft mentre l'asse z dello script in Python corrisponde con quello X della codifica Microsoft)
Leggendo i dati si ha che non e' presente un sensore di azimuth per cui non e' possibile avere una orientazione nello spazio kinect. In pratica non e' possibile distinguere la rotazione sull'asse Y
Sito Microsoft |
L'asse Z Microsoft mostra la rotazione destra/sinistra (mettendo di fronte al kinect appoggiato sul tavolo) e ruotando di 90° verso sinistra mostra valori positivi di 858 unita' mentre ruotando a destra di -797 unita'
L'asse X mostra la rotazione con valori di +779 unita' per posizione a 90° con i sensori che guardano lo zenith mentre di -865 unita' con i sensori che guardano nadir
Se si continua la rotazione oltre i 90° i valori tornano a decrescere verso il valore 0. Per capire se il sensore sta guardando avanti od indietro (ovvero se e' appoggiato alla sua basetta od e' appeso alla sua basetta) vengono usati i valori dell'asse Y Microsoft (y Python) che sono positivi se il Kinect guarda avanti e negativi se guarda indietro
i valori riportati sono espressi come accelerazioni in funzione dell'accelerazione di gravita'
Per calcolare l'accelerazione reale misurata la regola sembra essere
(misura/819)*9.18 m/sec*sec
Sembra quindi che i valori letti debbano essere confinati tra 0 ed 819 mentre le mie letture eccedono questo valore. Se si calcola il valore medio tra la misura maggiore e minore si ha che
asse Z (858+797)/2 = 827
asse X (779+865)/2=822
quindi considerando l'incertezza (vedi sotto) c'e' solo da calcolare un piccolo offset dello zero ed i valori coincidono con quelli di fabbrica
Mantenendo fermo il kinect ho effettuato oltre 14200 misure ed ho ottenuto una deviazione standard dei dati nei vari assi come segue
x = +/- 6.9 unita'
y = +/- 7.45 unita'
z = +/- 21.7 unita'
Per riportare i valori di inclinazione in gradi si puo' usare il seguente calcolo
-------------------------------------------------------------------------
pitch = math.atan2(y,x)*(180/3.1415926)
roll = math.atan2(y,math.sqrt((x*x)+(z*z)))*(180/3.1415926)
if (z <0):
roll = 90+(90-roll)
-------------------------------------------------------------------------
Di seguito una immagine con l'orientazione ed il valore degli angoli in relazione a diverse orientazioni
Per riportare i valori di inclinazione in gradi si puo' usare il seguente calcolo
-------------------------------------------------------------------------
pitch = math.atan2(y,x)*(180/3.1415926)
roll = math.atan2(y,math.sqrt((x*x)+(z*z)))*(180/3.1415926)
if (z <0):
roll = 90+(90-roll)
-------------------------------------------------------------------------
Di seguito una immagine con l'orientazione ed il valore degli angoli in relazione a diverse orientazioni
RGB con PyOpenNi Kinect
Non si tratta di una funzione molto bene documentata (anche perche' non presente nella cartella degli esempi) ma con PyOpenNi e' possibile acquisire immagini RBG da Kinect
il codice di riferimento (sostanzialmente autoesplicativo) e' il seguente
----------------------------------------------
from openni import *
from PIL import Image
ctx = Context()
ctx.init()
depth = DepthGenerator()
rgb = ImageGenerator()
depth.create(ctx)
rgb.create(ctx)
depth.set_resolution_preset(RES_VGA)
depth.fps = 30
rgb.set_resolution_preset(RES_VGA)
rgb.fps = 30
ctx.start_generating_all()
ctx.wait_one_update_all(rgb)
im = Image.fromstring('RGB',(640,480),rgb.get_raw_image_map())
im.save("rgb.jpg")
ctx.wait_one_update_all(depth)
de = Image.fromstring('L',(640,480),depth.get_raw_depth_map_8())
de.save("depth.jpg")
il codice di riferimento (sostanzialmente autoesplicativo) e' il seguente
----------------------------------------------
from openni import *
from PIL import Image
ctx = Context()
ctx.init()
depth = DepthGenerator()
rgb = ImageGenerator()
depth.create(ctx)
rgb.create(ctx)
depth.set_resolution_preset(RES_VGA)
depth.fps = 30
rgb.set_resolution_preset(RES_VGA)
rgb.fps = 30
ctx.start_generating_all()
ctx.wait_one_update_all(rgb)
im = Image.fromstring('RGB',(640,480),rgb.get_raw_image_map())
im.save("rgb.jpg")
ctx.wait_one_update_all(depth)
de = Image.fromstring('L',(640,480),depth.get_raw_depth_map_8())
de.save("depth.jpg")
Kinect con SimpleCV
Un metodo alternatico a PyOpenNi per interagire con Kinect da Python e' utilizzare SimpleCV
sudo apt-get install libopencv-*
sudo apt-get isntall python-opencv
sudo apt-get install python-numpy
sudo apt-get install python-pygame
sudo apt-get install python-setuptools
si scarica la libreria Simple CV di GitHub al seguente link e si installa com
python setup.py installse tutto e' andato a buon fine sono sufficiente le poche righe sottostanti per avere l'acquisizione dell'immagine RGB e di profondita' da Kinect
------------------------------------------------------
from SimpleCV import *
cam=Kinect()
depth = cam.getDepth()
depth.save('depth.jpg')
rgb = cam.getImage()
rgb.save('rgb.jpg')
Allineamento RGB/IR su Kinect
Sovrapponendo le immagini RGB e di profondita' di Kinect si vede chiaramente, indipendentemente se l'oggetto e' in primo piano o sullo sfondo
Leggendo questo link, si osserva che i parametri di calibrazioni delle camere sono codificate (e diversi) all'interno di ogni Kinect in funzione di come sono state montate e calibrate in fabbrica
Usando la versione completa di OpenNi (o l'SDK Microsoft) sono presenti specifiche funzioni che effettuano la fusione delle immagini dai due sensori come depth.GetAlternativeViewPointCap().SetViewPoint(image);
Leggendo questo link, si osserva che i parametri di calibrazioni delle camere sono codificate (e diversi) all'interno di ogni Kinect in funzione di come sono state montate e calibrate in fabbrica
Usando la versione completa di OpenNi (o l'SDK Microsoft) sono presenti specifiche funzioni che effettuano la fusione delle immagini dai due sensori come depth.GetAlternativeViewPointCap().SetViewPoint(image);
venerdì 11 aprile 2014
3D Scanner con Kinect
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.
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
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)
-------------------------------------------------
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) #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
#!/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.
Iscriviti a:
Post (Atom)
Debugger integrato ESP32S3
Aggiornamento In realta' il Jtag USB funziona anche sui moduli cinesi Il problema risiede nell'ID USB della porta Jtag. Nel modulo...
-
In questo post viene indicato come creare uno scatterplot dinamico basato da dati ripresi da un file csv (nel dettaglio il file csv e' c...
-
La scheda ESP32-2432S028R monta un Esp Dev Module con uno schermo TFT a driver ILI9341 di 320x240 pixels 16 bit colore.Il sito di riferiment...
-
Questo post e' a seguito di quanto gia' visto nella precedente prova Lo scopo e' sempre il solito: creare un sistema che permet...