Elaborazione digitale di immagini
Argomenti trattati:
1-Immagini digitali
2-Manipolazioni dei pixel
3-Manipolazioni geometriche
4-Decomposizione spettrale, filtraggio e compressione
5-Restauro di immagini degradate
6-Crittografia con le immagini
1-Immagini digitali
Un'immagine digitale bianco nero viene descritta da una matrice mxn di
pixels (contrazione di picture elements). Il generico pixel p(i,j), il
cui valore numerico puo' essere intero o reale, fornisce la luminosita'
del punto di coordinate (i,j) dell'immagine.
Formato PGM (Portable Gray Map). Nella
convenzione PGM il file che contiene le informazioni sull'immagine e' organizzato
nel modo seguente:
P2
# eventuali commenti
numero_righe, numero_colonne
valore_livello_bianco
p(1,1)
p(1,2)
.
.
p(1,n)
p(2,1)
p(2,2)
.
.
dove:
P2 indica al sistema che visualizzera'
il file sullo schermo che si tratta di una immagine bainco nero nel formato
PGM
# eventual commenti sono commenti
arbitrari preceduti da #
numero_righe e numero_colonne sono due
interi che determinano le dimensioni dell'immagine (matrice dei pixels)
valore_livello_bianco e' un intero che
determina il valore numerico del bianco (generalmente 255), mentre il nero
e' 0.
p(i,j) sono i valori numerici dei pixels
(fra 0 e valore_livello_bianco) relativi alla posizione (i,j). Essi sono ordinati
per righe.
Esistono diversi programmi per visualizzare un'immagine sullo schermo di
un computer. Due pacchetti che girano sotto linux sono xv e gimp.
Ad esempio, se immagine.pgm e' il nome di un file che contiene un'immagine
codificata come file PGM, allora il comando
xv immagine.pgm
visualizza sullo schermo il contenuto di immagine.pgm.
Esempio di file PGM
P2
# esempio semplice
4,4
255
0
0
0
0
0
255
255
0
0
255
255
0
0
0
0
0
La stessa immagine poteva essere memorizzata come
P2
# esempio semplice
4,4
255
0 0 0 0
0 255 255 0
0 255 255 0
0 0 0 0
File ASCII e file RAW
Un file PGM puo' essere memorizzato nella modalita' ASCII o nella modalita'
RAW.
Nella modalita' ASCII il valore del generico pixel viene scritto nella sua
rappresentazione decimale con caratteri ASCII. Ad esempio. se il valore del
pixel e' 123, vengono scritti i numeri 1,2 e 3, consumando quindi tre byte
di memoria. Nella rappresentazione RAW, il pixel il cui valore e' 123 viene
memorizzato con il singolo byte il cui valore e' 123. In questo modo un solo
byte e' sufficiente per ciascun pixel. La rappresentazione ASCII e' piu' comoda
perche' permette di essere visualizzata e manipolata piu' facilmente. Ha
lo svantaggio che e' piu' ingombrante. Noi useremo la rappresentazione ASCII.
Per semplicita' eviteremo di scrivere commenti nei file PGM.
Esempio 1. Costruiamo un'immagine 100x100 che abbia valori di grigio
che sfumano da 0 a 255 secondo la regola p(i,j)=i+j mod 256. Usiamo il linguaggio
FORTRAN 90. E' possibile comunque usare un qualsiasi altro linguaggio di programmazione
visto che non svolgiamo operazioni particolarmente complesse.
Program grigi
implicit none
integer :: i,j
open(file="grigi.pgm", unit=2)
write(2,'(A)') "P2"
write(2,*)100,100
write(2,*) 255
do i=1,100
do j=1,100
write(2,*)mod(i+j,256)
end do
end do
end program grigi
L'immagine che si ottiene in questo modo e' la seguente:
Esempio 2. Costruiamo una immagine 200x200 tale che il pixel di posto
(i,j) sia 255 (bianco) se i+j e' un numero primo, sia 0 (nero) altrimenti.
Per questo ci occorre una funzione (function in fortran) che dato un intero
p ci dice se p e' primo o no.
Program evidenzia_primi
implicit none
integer :: i,j,p,n
logical :: primo
n=200
open(file="primi.pgm", unit=2)
write(2,'(A)') "P2"
write(2,*)n,n
write(2,*) 255
do i=1,n
do j=1,n
if (primo(n*(i-1)+j)) then
write(2,*) 255
else
write(2,*)0
end if
end do
end do
end program evidenzia_primi
function primo(p)
implicit none
integer :: i,p,q
primo :: logical
q=sqrt(p*1.0)
primo=.true.
do i=2,q
if(mod(p,i)==0) then
primo=.false.
exit
end if
end do
end function primo
La figura che si ottiene e' la seguente
Un pochino piu' complicato, ma vale la pena
farlo, e' numerare i pixels a spirale che si dipana dal centro del quadrato.
In questo modo si ottiene la spirale di Ulam.
2-Manipolazione dei pixel
Esempio 3. Vediamo come e' possibile trasformare
un'immagine in negativo. Supponiamo di avere nel file foto.pgm una fotografia
che vogliamo leggere, trasformare in negativo e registrarla in un file diverso.
La trasformazione che dobbiamo applicare a ciascun pixel e' f(p)=255-p
Program negativo
implicit none
integer :: i,j,p,m,n
character(length=2) :: ch
open(file="foto.pgm", unit=2)
open(file="foto_negativa.pgm",
unit=3)
read(2,'(A)')ch
write(3,'(A)') ch
read(2,*)m,n
write(2,*)m,n
read(3,*)p
write(2,*) p
do i=1,m
do j=1,n
read(2,*)p
write(3,*)255-p
end do
end do
end program negativo
Esempio 4. Cosa succede dell'immagine se applichiamo la trasformazione
f(p)=min(255,p+20) oppure f(p)=max(0,p-20). Cosa succede invece se la
trasformmazione e' f(p)=min(255, 2p) oppure f(p)=parte_intera(p/3)? Osservate
che le operazioni di min e max servono a tenere il valore della funzione
dentro il segmento consentito [0,255]. Osservate ancora che occorre prendere
la parte intera. Mediante queste trasformazioni si cambiano globalmente la
luminosita' e il contrasto di una immagine. Volendo, potete aumentare il
contrasto e schiarire le zone scure lasciando la situazione inalterata nelle
zone chiare, ad esempio con
f(p)=p se p>128
f(p)=max(2p,128) se p<=128
Ancora provate a portare in negativo solo le zone "buie" dell'immagine con
f(p)=255-p se p<=128
f(p)=p se p>128.
Immagini a colori, modalita' RGB
Una immagine a colori puo' essere memorizzata mediante la modalita' RGB
(Red, Green, Blue). In questo modo ad ogni pixel viene assegnata una terna
di numeri r,g,b, dove r fornisce l'intensita' del rosso, g l'intensita' del
verde e b l'intensita' del blu. Il file che viene costruito e' organizzato
come segue
P3
# eventuali commenti
numero_righe, numero_colonne
massima_luminosita'
r(1,1) g(1,1) b(1,1)
r(1,2) g(1,2) b(1,2)
.
.
.
Cio' che cambia rispetto ad un file b/n e' la prima riga che contiene P3
a indicare che e' un file a colori nella modalita' RGB e la presenza delle
terne di pixels (un valore per ogni colore) anziche' dei singoli valori. Le
terne dei valori rgb possono non stare sulla stessa riga ma essere distribuite
su righe consecutive. I file di immagini a colori hanno generalmente l'estensione
PNM o PPM.
Potete provare a effettuare le manipolazioni di contrasto e luminosita'
sui singoli colori in modo diverso da colore a colore, oppure potete scambiare
il rosso col blu o portare solo il verde in negativo o mescolare i colori
su ciascun pixel secondo una regola prefissata, ad esempio, r'=3r+g-2b mod
256, g'=r+2g+b mod 256, b'=r-g+b mod 256 e vedere l'effetto sull'immagine.
Come e' possibile trasformare un'immagine da colori a b/n?
Esempio 5. (Insiemi di Julia e bacini di attrazione). Sapreste costruire
un'immagine che rappresenti i bacini di attrazione del metodo di Newton per
risolvere equazioni del tipo x^n-1=0?
Altri formati La
codifica di tipo PGM, anche nella modalita' RAW ha lo svantaggio di essere
molto ingombrante. Esistono altri modi di rappresentare file di immagini piu
o meno vantaggiosi. Un formato particolarmente usato, che pero' conduce ad
un degrado qualitativo dell'immagine e' il formato JPG. Esso si basa su tecniche
di compressione ottenute mediante trasformate di coseni. Vedremo piu' avanti
cosa questo significhi.
Esempio 6. videnziare i contorni. Sapreste affrontare il problema
di evidenziare i contorni di una immagine assegnata?