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
mercoledì 23 aprile 2014
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)
PointCloud e Mesh con CloudCompare e Meshlab
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)
Per la versione Ubuntu si installa mediante PPA con la seguente procedura
sudo add-apt-repository ppa:romain-janvier/cloudcompare
apt-get update
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
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)
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 |
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)
lunedì 21 aprile 2014
Chrome Remote Desktop
Contrariamente a quanto prevede il nome Chrome Remote non e' una estensione in senso stretto del browser. Pur installando una componente dal WebStore di fatto in seguito viene scaricato un eseguibile indipendente dal browser che effettua tutto il lavoro di server di remote desktop
![]() |
| Il componente di Google Remote Desktop nelle Applicazioni di Chrome |
![]() |
| Definizione dei pin di sicurezza |
![]() |
| Installazione del server |
Giusto per confermare come Chrome Remote Desktop sia distaccata dal browser Chrome e' possibile accedere alla macchina remota anche se sulla macchina remota non e' avviato il browser
Rispetto ad altri esempi di software di desktop remoto, Chrome Remote Desktop ha un fantastico client perfettamente integrato in Android
![]() |
| In alto a destra l'icona per aprire la tastiera remote |
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
Iscriviti a:
Post (Atom)
FigSpec FS-60CL
A lavoro mi hanno rifilato questo sensore iperspettrale cinese (pushbroom 400-1000 nm con larghezza di banda di 0.5 nm compatibile con DJI M...
-
Aggiornamento questo e' la risposta degli sviluppatori First of all, almost all operating systems on both mobile and laptop/desktop n...
-
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...






















