Skip to content Skip to navigation

OpenStax_CNX

You are here: Home » Content » Rappresentazione di Media in Processing

Navigation

Recently Viewed

This feature requires Javascript to be enabled.
 

Rappresentazione di Media in Processing

Module by: Davide Rocchesso, Pietro Polotti. E-mail the authors

Summary: Introduzione alla rappresentazione di suoni e immagini (colori, coordinate, ecc.) in Processing.

Note: You are viewing an old version of this document. The latest version is available here.

Elementi Visuali

Coordinate

L´elaborazione grafica in Processing utilizza un sistema di coordinate cartesiane 3D, come rappresentato in Figura 1.

Figura 1: Sistema di coordinate 3D in uso in Processing
Sistema di coordinate
Sistema di coordinate (coordinate.png)
L´elaborazione di immagini bidimensionali si effettua agendo sul piano X-Y, assumendo quindi la coordinata Z a zero. La funzione size() definisce la dimensione della finestra di display e stabilisce quale motore di rendering sarà utilizzato per disegnare su tale finestra. Il motore di default è JAVA2D, cioè la libreria di grafica bidimensionale di Java. Se si desidera operare sulle tre dimensioni è necessario impostare il rendering P3D (Processing 3D), particolarmente efficiente per la grafica su web, oppure OPENGL, che consente di delegare alla scheda grafica molte operazioni tipiche della grafica 3D.

Immagini

In Processing, una immagine può essere assegnata ad un oggetto di tipo PImage. La funzione loadImage("myImage") preleva il file (gif o jpg) myImage, contenente la codifica di una immagine, e restituisce in uscita il contenuto in pixel della immagine stessa, il quale può essere assegnato ad una variabile di tipo PImage. Il file myImage deve essere caricato nella cartella data della directory avente lo stesso nome dello sketch Processing al quale si sta lavorando.

Nota:

Quando si esegue il comando New, Processing apre una cartella di nome sketch_???????, all'interno di una directory Processing, corrispondente al nome assegnato dal sistema al file al quale si comincia a lavorare. Tale cartella è accessibile tramite i comandi del menu Sketch/Add File di Processing.
La classe PImage rende accessibili, mediante i campi width e height, rispettivamente la larghezza e la altezza della immagine caricata. Il contenuto è invece accessibile mediante il campo pixels[].

Esempio 1: Caricamento e visualizzazione di una immagine


	  size(400,300);
	  PImage b;
	  b = loadImage("gondoliers.jpg");
	  println("width=" + b.width + " height=" + b.height);
	  image(b, 0, 0, 400, 300); // position (0,0); width=400; height=300;
	  image(b, 20, 10, 100, 80); // position (20,10); width=100; height=80;
	

Colori

Poiché i nostri ricettori oculari di colore (coni), ciascuno sintonizzato su una regione di lunghezze d'onda, sono in numero di tre, i modelli di colore sono sempre riferiti ad uno spazio a tre dimensioni. Nei modelli di colore di tipo additivo vengono individuati tre assi coordinati, ciascuno corrispondente ad un colore base, e mediante miscelazione di tre corrispondenti fasci luminosi, si possono ottenere tutti i colori appartenenti ad un volume (gamut) individuato da tali assi. I tre colori base sono scelti in maniera arbitraria o, più spesso, sulla base del campo di applicazione (es., colore di una terna di fosfori o di laser). Nei processi di stampa si usano modelli di tipo sottrattivo, nei quali si parte da una superficie bianca e si usano inchiostri primari per sottrarre colore dal bianco.

Nota:

Guida ai modelli di colore: http://en.wikipedia.org/wiki/color_space

In Processing color è un tipo primitivo usato per specificare il colore. E' realizzato mediante un numero di 32 bit, in cui il primo byte specifica il valore alpha, e gli altri byte successivi specificano una terna nel modello RGB o in quello HSB. La scelta di un modello piuttosto che dell'altro è fatta mediante la funzione colorMode(). I colori rappresentabili mediante tre byte sono in numero di 256×256×256=16777216 256 256 256 16777216 .

Modello RGB

I colori si rappresentano con una terna di numeri, ciascuno rappresentante rispettivamente le intensità dei colori primari rosso (Red), verde (Green), e blu (Blue). Ciascun numero può essere un intero senza segno e quindi assumere valori tra 0 e 255, oppure essere espresso come un numero floating point compreso tra 0 e 1.0. Queste possibilità possono essere specificate mediante la funzione colorMode(). Il modello RGB è di tipo additivo.

Modello HSB

