martedì 25 marzo 2014

Fractal Explorer su Firefox Os

Ed ecco il programmino per esplorare Mandelbrot in versione Firefox OS
Rispetto alla versione HTML5 pura ci sono alcune differenze


Per prima cosa e' stato necessario aggiungere un pulsante di Reset perche' premendo il pulsante Home del telefono l'applicazione non viene chiusa ma solo nascosta ed al successivo riavvio si presenta con l'ultimo livello di zoom impostato

In esecuzione sull'emulatore


In esecuzione su Alcatel One Touch Fire


Inoltre poter passare la validazione del Market di Firefox e' stato necessario dividere la parte HTML dalla sezione Javascript

Da questo link di puo' scaricare il file zip dell'applicazione

manifest.webapp
------------------------------------------------------------------------
{
  "version": "0.5",
  "name": "MandExplorer",
  "description": "A simple Mandelbrot Explorer with zoom function",
  "launch_path": "/index.html",
  "icons": {
    "16": "/app-icons/icon-16.png",
"32": "/app-icons/icon-32.png",
    "48": "/app-icons/icon-48.png",
"60": "/app-icons/icon-60.png",
"90": "/app-icons/icon-90.png",
"120": "/app-icons/icon-120.png",
    "128": "/app-icons/icon-128.png",
"256": "/app-icons/icon-256.png"
  },
  "developer": {
    "name": "Luca Innocenti",
    "url": "http://debiaonoldcomputers.blogspot.com/"
  },
  "locales": {
    "en": {
      "description": "A simple Mandelbrot Explorer with zoom function",
      "developer": {
        "url": "http://debiaonoldcomputers.blogspot.com/"
      }
    },
    "it": {
      "description": "Un semplice visualizzatore con zoomabile dell'insieme di Mandelbrot",
      "developer": {
        "url": "http://debiaonoldcomputers.blogspot.com/"
      }
    }
  },
  "default_locale": "en"
}
------------------------------------------------------------------------


index.html
------------------------------------------------------------------------
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    </head>
    <body>
<script src="./js/calcola.js"></script>

        <canvas id="mandelbrot"  height="400" width="320">
        Il Browser non supporta HTML5.
        <!-- Utile per inserire informazioni di default -->
        </canvas><br>
<center><input type="button" id="reset" value="Reset"></center>


    </body>
</html>
------------------------------------------------------------------------

calcola.js
------------------------------------------------------------------------
//inizializza le variabili
//dimensioni dello schermo
var SCREEN_HEIGHT = 400;
var SCREEN_WIDTH = 320;
//finestra di visualizzazione in coordinate Mandelbrot
var a1 = -2.0;
var b1 = -1.2;
var a2 = 1.0;
var b2 = 1.2;
//numero di cicli
var it = 25;
var delta_x ;
var delta_y; 
// palette di 12 colori
var colori = ["#FFFFFF","#FF0000","#00FF00","#0000FF","#FF00FF","#FFFF00","#00FFFF","#FFaa00","#abcedf","#fedc0a","#ab16dd","#d00fba","#edabcc","#ddacff"];

//function punto(x1,y1,

function disegna(r_mi,i_mi,r_ma,i_ma,ite)
{
//effettua il calcolo dell'insieme date le dimensioni della finestra
var canvas = document.getElementById("mandelbrot");
if (canvas.getContext) {

 var context = canvas.getContext("2d");
 //rende il fondo nero
 context.fillStyle="rgb(0,0,0)";
 context.fillRect(0, 0, canvas.width, canvas.height);
var re_min = r_mi;
var im_min = i_mi;
var re_max = r_ma;
var im_max = i_ma;
var iterazioni = ite;
var r;
var a,b;
var x,y,x_new,y_new;
var test;
var k,j,i;
var re_factor = (re_max-re_min);
var im_factor = (im_max-im_min);
for (var i=0;i<SCREEN_HEIGHT;i++)
{
for (var j=0;j<SCREEN_WIDTH;j++)
 {
 a = re_min+(j*re_factor/SCREEN_WIDTH);
 b = im_min+(i*im_factor/SCREEN_HEIGHT);
 x = 0;
 y = 0;
 test = 0;
 for (var k=0;k<iterazioni;k++)
  {
  x_new = (x*x)-(y*y)+a;
  y_new = (2*x*y)+b;
  if (((x_new*x_new)+(y_new*y_new))>4)
{
// colora il punto
r = k%12;
context.beginPath();
context.fillRect(j-1,i-1,1,1);
context.fillStyle=colori[r];
context.stroke();
break;
}
  x = x_new;
  y = y_new;
  }
 }
}
}
}


function doMouseDown(event)
{
canvas_x = event.pageX;
canvas_y = event.pageY;
//calcola il punto in coordinate Mandelbrot
var p1 = (((a2-a1)/SCREEN_WIDTH)*canvas_x) + a1;
var p2 = (((b2-b1)/SCREEN_HEIGHT)*canvas_y) + b1;
//calcola la dimensione della finestra (riduzione di 1/4)
var delta_x = (a2-a1)/4;
var delta_y = delta_x*(SCREEN_WIDTH/SCREEN_WIDTH);
//aumenta il numero di iterazioni per ogni ciclo
it = it + 75;
//definisce la finestra intorno al punto cliccato
a1 = p1 - delta_y;
b1 = p2 - delta_x;
a2 = p1 + delta_y;
b2 = p2 + delta_x;
disegna(a1,b1,a2,b2,it);
}

function res(event)
{
a1 = -2.0;
b1 = -1.2;
a2 = 1.0;
b2 = 1.2;
it = 25;
disegna(a1,b1,a2,b2,it);
}

window.onload = function()
{
//riscala alla dimensione della finestra
var canvas = document.getElementById("mandelbrot");
var button = document.getElementById("reset");

//aggiunge l'evento click del mouse 
canvas.addEventListener("mousedown",doMouseDown,false);
button.addEventListener("click", res,false);
disegna(a1,b1,a2,b2,it);
}

------------------------------------------------------------------------

Fractal Explorer in HTML5

Per provare a creare una applicazione per Firefox OS ho modificato il programmino in HTML5 per generare l'insieme di Mandelbrot per renderlo interattivo
In pratica cliccando sullo schermo con il mouse viene effettuato uno zoom centrato sul punto cliccato diminuendo la finestra di visualizzazione di 1/4



Il programma in esecuzione



Rispetto alla versione precedente e' stata creata anche una semplice palette da 12 colori

-----------------------------------------------------------
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        </style>
    </head>
    <body>
      
        <canvas id="mandelbrot" height="400" width="800">
        Il Browser non supporta HTML5.
        <!-- Utile per inserire informazioni di default -->
        </canvas>

<script type="text/javascript">
//inizializza le variabili
//dimensioni dello schermo
        var SCREEN_HEIGHT = 0;
        var SCREEN_WIDTH = 0;
//finestra di visualizzazione in coordinate Mandelbrot
var a1 = -2.0;
var b1 = -1.2;
var a2 = 1.0;
var b2 = 1.2;
//numero di cicli
var it = 100;
var delta_x ;
var delta_y; 
// palette di 12 colori
var colori = ["#FFFFFF","#FF0000","#00FF00","#0000FF","#FF00FF","#FFFF00","#00FFFF","#FFaa00","#abcedf","#fedc0a","#ab16dd","#d00fba","#edabcc","#ddacff"];

//function punto(x1,y1,

function disegna(r_mi,i_mi,r_ma,i_ma,ite)
{
//effettua il calcolo dell'insieme date le dimensioni della finestra
var canvas = document.getElementById("mandelbrot");
                if (canvas.getContext) {

                  var context = canvas.getContext("2d");
 //rende il fondo nero
 context.fillStyle="rgb(0,0,0)";
 context.fillRect(0, 0, canvas.width, canvas.height);
                    var re_min = r_mi;
                    var im_min = i_mi;
                    var re_max = r_ma;
                    var im_max = i_ma;
                    var iterazioni = ite;
                    var r;
                    var a,b;
                    var x,y,x_new,y_new;
                    var test;
                    var k,j,i;
                    var re_factor = (re_max-re_min);
                    var im_factor = (im_max-im_min);
                    for (var i=0;i<SCREEN_HEIGHT;i++)
                     {
                     for (var j=0;j<SCREEN_WIDTH;j++)
                      {
                      a = re_min+(j*re_factor/SCREEN_WIDTH);
                      b = im_min+(i*im_factor/SCREEN_HEIGHT);
                      x = 0;
                      y = 0;
                      test = 0;
                      for (var k=0;k<iterazioni;k++)
                       {
                       x_new = (x*x)-(y*y)+a;
                       y_new = (2*x*y)+b;
                       if (((x_new*x_new)+(y_new*y_new))>4)
                        {
// colora il punto
                        r = k%12;
context.beginPath();
context.fillRect(j,i,1,1);
context.fillStyle=colori[r];
    context.stroke();
                        break;
                        }
                       x = x_new;
                       y = y_new;
                       }
                      }
                     }
                }
}


