mercoledì 2 aprile 2014

Accuratezza del sensore di distanza di Kinect

Per verificare l'accuratezza del sensore di distanza del Kinect ho provato ad acquisire due immagini di una stessa scena statica e a vedere le differenze

Mappa di profondita' di Kinect

Le due immagini sono state acquisite con lo script visto in questo post

Per calcolare la differenza ho usato il seguente script
------------------------------------------------
import pickle
import numpy as np
import Image

posizione = 0
accumula = 0

f = open("3.txt")
data1 = pickle.load(f)
f.close

f = open("4.txt")
data = pickle.load(f)
f.close
accumula = data - data1

img = Image.new('L', (480,640), "black")
pixels = img.load()

for i in range(img.size[0]):
for j in range(img.size[1]):
pixels[i,j] = accumula[posizione]
posizione = posizione + 1

img2 = img.rotate(270)
img2.save("3-4.png")

print np.histogram(accumula,[-3000,-100,-10,10,100,3000])
------------------------------------------------

Questa e' l'immagine di differenza
E' subito evidente che le maggiori differenze sono ubicate nei punti in cui c'e' la maggior distanza tra due pixel vicini

Mappa delle differenze test 1


La distribuzione di frequenza indica che per il 92.6% la differenza di distanza misurata e' compresa tra -1/+1 cm. Un altro 5.7% delle differenze e' compresa tra -10/+10 cm
Per maggiore dettaglio il 75% delle misure ha differenza 0


Un altro esempio

Mappa delle differenze Test 2

in questo caso il 77% dei punti mostra differenza di 0 mm con il 93% dei punti con differenza inferiore a 1 cm.


Un terzo esempio

Mappa delle differenze Test 3

anche qui il 76% dei punti mostra differenza di 0 mm con il 92.4% dei punti con differenza inferiore a 1 cm.




In buona sostanza il sensore di Kinect lavora molto bene su scene piatte mentre dove ci sono oggetti su piani a distanza differente con bruschi salti di distanza l'errore diventa sensibile





Hello World su Ios

Giusto un promemoria per me stesso su come compilare Hello World su IOS (piu' che altro perche' alcune azioni sono visive ed e' difficile descriverle senza un video



-----------------------------------------------------------------
- (IBAction)premi:(id)sender{
    NSString *const saluto = @"Hello World";
    hello.text = saluto;
}

-----------------------------------------------------------------
{
    IBOutlet UILabel *hello;
}
- (IBAction)premi:(id)sender;

Sviluppare FirefoxOS su Ubuntu

Grazie a quanto indicato in questo post sul forum di Firefox Italia, sono riuscito a far partire l'ambiente di sviluppo di Firefox OS su Linux (Ubuntu nel caso specifico)



in pratica si devono lanciare i seguenti comandi

sudo adb kill-server
sudo adb devices
sudo adb forward tcp:6000 localfilesystem:/data/local/debugger-socket


ed in seguito, all'interno di App Manager si deve effettuare la connessione  a localhost:6000

Depth Map di Kinect con PyOpenNi e 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) 


acquisisci.py
-----------------------------------------------
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()

contatore =1
while True:
    # Update to next frame
    nRetVal = ctx.wait_one_update_all(depth)

    depthMap = depth.map
    depthMap2 = np.array(depthMap)
    f = open("faccia"+str(contatore)+".txt","w+b")
    pickle.dump(depthMap2,f)
    f.close()

    print contatore

    contatore = contatore + 1
    time.sleep(5)
-----------------------------------------------
lettura.py
-----------------------------------------------
import pickle
import numpy

posizione = 0

f = open("faccia5.txt")
data = pickle.load(f)
f.close

for i in range(img.size[0]):
for j in range(img.size[1]):
print str(i)+","+str(j)+","+str(data[posizione]) 
posizione = posizione + 1


lunedì 31 marzo 2014

Copiare linee da file testo con Bash

Su richiesta di un amico, c'era la necessita' di estrarre solo le righe pari (o dispari) da un file testo puro usando Bash

il primo tentativo e' stato fatto con un ciclo for
--------------------------------------------
for i in `seq 1 2 10`;
do
   
    comando="sed -n "$i"p file1.txt >> file2.txt"
    eval $comando
done
---------------------------------------------

in realta' il comando sed ha gia' al suo interno questa possibilita', infatti lo switch p permette di indicare a quale riga iniziare a quante righe saltare. per esempio nell'esempio sottostante vengono salvate una riga si' ed una no partendo da 1
---------------------------------------------
sed -n 1~2p file1.txt >> file2.txt
---------------------------------------------

Geocompass per FirefoxOS


Questa applicazione e' un porting della precedente Geocompass per Android per FirefoxOS
A parte il linguaggio differente, il codice condivide larghe parte di righe che sono state semplicemente copiate complice una sintassi uguale tra Java e Javascript
Il programma e' stato scritto con l'aiuto di Cordova/Phonegap.
Per istruzioni si puo' consultare Wikipedia o questa pagina




L'applicazione puo' essere scaricata a questo link


index.html
----------------------------------------------------
<!DOCTYPE html>
<html>
  <head>
    <title>Geocompass</title>
<style>
    #content {
       width: 100px;
       height:100px;
       margin: 0px auto;
}
</style>

    <script type="text/javascript" charset="utf-8" src="./js/cordova.js"></script>
    <script type="text/javascript" charset="utf-8" src="./js/misura.js"></script>
  </head>

  <body onload="drawCanvas();">
  <div id="content">
    <canvas id="myCanvas"  width="256" height="256">Your browser doesn't support canvas tag</canvas>
</div>
 <p id="ang" style="text-align:center;font-family:arial;color:red;font-size:30px;"></p>
 <p  style="text-align:center;font-family:arial;color:red;font-size:30px;">Strike/Dip</p><center>
 <p><a style='text-align:center;font-family:arial;color:red;font-size:20px;' href='http://en.wikipedia.org/wiki/Strike_and_dip'>Help</a></p></center>
 <p style="text-align:center;font-family:arial;color:red;font-size:15px;">Contact : lucainnoc@gmail.com</p></center>
  </body>
</html>
----------------------------------------------------

misura.js
----------------------------------------------------
var surface;
     var misura; 
     var angle = 0;
var ang_maxpendenza = 0;
function drawCanvas() {
screen.mozLockOrientation("portrait-primary");
    surface = document.getElementById("myCanvas");
if (surface.getContext) {
misura = new Image();
misura.onload = loadingComplete;
misura.src = "./img/misura.png";
if (ang_maxpendenza < 10) 
{
misura.src = "./img/orizzontale.png";
}
if (ang_maxpendenza > 80) 
{
misura.src = "./img/verticale.png";
}
}
}

 function loadingComplete(e) {
     var surfaceContext = surface.getContext('2d');
     surfaceContext.fillStyle = "rgb(255,255,255)";
     surfaceContext.fillRect(0, 0, surface.width, surface.height);
     surfaceContext.save();
surfaceContext.translate(misura.width * 0.5, misura.height * 0.5);
if ((ang_maxpendenza > 10) && (ang_maxpendenza < 80))
{
surfaceContext.rotate(angle* 0.0174532925199432957);
}
surfaceContext.translate(-misura.width * 0.5, -misura.height * 0.5);
surfaceContext.drawImage(misura, 0, 0);
     surfaceContext.restore();
}

function converti2deg(angolo) {
return angolo*(180/Math.PI);
}
function converti2rad(angolo) {
return angolo*(Math.PI/180);
}

    
    window.addEventListener('deviceorientation', function(event) {
var azimuth = event.alpha;
    var pitch = event.beta;
    var roll = event.gamma;
pitch = converti2rad(pitch);
    roll = converti2rad(roll);
var cosalfa = Math.cos(roll-(Math.PI/2));
    var cosbeta = Math.cos(pitch-(Math.PI/2));
var dir_maxpendenza = -converti2deg(Math.atan(cosalfa/cosbeta));  
if ((pitch < 0) && (roll<=0)) dir_maxpendenza =  dir_maxpendenza + 180;
if ((pitch <= 0) && (roll>0)) dir_maxpendenza =  dir_maxpendenza + 180;

    if ((pitch > 0) && (roll>0)) dir_maxpendenza =  dir_maxpendenza + 360;
    if ((pitch == 0) && (roll>0)) dir_maxpendenza =  270;
    if ((pitch > 0) && (roll==0)) dir_maxpendenza =  0;

    ang_maxpendenza = 90-converti2deg(Math.acos(Math.sqrt((cosalfa*cosalfa)+(cosbeta*cosbeta))));
var dir_maxpendenza_reale = (azimuth+dir_maxpendenza)%360;

document.getElementById("ang").innerHTML = dir_maxpendenza_reale.toFixed(0)+"/"+ang_maxpendenza.toFixed(0);
if (ang_maxpendenza < 10) document.getElementById("ang").innerHTML = "Horizontal";
if (ang_maxpendenza > 80) document.getElementById("ang").innerHTML = "Vertical " + azimuth.toFixed(0) + "-" + (azimuth.toFixed(0)+180)%360;


angle = dir_maxpendenza;
drawCanvas()
}, false);
----------------------------------------------------

manifest.webapp
----------------------------------------------------
{
"name": "Geocompass",
  "description": "Compass for Geologists",
"launch_path":"/index.html",
"installs_allowed_from":["*"],
"version":"0.9.0","name":"Geocompass",
"orientation": "portrait-primary",
 "icons": {
    "256": "/img/icon-256.png",
    "128": "/img/icon-128.png",
"120": "/img/icon-120.png",
"90": "/img/icon-90.png",
"60": "/img/icon-60.png",
"32": "/img/icon-32.png"
  },
  "developer": {
    "name": "Luca Innocenti",
    "url": "http://debiaonoldcomputers.blogspot.com/"
  },
  "default_locale": "en"

}
----------------------------------------------------


Opencv camera calibration in cpp

Oltre che con uno script Python come visto qui la calibrazione della camera si puo' fare anche con il programma in CPP Questo il proce...