I colori si rappresentano con una terna di numeri, ciascuno rappresentante rispettivamente la tinta o lunghezza d'onda dominante(Hue), la saturazione (Saturation), e l'intensità o brillantezza (Brightness).

Nota:
Spesso il modello viene chiamato HSV, dove la V sta per Value.
La hue assume valori in gradi tra 0 (rosso) e 360, essendo le diverse tinte rappresentate lungo una circonferenza ed essendo il rosso convenzionalmente situato a 0 ˚ 0˚ . Saturation e brightness variano tra 0 e 100. La saturazione è il grado di purezza del colore. Se ad un colore puro viene aggiunta della luce bianca il suo grado di purezza diminuisce, fino a che il colore viene a trovarsi sulla scala dei grigi, in corrispondenza di saturazione nulla. In termini fisici, la brillantezza è proporzionale alla potenza spettrale. In termini intuitivi, la brillantezza aumenta con la intensità della luce. Lo spazio è ben rappresentato da un cilindro, con hue (scala nominale) arrangiata lungo la circonferenza, saturation (scala rapporto) arrangiata lungo il raggio, e brightness (scala intervallo) arrangiata lungo l'asse. Oppure si da una rappresentazione bidimensionale dello spazio, come nel color chooser del programma di elaborazione di immagini Gimp, rappresentato in Figura 2. Lungo la circonferenza sono visibili i tre colori primari (rosso, verde, e blu), che distano di 120 ˚ 120˚ l'uno dall'altro, separati dai tre colori secondari (magenta, ciano, giallo). Ogni colore secondario è il complementare del colore primario che gli sta di fronte nella circonferenza. Ad esempio, se alla luce bianca si toglie la componente verde, si ottiene una luce magenta. Il triangolo inscritto nella circonferenza ha un vertice che punta alla tinta di riferimento. Il lato opposto a tale vertice è adagiato sulla scala dei grigi, e quindi rappresenta colori a saturazione nulla e brillantezza variabile. Andando dal vertice di riferimento al lato ad esso opposto si ha una graduale diminuzione della saturazione.
Figura 2: Color chooser del software Gimp
Gimp color chooser
Gimp color chooser (gimp_color.gif)

Alpha channel

E' un byte di informazione usato per effettuare interpolazione tra immagini, ad esempio allo scopo di rendere la trasparenza. Esso si può ottenere, da una variabile di tipo color, con il metodo alpha(). La manipolazione dell'alpha channel si svolge mediante il metodo blend() della classe PImage.

Esempio 2: Caricamento e visualizzazione di una immagine con trasparenza

Tabella 1
gondolieri.gif

          
size(400,300);
PImage b = loadImage("gondoliers.jpg");
PImage a = loadImage("gondoliers.jpg");
float ramp = 0;
for (int j = 0; j < b.height; j++)
 for (int i = 0; i < b.width; i++) {
   b.set(i, j, b.get(i,j) + 
     color(0,0,0, 255 - (int)((1-ramp)*255)) );   
   ramp = ramp + 1/(float)(b.width * b.height); 
   }
a.blend(b, 0, 0, b.width, b.height,  
	80, 10, 450, 250, BLEND);
image(a, 0, 0, 400, 300);
          
	

In Processing, è possibile assegnare un colore ad una variabile di tipo color mediante la funzione color(), essendo il modello precedentemente stato definito mediante colorMode(). Le funzioni red(), green(), blue(), hue(), saturation(), e brightness() consentono di passare da un modello all'altro.


	  colorMode(RGB);
	  color c1 = color(102, 30,29);
	  colorMode(HSB);
	  color c2 = color(hue(c1), saturation(c1), brightness(c1));
	  colorMode(RGB);
	  color c3 = color(red(c2), green(c2), blue(c2));
	  // le variabili c1, c2, c3 contengono codifica dello stesso colore
	

Tinteggiatura di una immagine

Una immagine può essere tinteggiata con un colore e resa più o meno trasparente mediante assegnazione di un valore alpha. La funzione da usare a questo scopo è tint(). Ad esempio, per dare un tono blu all'immagine incastonata nel Esempio 1, è sufficiente far precedere il secondo comando image() da tint(0, 153, 204, 126) .

Traslazioni, Rotazioni, e Trasformazioni di Scala

Rappresentazione di Punti e Vettori

In computer graphics, punti e vettori sono rappresentati in

Definition 1: Coordinate Omogenee
quaterne di numeri, in cui i primi tre vanno letti nello spazio X-Y-Z, mentre il quarto denota un vettore se assume valore 0, e denota un punto se assume valore 1.
Una traslazione si ottiene sommando, in coordinate omogenee, un vettore a un punto, ed il risultato è, ovviamente, un punto. Oppure, si può vedere la traslazione come un prodotto matrice-vettore, dove la matrice è ( 1 0 0 t x 0 1 0 t y 0 0 1 t z 0 0 0 1 ) 1 0 0 t x 0 1 0 t y 0 0 1 t z 0 0 0 1 , e il vettore è quello che rappresenta il punto xyz1 x y z 1 . Una rotazione antioraria di un angolo θ θ rispetto all'asse z z (roll o rollio), viene realizzata mediante la matrice di rotazione ( cosθsinθ0 0 sinθcosθ0 0 0 0 1 0 0 0 0 1 ) θ θ 0 0 θ θ 0 0 0 0 1 0 0 0 0 1 . Rotazioni rispetto agli assi x x (pitch o beccheggio) e y y (yaw o imbardata) si realizzano con matrici di rotazione di tipo analogo, e la rotazione rispetto ad un asse arbitrario si può realizzare mediante composizione (moltiplicazione a sinistra) di rotazioni elementari rispetto a ciascun asse.

Traslazioni

La funzione translate() consente di spostare oggetti sulla finestra di immagine. Ammette due o tre argomenti, che sono rispettivamente gli spostamenti lungo le direzioni x x, y y (e z z).

Rotazioni

In due dimensioni, la funzione rotate() consente di ruotare oggetti sulla finestra di immagine. Ciò avviene mediante una moltiplicazione (a sinistra) delle coordinate di ciascun pixel dell'oggetto non ruotato per una matrice di rotazione. La rotazione avviene sempre rispetto all'angolo superiore sinistro (coordinate 00 0 0 ), e quindi va opportunamente accompagnata da una traslazione. L'angolo di rotazione viene fornito secondo la misura in radianti. Si ricordi che 2 π rad = 360 ˚ 2 rad 360 ˚ . Ad esempio, si inserisca la rotazione rotate(PI/3) prima del secondo comando image() in Esempio 1. In tre dimensioni, si possono usare le rotazioni elementari rispetto agli assi coordinati rotateX(), rotateY(), e rotateZ().

Trasformazioni di Scala

La funzione scale() consente di espandere o contrarre un oggetto mediante moltiplicazione per una costante delle coordinate dei punti che lo compongono. Se invocata con due o tre parametri, gli scalamenti possono anche essere diversi lungo i diversi assi cartesiani.

Elementi tipografici

Ogni strumento o linguaggio per la manipolazione di media offre anche la possibilità di lavorare con la parola scritta e con i suoi elementi visuali fondamentali: i caratteri tipografici.

L'aspetto di un tipo di carattere ha due componenti principali: il font e la dimensione.

Processing mette a disposizione la classe PFont ed i metodi loadFont() (per caricare un font ed assegnarlo ad un oggetto di classe PFont) e textFont() (per attivare un font con una specifica dimensione). Per poter essere caricato, il font deve essere stato precedentemente inserito nella directory data dello sketch corrente. Il tool Create Font, accessibile dal menu Tools di Processing, consente di creare le bitmap dei caratteri che si andranno ad usare e ne colloca il file relativo nella directory data. In seguito a queste operazioni preliminari, il font può essere usato per scrivere del testo, usando la funzione text(). Questa consente di collocare una stringa di caratteri nello spazio bidimensionale o tridimensionale, eventualmente inserendola all'interno di una box rettangolare. L'allineamento dei caratteri all'interno della box è governato dalla textAlign(). Nella configurazione di default, il testo scritto può essere sottoposto a trasformazioni spaziali come ogni altro oggetto. Se però si vogliono avere caratteri di alta qualità bisogna usare la direttiva textMode(SCREEN), la quale li colloca nella finestra immagine alla dimensione piena con cui sono stati creati. Per quanto riguarda il colore dei caratteri, esso può essere impresso con la funzione fill(), come per ogni altro oggetto grafico.

Esempio 3: Sovrapposizione di scritte

Tabella 2
pippo.gif


PFont fonte;
/*The font have been previously created 
in the data folder*/
fonte = loadFont("HoeflerText-Black-48.vlw");
textFont(fonte, 12);
fill(10, 20, 250, 80);
textAlign(RIGHT);
text("pippo pippo non lo sa", 10, 14, 35, 70);
fill(200, 0, 0, 100);
textMode(SCREEN);
text("ppn", 25, 5, 30, 90);

	