function doMouseDown(event)
{
canvas_x = event.pageX;
canvas_y = event.pageY;
//calcola il punto in coordinate Mandelbrot
var p1 = (((a2-a1)/SCREEN_WIDTH)*canvas_x) + a1;
var p2 = (((b2-b1)/SCREEN_HEIGHT)*canvas_y) + b1;
//calcola la dimensione della finestra (riduzione di 1/4)
var delta_x = (a2-a1)/4;
var delta_y = delta_x*(SCREEN_WIDTH/SCREEN_WIDTH);
//aumenta il numero di iterazioni per ogni ciclo
it = it + 75;
   //definisce la finestra intorno al punto cliccato
a1 = p1 - delta_y;
b1 = p2 - delta_x;
a2 = p1 + delta_y;
b2 = p2 + delta_x;
disegna(a1,b1,a2,b2,it);
}

       window.onload = function()
            {
//riscala alla dimensione della finestra
var canvas = document.getElementById("mandelbrot");
if (canvas.width  < window.innerWidth)
            {
                canvas.width  = window.innerWidth;
SCREEN_WIDTH =  canvas.width;
            }

            if (canvas.height < window.innerHeight)
            {
                canvas.height = window.innerHeight;
SCREEN_HEIGHT = canvas.height;
            }
//aggiunge l'evento click del mouse 
canvas.addEventListener("mousedown",doMouseDown,false);
disegna(a1,b1,a2,b2,it);
            }
        </script>
    </body>
</html>

venerdì 21 marzo 2014

Interazione tra Kinect ed XWindow con PyOpenNi

Francamente non amo Processing (a meno che non si declini come IDE di Arduino) ed dopo un po' di ricerche ho trovato il modo di pilotare Kinect mediante Python con la libreria PyOpenNi

L'installazione e' sostanzialmente manuale dai sorgenti con la procedura

git clone https://github.com/jmendeth/PyOpenNI.git 

mkdir PyOpenNI-build 
cd PyOpenNI-build 
cmake ../PyOpenNI
(per soddisfare le dipendenze sudo apt-get install cmake build-essential git-core \ python-dev libboost-python-dev)

Al termine della compilazione non c'e' la possibilita' di fare make install in  quanto e' lasciato all'utente la fase finale. Per i miei scopi la cosa piu' semplice e' stata quella di spostare il file openni.so dalla PyOpenNI-build/lib nella cartella degli esempi


