Processing e visualizzazione

III parte: Oltre la grafica - le librerie esternedi

Video, audio, accesso ai dati e alla rete: Processing ha potenzialità che vanno oltre la grafica. In questo articolo vederemo le librerie che permettono di aggiungere con poco sforzo simulazioni fisiche, audio, video e rendono possibile l‘accesso alla rete.

Negli scorsi mesi abbiamo introdotto Processing e visto gli elementi grafici base per creare illustrazioni e visualizzazioni di dati.
Ma Processing non è solo grafica, e tramite l'uso di librerie, sia incluse nel core del linguaggio che scaricabili separatamente, è possibile manipolare o produrre video, analizzare campioni audio, accedere alla rete e interagire con dispositivi hardware.
Per evitare di inserire troppo codice nell'articolo ho incluso solo i pezzi salienti per spiegare la funzionalità. Vi rimando alla bibliografia e alla documentazione delle librerie trattate per esempi più dettagliati.

Gestione delle immagini raster

Iniziamo la carrellata di funzionalità aggiuntive partendo dalla gestione delle immagini raster.
In Processing è possibile caricare immagini con la funzione loadImage(). È possibile specificare sia un'immagine che si trova nella cartella dati dello sketch, che l'URL di un'immagine remota.

PImage b;
b = loadImage("mokabyte.jpg");
image(b, 0, 0);
image(b, 0, 0, width/2, height/2);

Come potete aver intuito, la funzione image serve per disegnare a schermo un oggetto di tipo Image, specificando la sua posizione e, se lo si volesse ridimensionare, la sua nuova altezza e larghezza. È anche possibile fare delle elaborazioni a runtime sull'immagine usando direttamente le API core di Processing.