Processing consente anche un controllo completo dell'occupazione spaziale dei caratteri e della distanza tra caratteri contigui. La funzione textWidth() calcola l'estensione orizzontale di una carattere o di una stringa. Essa può essere usata, insieme alle coordinate esatte di posizionamento passate alla text(), per controllare il kerning ed il tracking tra caratteri. La textSize() consente di ridefinire la dimensione dei caratteri. La textLeading() ridefinisce la distanza in pixel tra linee contigue di testo. Questa distanza si misura tra le baseline su cui si adagiano le stringhe di caratteri. Lettere quali "p" o "q" si estendono al di sotto della baseline per una quantità di pixel calcolabile con textDescent(). Invece, la textAscent() restituisce l'estensione massima al di sopra della baseline (tipicamente, l'altezza della lettera "d").

Elementi Uditivi

Suoni

Processing non fornisce solamente un ambiente per la programmazione grafica, ma prevede anche la possibilità di utilizzare diverse funzionalità audio. Nella versione Beta sono disponibili due primitive di base, che consentono la semplice riproduzione dei file .wav: PSound e loadSound(). Quest'ultima permette di caricare un suono in una variabile di tipo PSound predefinita. Si possono caricare solo file .wav. Per poterli importare, i file di suono devono essere archiviati nella directory data dello sketch corrente. La sintassi è soundA = loadSound(filename), dove soundA è una variabile di tipo PSound. Per riprodurre i suoni i comandi a disposizione sono soundA.play(), oppure soundA.loop() se si vuole far suonare il campione in circolo. Una collezione di primitive più ricca è invece raccolta all'interno di una libreria denominata Sonia . Tale libreria contiene, per esempio, delle funzioni che permettono di riprodurre campioni audio (sample playback), di eseguire un'analisi di Fourier in tempo reale (ovvero un'analisi del suono che viene captato da un microfono collegato al computer: realtime FFT), nonchè di salvare dei file .wav sul disco. Per poter utilizzare la libreria Sonia è necessario scaricare il file .zip dal sito http://www.pitaru.com/sonia/. Bisogna poi decomprimere il tutto e copiare la directory Sonia_?_? dentro la directory Processing/libraries. Infine, dopo aver riavviato Processing, si deve aggiungere un comando import, selezionandolo direttamente dal menu Sketch / Import Library / Sonia_?_?.

Nota:

Le applet prodotte con Sonia, per poter essere eseguite all'interno di un browser, necessitano del plugin JSyn di Phil Burk che può essere scaricato e installato dal sito http://www.softsynth.com/jsyn/plugins/.
Come nel caso della primitiva loadSound(), per poter utilizzare dei campioni audio è necessario copiarli all'interno della cartella data, così come fatto nel caso delle immagini. A questo punto siamo pronti per poter imparare a lavorare con il suono in Processing.

Timbri

In questa sezione proveremo prima ad utilizzare e poi ad analizzare un'applicazione per l'esplorazione dei timbri, simile nella concezione al Color Chooser di Figura 2, denominata Sound Chooser. Per adesso possiamo pensare al timbro di un suono come al "colore" di un'immagine. O se si vuole possiamo pensare al timbro come al diverso "colore" dei diversi strumenti. Più avanti nel corso vedremo con maggior precisione a cosa corrispondono dal punto di vista fisico e percettivo sia il colore sia il timbro. Nella applet Sound Chooser si possono far suonare quattro suoni con timbri diversi, facendo click con il mouse su uno qualsiasi dei raggi. Ciascuno dei raggi corrisponde ad uno strumento musicale (timbro/colore) diverso. Cambiando posizione lungo il raggio e facendo click, è possible sentire come la brillantezza del timbro corrispondente cambia. Più precisamente, man mano che si procede verso il centro, il suono si fa vieppiù povero.

Trasformazioni