Un esempio veramente interessate e' dato da hand-tracker.py che, brevemente modificato, puo' essere utilizzato per creare un mouse virtuale per X (nel brevissimo esempio se la mano si trova tra 750 e 1000 mm dal Kinect viene agganciato il Kinect, se si trova a meno di 750 mm si fa clic sul punto del mouse....lo script e' ampiamente migliorabile)

------------------------------------------------
#! /usr/bin/python

from openni import *
import os

context = Context()
context.init()

depth_generator = DepthGenerator()
depth_generator.create(context)
depth_generator.set_resolution_preset(RES_VGA)
depth_generator.fps = 30

gesture_generator = GestureGenerator()
gesture_generator.create(context)
gesture_generator.add_gesture('Wave')

hands_generator = HandsGenerator()
hands_generator.create(context)

# Declare the callbacks
# gesture
def gesture_detected(src, gesture, id, end_point):
    print "Detected gesture:", gesture
    hands_generator.start_tracking(end_point)
# gesture_detected

def gesture_progress(src, gesture, point, progress): pass
# gesture_progress

def create(src, id, pos, time):
    print 'Create ', id, pos
# create

def update(src, id, pos, time):
    print 'Update ', id, pos
    x = pos[0]+300
    y = pos[1]+300

    if (x < 0):
x = 0
 
    if (y < 0):
y = 0
    if ((pos[2] >750) and (pos[2] < 1000)):
os.system("xdotool mousemove "+ str(x)+" "+str(y))

    if (pos[2] <750):
os.system("xdotool mousemove "+ str(x)+" "+str(y) + " click 1")

# update

def destroy(src, id, time):
    print 'Destroy ', id
# destroy

# Register the callbacks
gesture_generator.register_gesture_cb(gesture_detected, gesture_progress)
hands_generator.register_hand_cb(create, update, destroy)

# Start generating
context.start_generating_all()

print 'Make a Wave to start tracking...'

while True:
    context.wait_any_update_all()
# while






Realta' aumentata con Aruco JS e WebGL

Una piccola introduzione: le librerie di realta' aumentata non gestiscono la fase di creazione degli oggetti 3D per cui si deve avere come integrazione una libreria grafica 3D

Detto cio' viene mostrato un breve esempio di come gestire un marker per la realta' aumentata catturato da una WebCam e creare un oggetto 3D che interagisca con il marker, il tutto gestito all'interno di un browser (in questo caso Firefox...Chrome non ha funzionato ma credo che sia dovuto ai permessi della webcam)

La libreria di AR utilizzata e' stata ArucoJS, la versione javascript di una libreria disponibile anche in C

Per prima cosa si deve stampare il marker (attenzione, una volta stampato il marker non deve essere tagliato a filo con il bordo nero ma deve essere lasciata una striscia bianca all'esterno del quadrato nero, altrimenti il marker non viene riconosciuto)


successivamente ho leggermente modificato l'esempio debug-posit presente nella cartella samples per generare un cubo al di sopra del marker con i comandi WebGL. Le modifiche, veramente minime, sono indicate dal segno giallo nel sorgente

Da notare che quando e' in esecuzione la pagina su Firefox, il processore entra in funzione in modo pesante con accensione delle ventole (su MacBook) e la pagina diventa un po' scattosa

il progetto puo' essere scaricato da questo link
---------------------------------------------------------------------------
<html>

<head>
  <title>Augmented Reality</title>

  <script type="text/javascript" src="libs/Three.js"></script> 

  <script type="text/javascript" src="svd.js"></script> 
  <script type="text/javascript" src="posit1.js"></script> 
  <script type="text/javascript" src="cv.js"></script> 
  <script type="text/javascript" src="aruco.js"></script> 

  <script>
    var video, canvas, context, imageData, detector, posit;
    var renderer1, renderer2, renderer3;
    var scene1, scene2, scene3, scene4;
    var camera1, camera2, camera3, camera4;
    var plane1, plane2, model, texture;
    var step = 0.0;

    var modelSize = 35.0; //millimeters

    function onLoad(){
      video = document.getElementById("video");
      canvas = document.getElementById("canvas");
      context = canvas.getContext("2d");
    
      canvas.width = parseInt(canvas.style.width);
      canvas.height = parseInt(canvas.style.height);
      
      navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
      if (navigator.getUserMedia){
        init();
      }
    };
    
    function init(){
      navigator.getUserMedia({video:true}, 
        function (stream){
          if (window.webkitURL) {
            video.src = window.webkitURL.createObjectURL(stream);
          } else if (video.mozSrcObject !== undefined) {
            video.mozSrcObject = stream;
          } else {
            video.src = stream;
          }
        },
        function(error){
        }
      );
      
      detector = new AR.Detector();
      posit = new POS.Posit(modelSize, canvas.width);

      createRenderers();
      createScenes();

      requestAnimationFrame(tick);
    };

    function tick(){
      requestAnimationFrame(tick);
      
      if (video.readyState === video.HAVE_ENOUGH_DATA){
        snapshot();

        var markers = detector.detect(imageData);
        drawCorners(markers);
        updateScenes(markers);
        
        render();
      }
    };

    function snapshot(){
      context.drawImage(video, 0, 0, canvas.width, canvas.height);
      imageData = context.getImageData(0, 0, canvas.width, canvas.height);
    };
    
    function drawCorners(markers){
      var corners, corner, i, j;
    
      context.lineWidth = 3;

      for (i = 0; i < markers.length; ++ i){
        corners = markers[i].corners;
        
        context.strokeStyle = "red";
        context.beginPath();
        
        for (j = 0; j < corners.length; ++ j){
          corner = corners[j];
          context.moveTo(corner.x, corner.y);
          corner = corners[(j + 1) % corners.length];
          context.lineTo(corner.x, corner.y);
        }

        context.stroke();
        context.closePath();
        
        context.strokeStyle = "green";
        context.strokeRect(corners[0].x - 2, corners[0].y - 2, 4, 4);
      }
    };

    function createRenderers(){
      renderer1 = new THREE.WebGLRenderer();
      renderer1.setClearColorHex(0xffff00, 1);
      renderer1.setSize(canvas.width, canvas.height);
      document.getElementById("container1").appendChild(renderer1.domElement);
      scene1 = new THREE.Scene();
      camera1 = new THREE.PerspectiveCamera(40, canvas.width / canvas.height, 1, 1000);
      scene1.add(camera1);

      renderer2 = new THREE.WebGLRenderer();
      renderer2.setClearColorHex(0xffff00, 1);
      renderer2.setSize(canvas.width, canvas.height);
      document.getElementById("container2").appendChild(renderer2.domElement);
      scene2 = new THREE.Scene();
      camera2 = new THREE.PerspectiveCamera(40, canvas.width / canvas.height, 1, 1000);
      scene2.add(camera2);

      renderer3 = new THREE.WebGLRenderer();
      renderer3.setClearColorHex(0xffffff, 1);
      renderer3.setSize(canvas.width, canvas.height);
      document.getElementById("container").appendChild(renderer3.domElement);
      
      scene3 = new THREE.Scene();
      camera3 = new THREE.OrthographicCamera(-0.5, 0.5, 0.5, -0.5);
      scene3.add(camera3);
      
      scene4 = new THREE.Scene();
      camera4 = new THREE.PerspectiveCamera(40, canvas.width / canvas.height, 1, 1000);
      scene4.add(camera4);
    };

    function render(){
      renderer1.clear();
      renderer1.render(scene1, camera1);
      
      renderer2.clear();
      renderer2.render(scene2, camera2);

      renderer3.autoClear = false;
      renderer3.clear();
      renderer3.render(scene3, camera3);
      renderer3.render(scene4, camera4);
    };

    function createScenes(){
      plane1 = createPlane();
      scene1.add(plane1);

      plane2 = createPlane();
      scene2.add(plane2);
      
      texture = createTexture();
      scene3.add(texture);
    
      model = createModel();
      scene4.add(model);
    };
    
    function createPlane(){
      var object = new THREE.Object3D(),
          geometry = new THREE.PlaneGeometry(1.0, 1.0, 0.0),
          material = new THREE.MeshNormalMaterial(),
          mesh = new THREE.Mesh(geometry, material);
      
      object.add(mesh);
      
      return object;
    };
    
    function createTexture(){
      var texture = new THREE.Texture(video),
          object = new THREE.Object3D(),
          geometry = new THREE.PlaneGeometry(1.0, 1.0, 0.0),
          material = new THREE.MeshBasicMaterial( {map: texture, depthTest: false, depthWrite: false} ),
          mesh = new THREE.Mesh(geometry, material);
      
      object.position.z = -1;
      
      object.add(mesh);
      
      return object;
    };
    
    function createModel(){
      var object = new THREE.Object3D(),
        
          cubo_geometry = new THREE.CubeGeometry(1,1,1),
          cubo_material = new THREE.MeshNormalMaterial(),
          mesh = new THREE.Mesh(cubo_geometry, cubo_material);
      
      object.add(mesh);
      
      return object;
    };

    function updateScenes(markers){
      var corners, corner, pose, i;
      
      if (markers.length > 0){
        corners = markers[0].corners;
        
        for (i = 0; i < corners.length; ++ i){
          corner = corners[i];
          
          corner.x = corner.x - (canvas.width / 2);
          corner.y = (canvas.height / 2) - corner.y;
        }
        
        pose = posit.pose(corners);
        
        updateObject(plane1, pose.bestRotation, pose.bestTranslation);
        updateObject(plane2, pose.alternativeRotation, pose.alternativeTranslation);
        updateObject(model, pose.bestRotation, pose.bestTranslation);

        updatePose("pose1", pose.bestError, pose.bestRotation, pose.bestTranslation);
        updatePose("pose2", pose.alternativeError, pose.alternativeRotation, pose.alternativeTranslation);
        
        step += 0.025;
        
        model.rotation.z -= step;
      }
      
      texture.children[0].material.map.needsUpdate = true;
    };
    
    function updateObject(object, rotation, translation){
      object.scale.x = modelSize;
      object.scale.y = modelSize;
      object.scale.z = modelSize;
      
      object.rotation.x = -Math.asin(-rotation[1][2]);
      object.rotation.y = -Math.atan2(rotation[0][2], rotation[2][2]);
      object.rotation.z = Math.atan2(rotation[1][0], rotation[1][1]);

      object.position.x = translation[0];
      object.position.y = translation[1];
      object.position.z = -translation[2];
    };
    
    function updatePose(id, error, rotation, translation){
      var yaw = -Math.atan2(rotation[0][2], rotation[2][2]);
      var pitch = -Math.asin(-rotation[1][2]);
      var roll = Math.atan2(rotation[1][0], rotation[1][1]);
      
      var d = document.getElementById(id);
      d.innerHTML = " error: " + error
                  + "<br/>"
                  + " x: " + (translation[0] | 0)
                  + " y: " + (translation[1] | 0)
                  + " z: " + (translation[2] | 0)
                  + "<br/>"
                  + " yaw: " + Math.round(-yaw * 180.0/Math.PI)
                  + " pitch: " + Math.round(-pitch * 180.0/Math.PI)
                  + " roll: " + Math.round(roll * 180.0/Math.PI);
    };

    window.onload = onLoad;
  </script>

</head>

<body style="text-align: center; font-family: monospace;">

  <video id="video" width=320 height=240 autoplay="true" style="display:none;"></video>
  
  <div style="margin: 10px;"><strong>-= Augmented Reality =-</strong></div>
  <div style="width: 100%;">
    <div style="width: 650px; margin-left:auto; margin-right:auto;">
      <canvas id="canvas" style="width: 320px; height: 240px; float: left; border: solid 1px black;"></canvas>
      <div id="container" style="width: 320px; height: 240px; float: left; border: solid 1px black; background: green;"></div>
      <div style="clear: both;"></div>
      <div style="float: left; border: solid 1px black;">
        <div id="container1" style="width: 320px; height: 240px; background: red;"></div>
        <div id="pose1"></div>
      </div>
      <div style="float: left; border: solid 1px black;">
        <div id="container2" style="width: 320px; height: 240px; background: blue;"></div>
        <div id="pose2"></div>
      </div>
    </div>
  </div>
  <div style="clear: both;"></div>
  <div style="margin: 15px;"><strong>Powered by <a href="http://code.google.com/p/js-aruco/">js-aruco</a> and <a href="https://github.com/mrdoob/three.js">Three.js</a></strong></div>

</body>
  
</html>

mercoledì 19 marzo 2014

Aggiornamento Alcatel One Touch Fire a Firefox OS 1.2

Visto che oramai Alcatel non ha mostrato l'intenzione di effettuare l'upgrade a Firefox OS 1.2 mi sono deciso a farlo da solo e devo ammettere che e' una procedura di gran lunga piu' semplice rispetto a qualsiasi aggiornamento di firmware per telefoni Android



La procedura e' stata eseguita su Linux perche' non avevo voglia di litigare con i driver di Windows
Le istruzioni sono state riprese da questo sito

Si scarica prima il pacchetto di Firefox OS per Alcatel One Touche Fire da questo sito (nel mio caso  ho preso il pacchetto v1.2-20140127 per avere l'ultima versione stabile

Poi si aggiunge al file /etc/udev/rules.d/99-android.rules la seguente riga


SUBSYSTEM==”usb”, ATTR{idVendor}==”18d1″, ATTR{idProduct}==”d00d”, MODE=”0666″, OWNER=”{luca}”(sostituire luca con il proprio nome utente)

Si modifica le impostazioni del telefono con
Impostazioni -> Info sul Dispositivo -> Altre Informazioni -> Sviluppatore abilita Debug remoto e Abilita console.

A questo punto si riavvia il telefono in boot mode (tasto volume - ed accensione) ed il telefono si arresta sulla schermata bianca con la scritta Alcatel



e si lancia il file ./flash.sh


L'operazione e' estremamente veloce ed indolore. Ed ecco il telefono senza la personalizzazione TIM


(per effettuare uno screenshot pulsate di accensione e tasto Home)


WebGL con ThreeJS


Sempre per un uso didattico, per visualizzare gli assi e i piani di simmetria dei minerali, stavo cercando un sistema semplice ed interattivo. Ero rimasto a VRML ma i tempi sono cambiati e la soluzione piu' semplice e' caduta su WebGL e la libreria ThreeJS


questo link c'e' una fonte inesauriibile di esempi ed idee. Io ho preso e modificato l'esempio HelloWorld per creare un cubo con indicato un asse di rotazione di ordine 4, un asse di rotazione di ordine 3 e 3 piani di simmetria.
Il modello e' navigabile (rotazione, spostamento) con il solo mouse ed e' compatibile sia con Chrome che con Firefox alle versioni piu' recenti

Il progetto completo e' scaricabile da qui

---------------------------------------------------------
<!doctype html>
<html lang="en">
<head>
<title>Solido</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
    <link rel=stylesheet href="css/base.css"/>
</head>
<body>

<script src="js/Three.js"></script>
<script src="js/Detector.js"></script>
<script src="js/Stats.js"></script>
<script src="js/OrbitControls.js"></script>
<script src="js/THREEx.KeyboardState.js"></script>
<script src="js/THREEx.FullScreen.js"></script>
<script src="js/THREEx.WindowResize.js"></script>


<!-- ------------------------------------------------------------ -->

<div id="ThreeJS" style="z-index: 1; position: absolute; left:0px; top:0px"></div>
<script>

// standard global variables
var container, scene, camera, renderer, controls, stats;
var keyboard = new THREEx.KeyboardState();
var clock = new THREE.Clock();

var cube;

init();
animate();


function init() 
{
scene = new THREE.Scene();
var SCREEN_WIDTH = window.innerWidth, SCREEN_HEIGHT = window.innerHeight;
var VIEW_ANGLE = 45, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 0.1, FAR = 20000;
camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR);
scene.add(camera);
camera.position.set(0,50,40);
camera.lookAt(scene.position);


if ( Detector.webgl )
renderer = new THREE.WebGLRenderer( {antialias:true} );
else
renderer = new THREE.CanvasRenderer(); 

renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);

// attach div element to variable to contain the renderer
container = document.getElementById( 'ThreeJS' );
// alternatively: to create the div at runtime, use:
//   container = document.createElement( 'div' );
//    document.body.appendChild( container );

// attach renderer to the container div
container.appendChild( renderer.domElement );

////////////
// EVENTS //
////////////

// automatically resize renderer
THREEx.WindowResize(renderer, camera);
THREEx.FullScreen.bindKey({ charCode : 'm'.charCodeAt(0) });

//////////////
// CONTROLS //
//////////////

// move mouse and: left   click to rotate, 
//                 middle click to zoom, 
//                 right  click to pan
controls = new THREE.OrbitControls( camera, renderer.domElement );



//////////////
// GEOMETRY //
//////////////


var cubeMaterialArray = [];
// order to add materials: x+,x-,y+,y-,z+,z-
cubeMaterialArray.push( new THREE.MeshBasicMaterial( { color: 0xff3333 } ) );
cubeMaterialArray.push( new THREE.MeshBasicMaterial( { color: 0xff8800 } ) );
cubeMaterialArray.push( new THREE.MeshBasicMaterial( { color: 0xffff33 } ) );
cubeMaterialArray.push( new THREE.MeshBasicMaterial( { color: 0x33ff33 } ) );
cubeMaterialArray.push( new THREE.MeshBasicMaterial( { color: 0x3333ff } ) );
cubeMaterialArray.push( new THREE.MeshBasicMaterial( { color: 0x8833ff } ) );
var cubeMaterials = new THREE.MeshFaceMaterial( cubeMaterialArray );
// Cube parameters: width (x), height (y), depth (z), 
//        (optional) segments along x, segments along y, segments along z
var cubeGeometry = new THREE.CubeGeometry( 10, 10, 10, 0, 0, 0 );
// using THREE.MeshFaceMaterial() in the constructor below
//   causes the mesh to use the materials stored in the geometry
cube = new THREE.Mesh( cubeGeometry, cubeMaterials );
cube.position.set(0, 0, 0);
scene.add( cube );

material = new THREE.LineBasicMaterial({
        color: 0x0000ff
    });

var geometry = new THREE.Geometry();
    geometry.vertices.push(new THREE.Vector3(0, 0, 10));
    geometry.vertices.push(new THREE.Vector3(0, 0, -10));
var line = new THREE.Line(geometry, material);
scene.add(line);

var plane = new THREE.Mesh(new THREE.PlaneGeometry(30, 30), new THREE.MeshNormalMaterial({ color: 0x888888, transparent: true, opacity: 0.5  }));
plane.material.side = THREE.DoubleSide;
    plane.overdraw = true;
    scene.add(plane);

    
    var plane2 = new THREE.Mesh(new THREE.PlaneGeometry(1,1,5, 5), new THREE.MeshNormalMaterial({ color: 0xff0000, transparent: true, opacity: 0.5  }));
plane2.material.side = THREE.DoubleSide;
    plane2.overdraw = true;
    scene.add(plane2);


}

function animate() 
{
    requestAnimationFrame( animate );
render();
update();
}

function update()
{
// delta = change in time since last call (in seconds)
var delta = clock.getDelta(); 

controls.update();
stats.update();
}

function render() 
{
renderer.render( scene, camera );
}

</script>

</body>
</html>

martedì 18 marzo 2014

Comandare Impress con Raspberry + HC-SR04 + Python

Sulla base del precedente post  mi sono chiesto se era possibile ridurre al minimo la spesa (ed il consumo di corrente). In questa ottica ho provato a montare una Raspberry che si interfaccia direttamente con l'HC-SR04 per fare una presentazione. In questo caso si ha la comodita' di poter far girare la presentazione anche su televisori di generose dimensioni vista l'uscita HDMI (nel test e' stato usato un mini monitor ma solo perche' il televisore di casa era occupato)



Il collegamento tra le porte GPIO e la Raspberry e' il seguente
VCC 5 V
GND
GPIO 17 connesso a Trigger
GPIO 27 connesso a Echo con con una resistenza da 1 KOhm


Dato che la prova e' stata fatta con PiBang e non Raspbian c'e' da montare la libreria Gpio per Python che non e' inclusa di default
Per fare cio'
apt-get install build-essential python-dev python-pip
pip install rpi.gpio

il comando xdotool invece e' gia' compreso in PiBanf
lo script che ho utilizzato deriva da questo sito leggermente modificato
Quando la distanza risulta inferiore a 30 cm viene cambiata la diapositiva 
------------------------------------------------------------

#!/usr/bin/python
import os

contatore = 1

def reading(sensor):
    import time
    import RPi.GPIO as GPIO
    
    GPIO.setwarnings(False)
    GPIO.setmode(GPIO.BCM)
    
    if sensor == 0:
        GPIO.setup(17,GPIO.OUT)
        GPIO.setup(27,GPIO.IN)
        GPIO.output(17, GPIO.LOW)
        time.sleep(0.3)

        GPIO.output(17, True)
        time.sleep(0.00001)
        GPIO.output(17, False)

        while GPIO.input(27) == 0:
          signaloff = time.time()

        while GPIO.input(27) == 1:
          signalon = time.time()
        
        timepassed = signalon - signaloff
        distance = timepassed * 17000
        return distance
        
        GPIO.cleanup()

    else:
        print "Incorrect usonic() function varible."

while True:        
if (reading(0) < 30):
contatore = contatore + 1
print contatore
if (contatore >= 4):
contatore = 1
os.system("xdotool key 1")
os.system("xdotool key Return")
else:
os.system("xdotool key Right")
------------------------------------------------------------
Rispetto al precedente script si vede che i comandi di xdotool sono stati modificati. Non ho chiaro il motivo per cui e' stata necessaria la modifica ma penso che sia attribuibile al WM che e' differente tra Ubuntu (Gnome) e PiBang(OpenBox)

Con questa configurazione il costo dell'hardware (monitor o televisore escluso) e' dell'ordine dei 50 euro


Feature Matching OpenCv

Il problema e' il seguente: trovare le differenze tra le due foto. Le due immagini sono state riprese a distanza di oltre un anno ed il ...