I metodi filter() e blend() permettono di modificare l'immagine. Il primo applica alcuni semplici filtri sull'immagine (come rendere l'immagine B&W, in toni di grigio, metterla in negativo, applicare blur gaussiano, e altri) e il secondo sovrappone due immagini (o due volte la stessa) combinandole tra di loro in vari modi. Infine, se si vuole avere un maggior controllo o se si vogliono effettuare elaborazioni particolari, è possibile ottenere un'array con tutti i pixel dell'immagine. Chiamando la funzione loadPixels() si ottiene l'array i cui elementi contengono il colore dei pixel. Questo array è uno dei pochi punti poco intuitivi di Processing: invece che essere una matrice di punti è un array mono-dimensionale, con tutte le righe messe una dopo l'altra. Per ottenere quindi un punto specificando X e Y è necessario usare questa formula:

index = Y*width + X

Una volta modificato l'array di pixel è poi necessario aggiornare lo schermo con la funzione updatePixels().

Alternativamente si potrebbe usare le funzioni get(x,y) e set(x,y,color), ma queste leggono e/o aggiornano ogni volta l'array rallentando quindi le performance dell'applicazione. Vanno quindi bene quando si devono effettuare pochi aggiornamenti ma non se si deve processare un'intera immagine.

PDF

Nel caso si voglia invece generare un documento da stampare è possibile dire a Processing di ridirigere l'output su un file PDF. La cosa è molto semplice: basta specificare PDF come tipologia di render nella funzione size():

size(2000,2000,PDF, "filename.pdf");

È anche possibile fare PDF multipagina, chiamando la funzione nextPage() sull'oggetto grafico sul quale viene disegnato l'output.

size(2000,2000,PDF, "filename.pdf");
PGraphicsPDF pdf = (PGraphicsPDF) g;  // Ottiene il render
pdf.nextPage();  //cambia pagina

 

Video

Processing è pensato principalmente per lavorare in real-time. Ma se vogliamo utilizzare le nostre animazioni in termini più classici di "video" è possibile utilizzare la libreria "core" MovieMaker. Questa ci permette di salvare l'output che verrebbe emesso sullo schermo in un filmato QuickTime. Inoltre rende possibile anche realizzare rendering complessi che richiederebbero più tempo di quello disponibile per l'utilizzo real-time.

Per esportare un'animazione in video è necessario, nella fase di setup dello sketch, inizializzare l'oggetto MovieMaker specificando il nome del file e i parametri relativi al codec da usare per il salvataggio (si va dal RAW al Sorenson fino a Mpeg4) e il framerate (in genere 25). Nella fase di draw, alla fine del rendering di ogni frame, è necessario chiamare il metodo addFrame() per aggiungerlo al filmato.
Infine bisogna aggiungere una funzione di chiusura che termina la fase di registrazione.

import processing.video.*;
MovieMaker mm;
void setup()
{
    size(200,200);
    mm = new MovieMaker(this, width, height, "mokabyte.mov",
            25, MovieMaker.RAW, MovieMaker.LOSSLESS, 25);
...
}
void draw(){
    //Genera immagine
    mm.addFrame();
}

//Alla pressione della barra spaziatrice termina
void keyPressed() {
    if (key == ' ') {
        mm.finish();
        exit();
    }
}

 

Un'altra funzionalità della libreria video è la possibilità di catturare immagini da dispositivi di acquisizione video. E ovviamente, come sempre contraddistingue le API di Processing, usare questa funzionalità è molto facile.

Nella fase di setup si inizializza l'oggetto Capture e ogni volta che è disponibile un nuovo frame si legge dallo stream della periferica di acquisizione per ottenere l'ultima immagine. Questa è un oggetto di tipo PImage, e quindi su di esso è possibile operare come su una qualunque immagine caricata dal filesystem.

import processing.video.*;
Capture myCapture;

void setup()
{
    size(400, 300);
    //Inizializzo la periferica di cattura
    myCapture = new Capture(this, width, height, 30);
}

//Ogni volta che è disponibile in frame, catturo l'immagine
void captureEvent(Capture myCapture) {
    myCapture.read();
}

void draw() {
    //Mostro l'immagine sullo schermo
    image(myCapture, 0, 0);
}

 

Audio

Processing non fornisce nessuna libreria nativa per la gestione dell'audio, ma sono disponibili varie librerie open source.

Una delle più utlizzate è ESS [1], che permette di generare suoni in real-time, caricare sample audio, analizzarli usando le FFT e applicare effetti. Ha il difetto però di aver poca documentazione a supporto e di richiedere un certo livello di conoscenza del processing audio.

Un'altra libreria molto utilizzata è Sonia [2]: è basata su JSyn e, anche se permette di fare playback di audio e manipolazioni basilari, il suo focus è la sintetizzazione di suoni.
Una libreria che reputo interessante è Minim [3]: è basata su JavaSound e le su API sono pensate per essere facili da usare per utenti poco esperti pur mantenendo un buona flessibilità per usi più avanzati.
Le fasi di funzionamento di Minim sono parallele a quelle di Processing:

void setup()
{
    size(100, 100);
   
    //Avviare Minim prima di tutto
    Minim.start(this);
   
    //Carica il file dalla directory di dati
    AudioPlayer song = Minim.loadFile("mysong.wav");
    song.play();
   
    //Apre il flusso di line in
    AudioInput in = Minim.getLineIn();
   
    //Crea un flusso per l'output
    AudioOutput out = Minim.getLineOut();
   
}

Se il nostro scopo fosse stato quello di mandare solo in esecuzione un file audio, ora dovremmo solo creare un metodo stop() per chiudere correttamente Minim e tutti i flussi creati:

void stop()
{
    song.close();
    in.close();
    out.close();
    super.stop();
}

 

Se invece volessimo anche analizzare il segnale audio che arriva, nella funzione di draw potremmo usare il buffer dei canali per accedere ai valori istantanei del segnale, e, ad esempio, disegnare la forma dell'onda sonora.

 

//disegno la forma d'onda accostando tante linee lunghe 2 px
          //il valore di get(i) è sempre tra -1 e 1, quindi moltiplico per 50
          for(int i = 0; i < song.bufferSize() - 1; i++)
          {
              line(i, 50 + song.left.get(i)*50, i+1, 50 + song.left.get(i+1)*50);
              line(i, 150 + song.right.get(i)*50, i+1, 150 + song.right.get(i+1)*50);
          }

Oppure, volendo analizzare lo spettro sonoro invece che la forma d'onda, potremmo usare l'oggetto FFT (Fast Fourier Transform[4]).

setup()
{
    ...
    //Creo l'oggetto FFT passando la grandezza del buffer
    //del segnale e la sua frequenza di campionamento
    fft = new FFT(song.bufferSize(), song.sampeRate());
    ...
}

draw()
{
    //Prima analizzo un canale audio (left, right o mix)
    fft.forward(song.mix);
   
    //per ogni valore dello spettro calcolato
    //disegno una linea con l'ampiezza relativa
    //alla frequenza i getBand(i)
    for(int i = 0; i < fft.specSize(); i++)
    {
        line(i, height, i, height - fft.getBand(i)*4);
    }
}

 

Accesso ai dati

Uno dei possibili usi di Processing è sviluppare animazioni, e per questo abbiamo visto come gestire immagini, video e audio. L'altro grosso uso di Processing è la visualizzazione di dati.
A questo scopo esistono svariate librerie realizzate dalla community open source che si è sviluppata attorno a Processing. Di queste ne vedremo due: una per l'accesso a database e una per la gestione di file XML.

Database

La libreria Processing-MySQL [5], è un "mini-wrapper" attorno al JDBC driver per MySQL, sviluppato con lo scopo di permettere un utilizzo immediato e tralasciando gli scenari d'uso complessi.
Quello che segue è un esempio di codice per accedere ad una ipotetica tabella utenti.

MySQL msql = new MySQL( "localhost", database, user, pass, this );
msql.connect()
msql.query( "SELECT * FROM USERS" );
while (msql.next()) {
    println(msql.getString("name"));
    }
mysql.close( );

L'accesso al database da applet Java è però problematico: le policy di sicurezza permetto l'accesso solo al server dal quale la applet è stata scaricata (a meno che non sia digitalmente firmata), e inoltre chiunque potrebbe leggere, decompilando l'applet, la stringa di connessione e quindi connettersi a sua volta al database.

Per questi motivi è preferibile, nel caso di sviluppo di applicativi remoti, l'utilizzo di XML.

 

XML

Con la core library di Processing è disponibile una API molto semplice e compatta per leggere file XML. Si basa sull'oggetto XMLElement e permette di interrogare l'albero dell'XML DOM per ottenere gli elementi presenti nell'XML:

XMLElement xml = new XMLElement(this, "feed.xml");
XMLElement item = xml.getChild("channel/author");
println(item.getStringAttribute("email"));

Nel caso si volessero avere maggiori funzionalità per la gestione dell'XML esiste una libreria opensource che permette di interagire con il file xml in maniera più completa: si chiama proXML[6].

Rete e Web Services

Con le librerie XML appena esposte è possibile accedere anche a file che si trovano su server remoti, ma con Processing è possibile anche interrogare e ricevere dati da webservices.
La libreria di networking presente all'interno di Processing permette di usare in maniera semplificata la socket per scrivere e leggere dati direttamente dalla rete, ma come al solito la comunità open source ci è venuta in aiuto semplificando l'utilizzo di quello che è attualmente lo standard de-facto per la comunicazione client-server: web services.

Xmlrpclib [7] di Burak Arikan fornisce un'API per interrogare servizi remoti che espongono delle webAPI basate sul protocollo XMLRPC.

Switchboard [8] di Jeff Crouse permette invece di accedere alle informazioni esposte da molti dei servizi web 2.0 più famosi: Google, Yahoo, Del.icio.us, Amazon, ecc.

Altre librerie interessantiLa community opensource ha prodotto un'infinità di librerie [9] per estendere Processing.

In questo paragrafo ne vedremo alcune.

Simulazioni fisiche

Phisics [10], di Jeffrey Traer Bernstein, è un motore di simulazione fisico per particelle: calcola la posizione di "punti" sottoposti ad attrito, gravità e forze varie

CellNoise [11], di Carl-Johan Ros���n. è un algoritmo per generare valori randomici che però siano generati secondo la distribuzione di Poisson, quindi in maniere da sembrare più naturali.

Computer Vision

WebcamExtra [12] è una libreria general purpose per elaborare le immagini acquisite da una webcam. Basata su di essa, FaceDetect [13], permette di riconoscere visi all'interno delle immagini acquisite.

Integrazione con l'Hardware

Il SMS [14], Sudden Motion Sensor, è presente in tutti i laptop Apple dal 2005 in poi: questa libreria permette di interagire con esso.

Sempre sviluppato da Daniel Shiffman, Most Pixel Ever [15], permette di realizzare animazioni multi-schermo, su schermi collegati a computer differenti.

Conclusioni

In questo articolo abbiamo fatto una veloce carrellata delle principali librerie che permettono a Processing di interagire con l'esterno: video, audio, accesso alla rete. Ora che abbiamo gli strumenti per poter usare proficuamente queste librerie, nel prossimo articolo vedremo quali sono i concetti teorici che stanno dietro alla realizzazione di una "visualizzazione di dati".

Riferimenti

[1] ESS Audio library
http://www.tree-axis.com/Ess/

[2] SONIA SOUND LIBRARY for Java and Processing
http://sonia.pitaru.com/

[3] Minim audio library
http://code.compartmental.net/tools/minim/

[4] Wikipedia - Fast Fourier transform
http://en.wikipedia.org/wiki/Fast_Fourier_transform

[5] MySql Library for Processing
http://www.bezier.de/mysql/

[6] proXML
http://www.texone.org/proxml/

[7] xmlrpclib - XML-RPC library for Processing
http://plw.media.mit.edu/people/arikan/xmlrpclib/

[8] Switchboard - web service library for Processing
http://switchboard.sourceforge.net/

[9] Processing.org - Elenco delle librerie esterne
http://www.processing.org/reference/libraries/index.html

[10] traer.physics
http://www.cs.princeton.edu/~traer/physics/

[11] CellNoise
http://carljohanrosen.com/processing/

[12] JMyron cross-platform video capture library
http://webcamxtra.sourceforge.net/

[13] Face detect library per Mac
http://tokage.cafe24.com/facedetect/

[14] Processing Sudden Motion Sensor Library
http://www.shiffman.net/p5/sms/

[15] The Most Pixels Ever
http://www.mostpixelsever.com/

Condividi

Pubblicato nel numero
130 giugno 2008
Software Architect e sviluppatore, Simone ha esperienza decennale nello sviluppo di appicazioni web based (sette anni con ASP.NET). Vive a Milano dove lavora come "Senior Solution Developer" per Avanade. Ha partecipato a numerosi progetti Open Source, sia Java che .NET, ma attualmente si sta concentrando principalmente su SubText per aiutarlo…
Articoli nella stessa serie