Vediamo ora in cosa consiste il codice Processing necessario per implementare il Sound Chooser nei tratti salienti. Il comando Sonia.start(this) è indispensabile per attivare il motore audio di Sonia. La linea Sample mySample1 dichiara una variabile atta a contenere campioni audio. A tale variabile possono essere applicati vari metodi, tra i quali il metodo play per riprodurre il campione. Nel loop() viene definito l'aspetto grafico della applet. Infine, tramite la funzione mouseReleased() viene rilevato quando il mouse viene rilasciato dopo essere stato premuto e in quale area del cerchiello. A quel punto una successione di condizioni if stabilisce quale strumento/timbro debba essere riprodotto a seconda del punto di interazione. Inoltre, all'interno della funzione mouseReleased() viene invocata un'altra funzione: filtra(float[] DATAF, float[] DATA, float RO, float WC). Questa funzione, che viene implementata alla fine del listato di questa applet, esegue un filtraggio sul suono che viene riprodotto. In particolare si tratta di un filtraggio passa-basso, vale a dire che lascia passare le basse frequenze ma non le alte. A seconda se il mouse viene rilasciato più o meno vicino al centro, l'effetto del filtraggio cambia. Più in particolare il filtraggio sarà più drastico (le alte frequenze sono maggiormente attenuate, con l'effetto di un maggior incupimento del suono) se il mouse viene rilasciato in prossimità del centro e il suono risulterà più povero (scolorito).

Tabella 3
Tromba
Oboe
Violino
Flauto
Applet: scelta di un timbro e controllo di brillantezza (brightness)

                 
import pitaru.sonia_v2_9.*;

Sample mySample1, mySample2, mySample3, mySample4;
Sample mySample1F, mySample2F, mySample3F, mySample4F;

float[] data1, data2, data3, data4;
float[] data1F, data2F, data3F, data4F;

int sr = 11025;  // sampling rate


void setup()
{
  size(200, 200);
  colorMode(HSB, 360, height, height);
  Sonia.start(this);

  mySample1 = new Sample("flauto.aif");
    mySample2 = new Sample("oboe.wav");
      mySample3 = new Sample("tromba.wav");
        mySample4 = new Sample("violino.wav");

  mySample1F = new Sample("flauto.aif");
 // ... OMISSIS ...

  data1  = new float[mySample1.getNumFrames()]; 
	  // creates new arrays the length of the sample
	  // for the original sound
 // ... OMISSIS ...

  data1F  = new float[mySample1.getNumFrames()]; 
	  // creates new arrays the length of the sample
	  // for the filtered sound
// ... OMISSIS ...


  mySample1.read(data1);
// ... OMISSIS ...

}

void draw()
{
// ... OMISSIS ...
}

void mouseReleased()
{

float ro;
float roLin;
float wc;


  // FLAUTO
  if ((mouseX > 95) && (mouseX < 105)&& (mouseY > 50)&& (mouseY < 90)) {

    roLin = (mouseY-49.99)/41;
    ro = pow(roLin,.33);
    wc = 298*(TWO_PI/sr);
    filtra(data1F, data1, wc, ro);

    mySample1F.write(data1F);
    mySample1F.play();
  }
// ... OMISSIS ...

}

//filtra = new function
void filtra(float[] DATAF, float[] DATA, float WC, float RO) {

  float G;
  float RO2;
  RO2 = pow(RO, 2);
  G = (1-RO)*sqrt(1-2*RO*cos(2*WC)+RO2)*4; // (*4) is for having it louder
 
  for(int i = 3; i < DATA.length; i++){
    DATAF[i] = G*DATA[i]+2*RO*cos(WC)*DATAF[i-1]-RO2*DATAF[i-2];
	  //filtraggio ricorsivo
  }
}

// safely stop the Sonia engine upon shutdown.
public void stop(){
  Sonia.stop();
  super.stop();
  }
            
             	      
	    

Exercise 1

Il contenuto di un oggetto PImage è accessibile mediante il suo campo pixels[]. I pixel della immagine, corrispondenti ad una lettura riga per riga, sono contenuti in questo array di dimensione width*height. Modificare il codice di Esempio 2 in modo da utilizzare il campo pixels[] invece del metodo get(), senza cambiare il funzionamento del programma.

Solution

Basta sostituire l'invocazione b.set() con la


	       b.set(i,j,b.pixels[j*b.width+i]+ color(0,0,0, 255 - (int)((1-ramp)*255)) );
	    

Exercise 2

Completare il codice riportato in Tabella 3 per ottenere l'applet Sound Chooser completa.

Exercise 3

Aggiungere ai raggi del Sound Chooser del colore, sostituendo le line con dei rect e colorando le barrette ottenute con una variazione di brillantezza, crescente dal centro verso l'esterno.

Content actions

Download module as:

Add module to:

My Favorites (?)

'My Favorites' is a special kind of lens which you can use to bookmark modules and collections. 'My Favorites' can only be seen by you, and collections saved in 'My Favorites' can remember the last module you were on. You need an account to use 'My Favorites'.

| A lens I own (?)

Definition of a lens

Lenses

A lens is a custom view of the content in the repository. You can think of it as a fancy kind of list that will let you see content through the eyes of organizations and people you trust.

What is in a lens?

Lens makers point to materials (modules and collections), creating a guide that includes their own comments and descriptive tags about the content.

Who can create a lens?

Any individual member, a community, or a respected organization.

What are tags? tag icon

Tags are descriptors added by lens makers to help label content, attaching a vocabulary that is meaningful in the context of the lens.

| External bookmarks