venerdì 19 dicembre 2014

Trasformare un'immagine in bianco e nero

Le immagini che usiamo, di solito, sono a colori. Tuttavia ci potrebbe interessare trasformarle in bianco e nero; ad esempio per dare un effetto di antico ad una foto.
Le foto che chiamiamo in bianco e nero, in realtà sono composte da diverse gradazione di grigio: cioè tutte le sfumature che vanno dal bianco fino al nero. In gergo informatico di dice in scala di grigi. In effetti i computer potrebbero creare un'immagine che usi solo il bianco e nero, ma perderemmo molti dettagli.
Ecco un esempio che mostra la stessa immagine con i tre diverse impostazioni:
Oggi vedremo come ottenere un'immagine in scala di grigi.
Prima di proseguire è meglio rinfrescare la teoria delle immagini in informatica. Ogni immagine è composta da puntini colorati, chiamati pixel. Ogni pixel è di un colore, ma questo colore si esprime attraverso quattro valori:
  1. quantità di trasparenza
  2. quantità di rosso
  3. quantità di verde
  4. quantità di blu
Le ultime tre sono semplici da capire,ogni colore si può ottenere mescolando opportune quantità di rosso, verde e blu. Il primo valore si usa solo in informatica, dove un'immagine può avere delle parti trasparenti o semi trasparenti. I valori delle quantità di solito variano da 0 a 255.
Per ottenere una sfumatura di grigio basta dare lo stesso valore ai tre colori fondamentali rosso, verde e blu. Il problema è: come calcolare questo valore?
Non esiste una regola scientifica per farlo, siccome è una trasformazione artificiale che noi imponiamo, sta a noi decidere il risultato che vogliamo ottenere.
Le tre modalità più utilizzate sono:
  • lucentezza
  • media
  • luminosità
Il metodo della lucentezza fa la media tra il massimo e il minimo dei valori dei colori fondamentali
Il metodo della media fa la somma dei valori dei colori fondamentali e li divide per 3.
Il metodo della luminosità usa una formula particolare: 0.3 * rosso + 0.59 * verde + 0.11 blu.
Oggi vedremo tutti e tre i casi.
Creiamo uno stack con due immagini uguali, che chiameremo rispettivamente partenza e arrivo. Poi mettiamo un menu a tendina con le tre possibili trasformazioni (che chiameremo tipo), un pulsante per eseguire la trasformazione e una scrollbar di tipo progress bar che ci mostrerà a che punto è l'elaborazione. In questo modo abbiamo fatto metà del programma senza scrivere una riga di codice, ottenendo un risultato simile a questo:

Livecode può fornire l'imageData cioè una serie di lettere, dove ognuna rappresenta una dei 4 valori di ciascun pixel. Con le funzioni charToNum() e numToChar() possiamo trasformare le lettere in valori e viceversa.
In rete si trovano molti esempi di codice per trasformare le immagini con Livecode, ma sono quasi tutti troppo lenti; il codice ottimizzato per la velocità sulle immagini è il seguente:

on mouseUp
   #memorizziamo i dati dell'immagine
   put the imageData of image "partenza" into tImage
   put the number of chars of tImage into totChars
   #contatore delle lettere   
   put 0 into cont   
   repeat for each char tChar in tImage
      add 1 to cont
      put cont mod 4 into cont2
      #cerchiamo di capire che valore sia (trasp., rosso , verde , Blu)
      switch cont2
         case 1 #trasparenza
            put tChar after tImage2
            break
         case 2 #rosso
            put chartonum(tChar) into rosso
            break
         case 3 #verde
            put chartonum(tChar) into verde
            break
         case 0 #blu
            put chartonum(tChar) into blu
            #qui cambiamo formula a seconda del tipo di trasformazione che preferiamo
            switch (the label of button "tipo")
               case "lucentezza"
                  put ( max(rosso, verde, blu) + min(rosso, verde, blu) ) / 2 into tGray
                  break
               case "media"
                  put (rosso + verde + blu) / 3 into tGray   
                  break
               case "luminosità"
                  put (0.3 * rosso + 0.59 * verde + 0.11 * blu) into tGray   
                  break
            end switch
            put numToChar(tGray) after tImage2
            put numToChar(tGray) after tImage2
            put numToChar(tGray) after tImage2
            break
      end switch            
      #qui ogni 1000 pixel aggiorniamo la barra dell'elaborazione
      if (cont mod 4000) = 0 then               
         set the thumbpos of scrollbar "elaborazione" to round(cont/totChars * 100 )
      end if
   end repeat            
   # impostiamo i dati per la nuoca immagine
   set the imageData of image "arrivo" to tImage2   
end mouseUp


Così possiamo vedere i risultati: