UNIVERSITÀ DEGLI STUDI DI TRIESTE Facoltà di Ingegneria Corso di Laurea in Ingegneria dell’informazione Curriculum in informatica Sviluppo e studio di un algoritmo genetico per la ricerca di un intervallo di colore in un’immagine digitale Relatore: Prof. Andrea SGARRO TESI DI LAUREA DI: ANDREA BIDINOST MATR. 83600156 Anno Accademico 2011/2012
107
Embed
Sviluppo e studio di un algoritmo genetico per la ricerca di un intervallo di colore in un'immagine digitale
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
UNIVERSITÀ DEGLI STUDI DI TRIESTE
Facoltà di Ingegneria
Corso di Laurea in Ingegneria dell’informazione
Curriculum in informatica
Sviluppo e studio di un algoritmo genetico
per la ricerca di un intervallo di colore
in un’immagine digitale
Relatore: Prof. Andrea SGARRO
TESI DI LAUREA DI:
ANDREA BIDINOST
MATR. 83600156
A n n o A c c a d e m i c o 2 0 1 1 / 2 0 1 2
2
3
Indice
INTRODUZIONE………………………………………...………………6
1 LA SEGMENTAZIONE ..................................................................... 7
1.1 Il colore e lo spazio di colore .................................................................................... 7
1.2 Panoramica sulla segmentazione .............................................................................. 9
1.3 Tecniche di segmentazione........................................................................................ 9
1.3.1 Segmentazione a soglia ..................................................................................... 9
1.3.2 Accrescimento delle regioni.......................................................................... 11
1.3.3 Divisione e Fusione ....................................................................................... 12
Desidero ringraziare la mia famiglia, per avermi accompagnato in questi mesi di
duri sforzi. Ringrazio il professor A. Sgarro per avermi dato l’opportunità di
approfondire quest’interessante argomento, con pazienza e curiosità. Ringrazio
il dott. Felice Andrea Pellegrino per l’aiuto nella stesura dei primi argomenti.
Infine vorrei ringraziare i miei amici ed i miei fratelli, per essermi stati accanto
ed aver fatto il tifo per me, come sempre.
6
Introduzione
Il presente lavoro di tesi si propone di sviluppare e studiare il problema della
ricerca di determinate tonalità di colore all’interno di un’immagine digitalizzata,
attraverso un algoritmo genetico.
Si è voluto quindi sviluppare un software per l’implementazione di tale
algoritmo e per lo studio delle sue caratteristiche.
Nel primo capitolo viene presentata la nozione di spazio di colore e vengono
fornite brevemente ed in modo informale alcune tecniche di Segmentazione di
immagini digitali. Questi algoritmi, permettono di estrarre informazioni
dall’immagine in modo automatico.
Nel secondo capitolo viene illustrata la tecnica degli algoritmi genetici per la
risoluzione di alcuni problemi (prevalentemente di carattere geometrico-
matematico). Ne vengono descritte le caratteristiche, il funzionamento, le
potenzialità ed i limiti. Inoltre vengono presentate alcune applicazioni in cui
sono stati utilizzati.
Nel terzo capitolo viene descritto l’algoritmo sviluppato e viene mostrato il suo
funzionamento attraverso l’interfaccia grafica predisposta.
Nel quarto capitolo vengono forniti i risultati di alcuni test effettuati
sull’algoritmo, attraverso cui si è potuti giungere a conclusioni riguardanti limiti
di efficacia ed efficienza. Al termine del capitolo vengono inoltre proposte due
possibili applicazioni: il rilevamento di un’area di calore ed il tracciamento di
una traiettoria.
Al termine, in Appendice A, è riportato il codice scritto per l’implementazione.
7
C a p i t o l o 1
LA SEGMENTAZIONE
1.1 Il colore e lo spazio di colore
Il colore viene percepito dall’occhio umano in base alla radiazione luminosa
emessa dall’oggetto osservato. I fotorecettori posti all’interno del bulbo oculare
possono inviare tre stimoli nervosi diversi a seconda della lunghezza d’onda del
segnale luminoso che colpisce quella particolare regione della retina.
Combinando tra lori i diversi stimoli, il nostro cervello è in grado di associare il
colore presente in quella particolare regione. È quindi naturale scegliere tre colori
“elementari” capaci di generare ognuno uno stimolo nervoso diverso. Ad
esempio, questi colori possono essere il magenta (Magenta), il giallo (Yellow) ed
il ciano (Cyan). Essi sono detti detti colori primari sottrattivi, poiché sono in
grado di generare gli altri colori in base ad una mescolanza sottrattiva1.
Figura1.1: Mescolanza sottrattiva dei colori ciano, giallo e magenta
Tuttavia, i colori possono essere generati anche tramite una mescolanza di tipo
additivo 2. I tre colori primari additivi, utilizzati nell’ambito elettronico, sono il
rosso (Red), il blu (Blue) ed il verde (Green).
1 La lunghezza d’onda del colore risultante è una radiazione “filtrata” dalla presenza di altri
colori che assorbono ognuno una componente della luce solare. Ad esempio, si può pensare a due inchiostri, uno giallo ed uno ciano, che si sovrappongono: una parte della luce viene assorbita dall’inchiostro giallo, un’altra parte dall’inchiostro ciano e la rimanente viene riflessa dando origine al verde. La riflessione di tutte le radiazioni luminose genera il bianco, mentre l’assorbimento di queste genera il nero. 2 La lunghezza d’onda del colore risultante è una radiazione “combinata”. Le radiazioni,
infatti, colpiscono nello stesso istante di tempo la retina: in questo modo, vengono propagati stimoli nervosi per ogni lunghezza d’onda incidente. L’informazione viene poi rielaborata dal cervello che “costruisce” il colore percepito. La presenza di tutte le radiazioni all’interno dell’occhio genera il bianco, mentre l’assenza genera il nero.
8
Figura 1.2: Mescolanza additiva dei colori rosso, blu e verde
Sia per mescolanza sottrattiva che additiva, è possibile quindi generare un colore
a partire da tre colori primari. In quest’ottica è possibile descrivere uno spazio di
colore. Infatti, assegnando ad ogni colore primario un valore numerico che ne
indica l’intensità, è possibile costruire uno spazio a tre dimensioni. Una volta
stabilita la natura delle dimensioni ed i valori numerici di massimo e di minimo, è
possibile costruire un modello di colore. Il modello di colore classico per la codifica
e l’archiviazione delle immagini digitali è l’RGB, in cui le dimensioni
corrispondono ai colori primari additivi ed ogni intensità va da un valore di
minimo pari a zero, ad un valore di massimo pari a 255.
Negli anni ’70 è stato introdotto anche la dimensione A (alpha), che rappresenta
la trasparenza o l’opacità del colore stesso. Per la memorizzazione digitale di un
colore nel modello ARGB, sono necessari 4 byte, ognuno per codificare un
numero da 0 a 255 associato alla dimensione corrispondente.
9
1.2 Panoramica sulla segmentazione
La segmentazione di un’immagine consiste nella divisione dell’immagine in
regioni significative. Successivamente, vi sono molteplici utilizzi. Ad esempio
l’immagine può essere partizionata per la rilevazione3 e/o il riconoscimento4 di
oggetti. Attraverso la segmentazione è possibile tracciare la traiettoria di un
oggetto presente in più fotogrammi in sequenza. Inoltre, è utilizzata nella
compressione digitale. L’immagine viene così trasformata in qualcosa di più
significativo e facile da analizzare attraverso un sistema automatico.
La segmentazione classifica i pixel dell’immagine, raggruppandoli in insiemi
aventi caratteristiche comuni (di colore, di luminosità, etc…).
1.3 Tecniche di segmentazione
1.3.1 Segmentazione a soglia (Hassan, 1989; Otsu, 1979)
Si basa sulle informazioni ottenibili dall’istogramma di colore5. Nel caso
più semplice, viene fissata una soglia di separazione in corrispondenza di
3 La rilevazione di un oggetto permette di stabilire la sua presenza o assenza all’interno
della scena 4 Il riconoscimento permette di associare una porzione dell’immagine ad uno specifico
oggetto 5 Istogramma che rappresenta la distribuzione dei colori in un’immagine. In ascissa sono
presenti le tonalità di colore (solitamente RGB) ed in ordinata il numero di pixel aventi quella determinata tonalità. Di seguito è illustrata un’immagine con il relativo istogramma di colore.
Figura 1.3: Immagine originale ed esempio di immagine segmentata
10
un certo livello di grigio presente nell’istogramma (per questo è detta
anche Sogliatura a livelli di grigio).
Figura 1.4: Istogramma di un’immagine a livelli di grigio con relativa soglia T
I pixel dell’immagine apparterranno quindi ad una regione o all’altra.
L’immagine risultante sarà in bianco e nero, dove il colore è deciso
dall’appartenenza o meno alla regione selezionata.
La Sogliatura può anche essere effettuata in base a diverse tonalità di colore.
In questo caso, si costruiscono più istogrammi e vengono fissate più soglie
di colore.
Esempio 1.1
Esempio di applicazione dell’algoritmo di “Sogliatura a livelli di grigio” ad un’immagine in bianco e nero, nel cui istogramma sono presenti in ordinata i livelli di grigio. In questo caso, sono state utilizzate 2 soglie per limitare le regioni delle tonalità interessate.
Figura 1.5: Immagine originale e segmentata tramite Sogliatura a diversi livelli
11
Il principale vantaggio è dato dalla semplicità d’implementazione.
Tuttavia questo algoritmo non tiene conto dell’informazione spaziale degli
elementi interni alla foto.
1.3.2 Accrescimento di regioni (Y.L. Chang, 1994)
Si basa sul suddividere l’immagine in molteplici regioni distinte Ri, unendo
poi quelle regioni adiacenti che verificano una determinata condizione
H(R). L’algoritmo è suddiviso in due fasi: inizializzazione ed
accrescimento.
Inizializzazione: L’immagine viene suddivisa in un determinato
numero di regioni elementari (al limite, una regione può contenere
un singolo pixel). Dopodiché vengono scelte quelle regioni che
presentano un alto valore della funzione di omogeneità H(Ri)6
Accrescimento: data una condizione di omogeneità tra regioni distinte
H(Ri Rj), in maniera iterativa le coppie di regioni contigue
vengono valutate dalla funzione H ed eventualmente aggregate in
una nuova regione.
Esempio 1.2
Stabilita una certa soglia , si aggreghino le regioni Ri ed Rj solo se vale la
disequazione:
≥
Dove è il numero di pixel di contorno aventi contrasto inferiore ad una certa soglia
e comuni alle due regioni e Pm è la lunghezza del perimetro della regione più piccola.
I principali vantaggi di questa tecnica sono l’elevata qualità ottenibile
rispetto alle altre tecniche di segmentazione e l’adattabilità a qualsiasi
tipo di immagine, attraverso un’opportuna costruzione della funzione
di omogeneità.
6 Funzione che valuta la presenza e la quantità di caratteristiche comuni appartenenti ai
pixel di una determinata regione. Ad esempio, si può confrontare la luminosità, la presenza di un certo colore elementare RGB o la varianza dalla media RGB della regione. È possibile anche la valutazione della presenza di più caratteristiche in una stessa regione.
12
Tuttavia questa tecnica richiede uno studio molto accurato della fase di
inizializzazione (regioni troppo grandi possono dar luogo a pixel non
omogenei, regioni troppo piccole richiedono più tempo per essere
unite tra loro) ed è caratterizzata da un elevato onere computazionale
(dovuto alla scansione e valutazione delle singole regione ed alla
valutazione dell’omogeneità sulle varie combinazioni possibili di
regione-regione adiacente).
1.3.3 Divisione e Fusione
L’algoritmo si compone di due fasi:
Fase di Divisione: Questa fase è ricorsiva. Inizialmente si considera
l’immagine intera e la si valuta attraverso una certa funzione di
omogeneità H(R). Se il risultato è soddisfacente, l’algoritmo
termina. Altrimenti si suddivide la regione in 4 sotto-regioni di
uguale dimensione e si itera il procedimento su ogni regione. Si
viene così a formare una struttura ad “albero quaternario”, come
mostrato in figura:
Figura 1.6: Suddivisione in una regione in sotto-regioni e albero quaternario corrispondente
13
Fase di Fusione: Poiché la fase di divisione crea blocchi sempre più
piccoli (sovra-segmentazione), è necessaria una procedura di
rilassamento ed unione di quei sotto-blocchi che darebbero luogo
ad una regione con alta funzione di densità. L’esempio sottostante
può chiarire il problema:
Esempio 1.3:
Poiché l’immagine sottostante non è omogenea, viene divisa in 4 blocchi.
Tuttavia solo un blocco dovrebbe essere separato, mentre gli altri 3
dovrebbero dare luogo alla stessa regione
Per la fusione si adotta una struttura dati chiamata RAG (“Region
Adjacency Graph o grafo delle regioni adiacenti). Questo grafo
pesato contiene in ogni nodo una regione (R1,…,Rn). Soltanto le
regioni adiacenti sono collegate da un arco, il cui peso è il costo
che si sosterrebbe nel fondere insieme i due blocchi. Il costo
esprime l’incremento dell’errore in termini della funzione di
omogeneità utilizzata. A ciascuna iterazione si fondono in un unico
nodo (e in un unico blocco) le due regioni che comportano un
costo minore. La computazione termina quando tutti i costi sono
troppo elevati per sostenere una fusione.
Figura 1.7: Immagine originale. Immagine dopo la fase di Divisione e dopo la Fusione delle zone omogenee.
R1 R1 R3 R4
R2 R1
R2
14
Il principale vantaggio di questa tecnica è lo sfruttamento
dell’informazione sia spaziale (in termini di regioni adiacenti) che
cromatica.
La qualità della segmentazione dipende però dalla grandezza minima dei
blocchi ed aumentare la qualità del risultato comporta un maggiore onere
computazionale.
1.3.4 Clustering
Vengono costituite classi di pixel, raggruppati in base ad una determinata
caratteristica (luminanza, contrasto, livello di grigio, etc…). Dallo spazio
bidimensionale dell’immagine si passa quindi allo spazio delle
caratteristiche, nel quale vengono raggruppate le varie porzioni di
immagine aventi una o più caratteristiche comuni. Si perde così
l’informazione spaziale, che dovrà essere recuperata mediante un
raffinamento successivo (pixel adiacenti appartenenti alla stessa classe
costituiranno una regione omogenea).
Figura 1.8: Esempi di gruppi di classi e di processo di raggruppamento in base alle caratteristiche
Il Raggruppamento è una tecnica generale di suddivisione di un insieme di
dati (detti oggetti), introdotta da Robert Tryon nel 1939 (R.C. Tryon,
1970). Le basi di un algoritmo di raggruppamento sono :
La creazione dello spazio multidimensionale delle caratteristiche
La definizione della funzione Fs di misura della similarità tra due
oggetti (distanza)
La definizione del criterio di appartenenza ad una classe
15
La principale tecnica utilizzata è l’algoritmo K-means, che osserva i seguenti
passi:
1. Fissato un numero K di classi, si attribuisce casualmente una classe
a ciascun oggetto(pixel)
2. Per ogni classe, si calcola il centroide (punto medio) degli oggetti
3. Ogni oggetto viene assegnato alla classe al cui centroide è più vicino
4. Se l’algoritmo converge7, ci si fermi, altrimenti si riparta dal punto
2
L’algoritmo non garantisce il raggiungimento di un ottimo globale, ma può
essere ripetuto più volte per ottenere più risultati su cui scegliere la
soluzione migliore.
Inoltre, l’efficacia dipende dal numero e dalla composizione dei cluster, per
cui si può utilizzare un’esplorazione euristica dell’immagine in sostituzione
del punto 1 dell’algoritmo.
1.3.5 Segmentazione a bacini
L’idea è quella di pensare all’immagine come ad un insieme di argini e
bacini, inizialmente vuoti. Questa distinzione viene fatta in base alla
luminosità di ciascun pixel. Inizialmente i bacini sono vuoti, poi vengono
riempiti d’acqua fino a che le acque di bacini distinti non si congiungono.
A questo punto, le acque vengono separate da una “diga”. Al termine
dell’algoritmo, le dighe rappresenteranno il contorno degli oggetti presenti.
Più in dettaglio, il procedimento è il seguente:
1. Si assegni ad ogni pixel un valore di luminosità
2. Partendo dal valore inferiore di luminosità λ, si scelgano tutti quei
pixel aventi luminosità λ. I pixel adiacenti ed i pixel isolati
costituiranno il primo gruppo di regioni R1,..,Rn.
3. Si alzi il livello di luminosità λ’. I pixel adiacenti alla regione Ri si
uniranno ad essa.
4. Si continui ad alzare il livello di luminosità e ad accrescere le
regioni fino ad una soglia scelta , che si ritiene possa creare una
distinzione tra le forme presenti.
7 La convergenza è data dal non cambiamento della composizione delle partizioni o dal
raggiungimento di una distanza minima tra oggetti e centroidi determinata a priori.
16
5. Superata quella soglia, ogni volta che alcune regioni si uniranno
(poiché i pixel di confine avranno una luminosità abbastanza
elevata), i pixel che dovrebbero essere annessi costituiranno invece
una parte dei contorni degli oggetti presenti
6. Al termine, tutti i contorni risulteranno uniti (formando delle
dighe) e le regioni rappresenteranno la forma dei vari oggetti
presenti (paragonabili a dei bacini pieni d’acqua).
Un esempio è dato dalla figura sottostante:
Il principale svantaggio di questa tecnica è che, scelto un troppo basso,
si costruiranno un numero molto elevato di piccole regioni (sovra-
segmentazione)
1.3.6 Contorni Attivi (Michael Kass, 1988)
Attraverso la tecnica dei Contorni Attivi, si vogliono distinguere gli oggetti
dal resto della scena identificandone i bordi. L’immagine viene
trasformata in una “mappa di forze” che agiscono su una linea curva
(detta snake) per farla aderire al contorno dell’oggetto desiderato. Questa
tecnica, diversamente dalle precedenti, richiede un’interazione con
l’utente, che dovrà prima di tutto tracciare il primo snake in prossimità
del bordo dell’oggetto specificato. Più in dettaglio ed in riferimento ad
un’immagine a livelli di grigio, l’algoritmo è il seguente:
1. L’utente tracci una curva chiusa (snake) in prossimità dell’oggetto
di cui si vogliono definire i bordi.
2. Si associ ad ogni pixel un valore che dipende dalla distanza al
bordo più vicino (un bordo è riconoscibile per l’elevato valore di
gradiente8) e che caratterizzerà la “forza” (energia esterna) che
8 Associando ad ogni pixel un livello nella scala di grigio, il gradiente di un pixel è
paragonabile alla variazione di intensità tra i suoi pixel “confinanti”. E’ plausibile ottenere un alto valore di gradiente alla presenza di due oggetti distinti separati da un bordo.
Figura 1.9: Evoluzione temporale della segmentazione "a bacini"
17
eserciterà sullo snake, nell’eventualità che esso passi per quel luogo.
L’energia esterna può essere calcolata seguendo una formula del tipo:
Dove Exy rappresenta l’energia esterna associata al pixel di
coordinate (x,y) e (xb,yb) rappresentano le coordinate del bordo più
vicino.
3. Si valuti l’energia interna associata allo snake, ovvero l’attitudine ad
allungarsi ed a curvarsi (decisa a priori dall’utente), seguendo una
formula del tipo:
Dove s(x,y) è l’equazione parametrica dello snake, α è un
coefficiente legato alla tensione della curva proporzionale alla
capacità di allungamento e β è un coefficiente legato alla rigidità
della curva, inversamente proporzionale alla sua capacità di
deformazione.
4. Si facciano agire le forze esterne sulla curva, che si poserà su zone
di gradiente minore (ad energia meno elevata), modificando la
propria energia interna.
5. L’algoritmo si interrompa se la somma di forze esterne ed interne
agenti sulla curva raggiunge un minimo, altrimenti si ritorni al
punto 3.
L’efficacia dell’algoritmo dipende dai valori iniziali scelti per α e β, nonché dalla
funzione secondo la quale calcolare energia interna ed esterna.
Figura 1.10: Immagine a livelli di grigio, mappa delle forze esterne, immagine segmentata
18
19
C a p i t o l o 2
GLI ALGORITMI GENETICI
2.1 La storia
Gli algoritmi genetici furono inventati formalmente da John Holland negli anni
sessanta e furono sviluppati negli anni sessanta e settanta. Lo scopo originale di
Holland era quello di studiare il fenomeno dell’adattamento delle specie così
come avviene in natura, per poi riproporlo come tecnica risolutiva nell’ambito
dei problemi nei sistemi informatici.
Nel libro intitolato “Adaptation in Natural and Artificial Systems” (Holland, 1975),
l’algoritmo genetico viene presentato come un’astrazione dell’evoluzione
biologica e vengono fornite metodologie teoriche per la modellizzazione della
realtà tramite un AG (Algoritmo Genetico).
2.2 Terminologia biologica
Per creare un collegamento con la teoria genetica anche a livello di
nomenclatura, è necessario introdurre alcuni termini che saranno poi utilizzati
nella descrizione dell’algoritmo.
Ogni AG opera su un insieme di elementi candidati a diventare soluzione di un
problema (ad esempio, un punto generico nel piano per un problema di
massimizzazione di una funzione). L’insieme di questi elementi si chiama
popolazione o generazione. Particolarità degli AG è di agire su popolazioni di “pochi
elementi” (nell’ordine delle decine o delle centinaia). Ogni elemento della
popolazione si chiama fenotipo e deve essere codificato in una struttura formata
da dati elementari, chiamati geni. La scelta della particolare struttura adottata è
fondamentale per la risoluzione del problema mediante una strategia genetica.
Scelta una struttura, una determinata sequenza di geni si chiama genotipo o
cromosoma.
20
Esempio 1.
Si può ad esempio codificare un punto del piano di fenotipo (5,12) come una sequenza di
bit (dove ogni bit rappresenta un gene), in cui i primi 4 bit rappresentano il numero 5 e gli
ultimi 4 rappresentano il 12. Questo è il relativo genotipo:
01001100
Ogni gene è rappresentato da un bit.
Questo punto può essere una soluzione candidata al probelma di massimizzare la funzione
f1(x) = x+2y.
Esempio 2.
Si può, ad esempio, voler codificare una funzione, come f2(x)=x2 + 3x + 1. A questo punto,
possono essere scelte 2 codifiche per i genotipi: una mediante stringhe di bit ed una
mediante albero binario.
La codifica mediante stringhe di bit associa ad una sequenza di n bit un particolare
valore univoco.
Codificando
Si ha:
11111000010000110100111101000001
x 2 + 3 * x + 1
dove ogni bit rappresenta un gene.
La codifica mediante albero binario rappresenta i geni tramite nodi dell’albero.
Seguendo una visita in ordine posticipato, si può riconoscere la funzione
Ogni genotipo, quindi, codifica un fenotipo e rappresenta una possibile
soluzione del problema modellizzato. Si chiama spazio di ricerca l’insieme di tutti i
possibili valori che può assumere il fenotipo codificato mediante un particolare
genotipo.
Carattere Codifica binaria
x 1111 2 1000
+ 0100
* 0100
3 0011
1 0001
+ + 1
3
*
x x
^2
21
Se il genotipo è una stringa di 4 bit, lo spazio di ricerca comprenderà 15 elementi (con o senza segno).
Ad ogni cromosoma viene associato un valore che lo legherà (direttamente o
meno) alla probabilità di essere scelto come buona soluzione e quindi di poter
dare origine ad un elemento figlio che erediterà alcuni suoi “caratteri genetici”.
Questo valore si chiama valore di valutazione ed è calcolato tramite una funzione
detta funzione di valutazione. Può rappresentare il fenotipo stesso, la distanza tra
due punti o tra due valori (si pensi ai problemi di approssimazione o di
interpolazione) o qualsiasi altra entità. In base al valore di valutazione, viene
calcolato un altro valore, chiamato valore di idoneità calcolato tramite la funzione di
idoneità. Questo valore rappresenta la “bontà” del cromosoma come possibile
soluzione e sarà tanto maggiore quanto migliore sarà il genotipo.
Per il probelma di massimo presentato nell’ esempio 1, la funzione di valutazione potrebbe
semplicemente essere la stessa funzione:
Funzione di valutazione = f1(x,y)
Il relativo valore sarà allora:
Valore di valutazione = f1(5,12) = 5 + 2*12 = 29
La funzione di idoneità potrebbe restituire la differenza tra il valore di valutazione e la
media dei fenotipi:
Funzione di idoneità per (xi,yi) = –
Dove N rappresenta il numero degli elementi della popolazione. Una funzione di idoneità
altrettanto valida potrebbe rappresentare il rapporto tra il valore di valutazione e l’insieme di
tutti i valori di valutazione, dando luogo ad un possibile valore di probabilità:
0 ≤
≤ 1
Per l’evoluzione della popolazione, ogni genotipo sarà soggetto (con una certa
probabilità) ad operazioni di selezione, incrocio, mutazione.
Nel processo di selezione, vengono scelti una coppia di cromosomi appartenenti
all’attuale popolazione, in base al valore della loro funzione di idoneità. Questo
processo è l’equivalente della selezione naturale.
22
Nel processo di incrocio, i geni dei due cormosomi scelti vengono mescolati
(totalmente a caso, oppure scegliendo uno o più punti di taglio), dando origine
ad uno o più nuovi cromosomi. Con questo processo si modellizza la
riproduzione sessuata.
Nel processo di mutazione, uno o più geni del cromosoma generato vengono
mutati (un bit può venire invertito, un valore di un nodo di un albero binario
può essere cambiato, etc…). Questa operazione è l’equivalente della mutazione
genetica e potrà essere sfruttato per rendere “più variegato” il campione.
Può essere poi presente un valore obiettivo, ovvero una soglia di tolleranza entro
cui si stabilisce a priori che una determinata soluzione è accettabile per il
problema, anche se non ottima (ad esempio, la soglia di tolleranza
nell’interpolazione di funzioni). Raggiunto questo valore, il processo di
evoluzione può fermarsi.
Infine, con il termine pressione di selezione si indica il grado con cui l’algoritmo
(l’ambiente) predilige individui con alto valore di idoneità rispetto a quelli con un
basso valore di idoneità.
Figura 2.1: Esempi di incrocio di 2 cromosomi, scegliendo uno o più punti di taglio
23
2.3 Funzionamento di un AG
Ogni algoritmo genetico segue una sequenza di passi che modellizzano
l’evoluzione naturale di una popolazione in un determinato ambiente (Ehud
Lamm, 2011):
1. Si generi una popolazione casuale di N cromosomi
2. Si calcoli il valore di valutazione ed il valore di idoneità di ogni
cromosoma nella popolazione
3. Si ripetano i seguenti i seguenti passi finchè non siano stati creati N
nuovi cromosomi
a. Selezione: si scelgano casualmente 2 cromosomi dalla popolazione
attuale. La probabilità di essere scelti deve dipendere dal valore di
idoneità dei cromosomi. Tanto più è alta l’idoneità di un
cormosoma, tanto più spesso sarà scelto per la riproduzione.
b. Incrocio: si effettui con probabilità pc un incrocio dei genotipi dei
genitori scelti per creare un nuovo cromosoma, altrimenti si
scelga un genitore come nuovo elemento.
c. Mutazione: per ogni gene presente nel nuovo genotipo, lo si muti
con probabilità pm
d. Si inserisca il nuovo elemento nella nuova popolazione
4. La nuova popolazione prenda il posto della popolazione corrente
5. Se esiste ed è stato raggiunto un valore obiettivo, ci si fermi, altrimenti si
riparta dal punto 2.
Questa sequenza è da ritenersi approssimativa, poiché in base al particolare
problema affrontato, è possibile scegliere di alterare i processi di selezione,
incrocio e mutazione per ottenere risultati migliori.
24
2.4 Schema
Un importante nozione nell’ambito degli AG è quella di Schema, introdotta da
Holland nel suo libro. Lo schema H rappresenta un blocco costitutivo di
soluzione, ed è codificato da una stringa di caratteri 1/0/* (non importa).
Rappresenta una determinata disposizione di caratteri all’interno di una stringa di
bit.
Il fenotipo 9 può essere rappresentato dal genotipo 1001, che appartiene agli schemi:
Il concetto deriva dalla scienza dei metalli, dove la ricottura è usata per
eliminare difetti reticolari dai cristalli, tramite il riscaldamento ed un
lento raffreddamento.
È utilizzato per trovare un minimo globale in presenza di più minimi
locali. Lo schema è il seguente:
Genera una soluzione corrente xc, un numero di passi massimi Rmax ed una temperatura T
30
For r =1 To Rmax do
While (non si è ottenuto un valore accettabile) do
xn = vicino di xc
Δ = f(xn) – f(xc)
u = casuale in (0,1]
if (Δ < 0) or ( Δ
< u) then di xc = xn
End while
Diminuisci T
End for
Soglia di accettazione (Dueck, 1990):
Ciò che nell’esercizio precedente era rappresentato da una temperatura
T, ora è rappresentato da un valore di soglia τ.
Genera una soluzione corrente xc, un numero di passi massimi Rmax ed una soglia
τ
For r =1 To Rmax do
While (non si è ottenuto un valore accettabile) do
xn = vicino di xc
Δ = f(xn) – f(xc)
if (Δ < τ) then di xc = xn
End while
Diminuisci τ
End for
Ricerca tabù (Glover, 1989):
Figura 2.2: Andamento esponenziale del valore della soglia di calore
31
Viene mantenuta una “storia recente” degli elementi ispezionati, per non coinvolgerli più volte nell’evoluzione.
Genera una soluzione corrente xc, ed una lista L vuota.
While (non si è ottenuto un valore accettabile) do
xn = vicino di xc non appartenente a L
Δ = f(xn) – f(xc)
if (Δ < 0) then di xc = xn ed inserisci xn in L
Elimina elementi vecchi da L
End while
Algoritmi Genetici
32
33
C a p i t o l o 3
L’ALGORITMO SVILUPPATO
3.1 Obiettivo
Il problema che si vuole risolvere è quello di determinare inizialmente la
presenza o meno di un determinato intervallo di colore9 (appartenente al
modello ARGB) all’interno di un’immagine. Successivamente, è possibile
stabilire se in una certa zona è presente un particolare colore. Attraverso un
ulteriore algoritmo di interpolazione, infine, è possibile delimitare la zona in cui il
colore è stato trovato.
3.2 Descrizione dell’algoritmo
Lo scopo principale dell’algoritmo è di fornire un’insieme di punti nei quali
l’immagine presenta un colore specificato. Il risultato ottimo, ma difficilmente
raggiungibile attraverso un algoritmo di tipo genetico, sarebbe l’indicazione di
tutti i punti il cui colore appartenga ad un intervallo scelto a priori dall’utente.
Nelle seguenti pagine si intenderà come “colore” un oggetto appartenente al
modello ARGB.
Esempio 3.1:
Ricercando tutti i colori compresi nell’intervallo I ={ [255,0,0,0] ; [255,0,0,255] },
ovvero tutti i punti con opacità massima (A = 255) ed appartenenti ad una tonalità di
blu ( B = 0,1,…255) nella figura 3.1a, il risultato ottimo è l’ottenimento di un insieme
di punti ricoprenti tutte le zone interessate, come in figura 3.1b (in bianco)
9 Insieme di valori compresi tra due colori “estremali”. Utilizzando la rappresentazione
ARGB, in cui ogni grandezza rappresenta una dimensione in uno spazio quadrimensionale, un intervallo è raffigurabile come un ipercubo, le cui facce sono limitate dai valori dei colori estremali. Ad esempio, scelti come colori il rosso [255,255,0,0] ed una tonalità di arancione meno opaco [200,247,153,59], l’intervallo di colore costituito è descrivibile come:
I = {(α,r,g,b) : α [200,255] , r [247,255] , g [0,153] , b [0,59]}
Figura 3.1a: Immagine iniziale Figura 3.1b: Area obiettivo
34
3.2.1 Inizializzazione
Il primo passo richiede la scelta dei parametri per l’algoritmo genetico (come
descritto nel Capitolo 2). Dovranno essere impostati i valori di probabilità di
mutazione (pMut) e di incrocio (pCross). Il numero di punti di taglio di un
cromosoma è deciso a priori scegliendo la lunghezza della porzione di
cromosoma che sarà tagliato durante l’incrocio (lSeg). Inoltre, si sceglie il
numero di elementi presenti nella popolazione (nPop). Infine vengono impostati
i colori di estremo per l’intervallo ( = {colour [ext1,ext2]}).
3.2.2 Prima generazione
Vengano creati casualmente nPop elementi (pixel) e vengano inseriti nella prima
popolazione.
Per ogni punto:
Si calcoli il valore di valutazione come somma delle distanze euclidee tra il
colore scelto (col = [colA ,colR ,colG ,colB] )ed i colori estremali per ,
ovvero:
Fval = +
Si aggiunga il punto generato alla popolazione
Si consideri il colore del pixel e, se appartiene all’intervallo , si
“segnali” il punto come parte della soluzione
Al termine, si ordini la popolazione secondo il valore di valutazione in modo
crescente, ovvero mantenendo in prima posizione gli elementi meno distanti
dall’intervallo .
3.2.3 Generazioni successive
Si generi una nuova popolazione di nPop elementi, inizialmente vuota.
Dopodichè, si proceda con la fase evolutiva dell’algoritmo:
Si scelgano 2 elementi “genitori”, seguendo una distribuzione di
probabilità sulla popolazione di tipo gaussiano. Poiché la popolazione è
stata ordinata, i primi elementi saranno scelti con maggior probabilità, e
saranno proprio quelli il cui colore è meno distante dall’intervallo . La
figura seguente schematizza la probabilità di scelta:
[1]
35
Figura 3.3: Incrocio di due cromosomi genitori con segmenti di lunghezza 3
Figura 3.2: Distribuzione gaussiana di probabilità di selezione sulla popolazione
Tra i due genitori si effettui l’operazione di incrocio con probabilità
pCross, generando due elementi figli. L’incrocio venga effettuato su più
punti, utilizzando segmenti di lunghezza l ≤ lSeg, dove l è scelto con
probabilità uniforme in [0, lSeg].
Con probabilità pMut ogni figlio sia soggetto all’operazione di
mutazione di un gene. Nel caso la mutazione porti a figli “non
ammissibili” (rappresentanti pixel di coordinate esterne all’immagine),
si sostituisca con un elemento generato casualmente, aumentando
l’eterogeneità della popolazione, per non incorrere nella convergenza veloce
Per ogni figlio, si valuti il valore di valutazione, lo si aggiunga alla nuova
popolazione e, nel caso il suo colore appartenga all’intervallo , lo si
“segnali” come parte della soluzione
Al termine, si ordini la popolazione in modo crescente secondo il valore
di valutazione
3.2.4 Interruzione
Non è previsto alcun meccanismo d’interruzione interno all’algoritmo: ad ogni
passo, infatti, deve essere l’utente a scegliere di generare un’ulteriore
popolazione a partire dall’attuale.
0,4
0,3
0,1
0,2
1 2 3 4 … … … nPop
36
Si noti che non è stato necessario implementare una funzione di idoneità, in quanto
il meccanismo di selezione si basa su una distribuzione gaussiana su una
popolazione ordinata: questo meccanismo di selezione fa le “veci” della funzione
di idoneità, poiché gli elementi migliori saranno scelti con probabilità più elevata.
3.3 Implementazione
L’algoritmo è stato sviluppato in linguaggio Java, versione 7. Si è utilizzato il tool
di sviluppo “NetBeans IDE 7.0.1”. Il codice è visionabile all’appendice A.
3.3.1 Struttura del codice
Per realizzare il solo algoritmo genetico, è stata realizzata la seguente struttura
di classi:
Pacchetto : pkgColouredImages
Il pacchetto descrive le classi utilizzate per una descrizione ed una
manipolazione più efficace delle immagini e dei colori.
MyARGB
Rappresenta un colore appartenente al modello ARGB e
contiene alcuni metodi dinamici, come il calcolo della distanza
euclidea tra l’istanza ed un parametro e l’appartenenza o meno
dell’oggetto istanziato ad un intervallo di colore.
MyImage
Descrive l’immagine su cui opera l’algoritmo genetico.
Implementa un metodo che restituisce il colore di un pixel dato
ed un metodo che modifica l’immagine stessa evidenziando i
È il “cuore” dell’algoritmo. Tramite il costruttore, assegna i
parametri di input per l’Algoritmo Genetico ed implementa i
metodi per creare ed evolvere la popolazione.
Il metodo makeFirstGeneration genera una popolazione iniziale
casuale e, come nella descrizione dell’algoritmo, assegna ad ogni
elemento il valore di valutazione e restituisce la lista
(eventualmente vuota) degli elementi che soddisfano
l’appartenenza all’intervallo di colore.
Il metodo makeNextGeneration incrocia gli elementi appartenenti
all’attuale popolazione e genera una nuova popolazione. Ogni
nuovo elemento potrebbe poi subire una mutazione. Infine,
restituisce la lista degli elementi che soddisfano l’appartenenza
all’intervallo di colore.
Per realizzare l’interazione con l’utente, è stata realizzata l’interfaccia riportata
in figura:
Figura 3.5: Maschera iniziale per l'impostazione dei parametri dell'algoritmo genetico
39
I pacchetti per gestire l’inserimento dei dati da utente attraverso la form sono
i seguenti:
Pacchetto: pkgPrimitiveWrapper
Re-implementa un tipo di dato primitivo con una classe dinamica, che sarà
utilizzata per la sincronizzazione di thread10,11.
MyBoolean
Descrive un oggetto di tipo booleano, implementandone i
metodi per impostarlo, modificarlo e restituirne il valore
Pacchetto: pkgSearcherFrontEnd
Contiene le classi per la gestione della form.
MyJPanel
Descrive il pannello (contenitore di oggetti grafici) in cui verrà
visualizzata l’immagine in elaborazione. Attraverso il click del
mouse su di un pixel, mostra il valore dei parametri ARGB
relativi al colore di quel punto.
MyFileOperator
Implementa metodi per la lettura/scrittura su un file di testo. È
stata creata per rendere più leggibile il codice.
FrmWelcomeSearcher
Oltre ad implementare e richiamare metodi per gestire il
funzionamento della maschera, contiene alcuni metodi per
avviare l’algoritmo vero e proprio. Le operazioni al run-time
sono gestite mediante l’utilizzo di thread sincronizzati. La
10
Con il termine thread si indica una classe che implementa metodi che possono essere lanciati e catturati al run-time. Il processo “padre” può lanciare un processo “figlio” (thread) che sarà eseguito indipendentemente dal padre. Il padre potrà poi arrestare (catturare) in qualunque momento l’esecuzione del figlio. Per una descrizione più accurata, si rimanda a Tanenbaum (Tanenbaum, 2009). 11
La sincronizzazione è un problema che si presenta quando vengono lanciati più thread dipendenti tra loro. Il problema è quello di far “comunicare” i processi attraverso un canale. Una delle possibili soluzioni (utilizzata in questo software) è l’utilizzo di un oggetto di tipo booleano. Ogni thread, prima di eseguire la sua porzione di codice, controlla lo stato di questa variabile ed “agisce” di conseguenza. Per una descrizione più accurata, si rimanda a Tanenbaum (Tanenbaum, 2009).
40
sincronizzazione avviene per mezzo di un oggetto di tipo
MyBoolean all’interno di un blocco sincronizzato12.
Di seguito viene illustrato il meccanismo di avvio dell’algoritmo, con uno
sguardo alle istruzioni eseguite.
1. All’inizio si scelga, tra i propri file, l’immagine su cui operare. Il software
supporta immagini di tipo JPEG, PNG e GIF.
Figura 3.6: Scelta dell’immagine
2. Scelta l’immagine, verrà richiesta la selezione di un file di testo in cui
salvare i punti trovati. Sarà possibile scegliere, per ogni generazione, di
aggiungere statistiche quali: media e varianza, valore minimo e massimo
del valore di valutazione, media e varianza delle coordinate cartesiane
nonché i valori impostati come parametri per l’algoritmo genetico e
modificabili al run-time.
3. Si scelgano i colori di estremo per l’intervallo. Essi saranno poi
“normalizzati”, ovvero verranno utilizzati due colori estremali diversi,
uno “di minimo” ed uno “di massimo”, in cui i valori dei parametri
ARGB saranno il minimo (o il massimo) tra i valori presenti nei due
colori.
12
Un blocco sincronizzato è un insieme di istruzioni che viene eseguito in mutua esclusione. Si ha mutua esclusione quando è garantito che tutti gli oggetti utilizzati da un thread non siano modificati da un altro thread eseguito in parallelo, che eventualmente attenderà. Definire un insieme di istruzioni all’interno di un blocco sincronizzato significa garantire la mutua esclusione per gli oggetti definiti al suo interno. I blocchi sincronizzati vengono utilizzati per modificare il valore degli oggetti creati per gestire la comunicazione e la sincronia tra thread paralleli.
41
Figura 3.7: Scelta dei colori di estremo per l'intervallo cercato
4. Si impostino i parametri dell’algoritmo genetico: probabilità di incrocio e
mutazione, numero di elementi della popolazione e lunghezza del
segmento di cromosoma che sarà tagliato durante l’incrocio. Per una
visione a run-time dell’evoluzione della popolazione, si scelga il colore
con cui visualizzare nell’immagine i pixel appartenenti alla generazione
corrente.
Figura 3.8: Impostazione dei parametri per l'esecuzione
5. Si prema “Start Generate”. Il metodo associato lancia il thread
StartThread in FrmWelcomeSearcher. Questo thread disabilita i comandi
non più necessari, istanzia un oggetto di tipo Searcher e richiama i
metodi makeFirstGeneration e makeNextGeneration. Attraverso un oggetto
di tipo MyFileOperator, aggiunge i punti trovati (e le eventuali
statistiche) al file scelto come destinazione del risultato. Quando viene
invocato il metodo associato al tasto “Stop Generate”, viene lanciato un
thread di tipo StopThread in FrmWelcomeSearcher. Mediante la
sincronizzazione, questo processo blocca l’esecuzione del thread
StartThread.
42
Figura 3.9: Esecuzione dell'algoritmo
6. Mediante il tasto “See Result” è possibile vedere all’interno
dell’immagine i punti trovati dall’algoritmo.
Figura 3.10: Visione del risultato
Il file ottenuto mostra i risultati in una forma facilmente identificabile ed adatta
ad un parsing, come riportato in figura seguente:
Figura 3.11: File di destinazione ottenuto
43
3.4 Note tecniche
3.4.1 Tipo di dati restituito
Scopo dell’algoritmo è fornire una lista di punti il cui colore rientra in un
intervallo specificato. I metodi makeFirstGeneration e makeNextGeneration,
infatti, restituiscono un oggetto di tipo ArrayList<Point>.
Il salvataggio di questi punti su un file di testo, l’aggiunta delle statistiche e
la visualizzazione a video mediante l’interfaccia progettata sono elementi
esterni all’Algoritmo Genetico, scelti per visionare, studiare e correggere il
comportamento del processo.
3.4.2 Rappresentazione del genotipo
Come descritto nella sezione “Struttura del codice”, il genotipo è stato
rappresentato tramite una concatenazione di bit. Ad ogni pixel è associata una
coppia di numeri naturali a 32 bit che ne indicano le coordinate all’interno
dell’immagine digitale. Il genotipo è una sequenza di 64 bit, rappresentata
tramite un numero intero di tipo long. I primi 32 bit rappresentano la
coordinata X, mentre gli ultimi 32 bit rappresentano la coordinata Y. Per i
metodi di conversione, si rimanda all’Appendice A,
pkgGeneticColourItems.GeneticPixel, righe 49-121.
44
45
C a p i t o l o 4
STUDIO DELL’ALGORITMO
4.1 Metodo di studio
Per lo studio del comportamento dell’algoritmo, si è utilizzata l’interfaccia
grafica descritta del capitolo precedente. In un primo momento si sono testate
diverse combinazioni di parametri su una stessa immagine di base. In un
secondo momento si è voluta studiare la risposta ad immagini differenti, con
diverse combinazioni di parametri in ingresso. Successivamente, si sono
analizzate le prestazioni in risposta ad un basso numero di evoluzioni. Infine, si
è voluta fornire una possibile applicazione dell’algoritmo, nella ricerca di aree di
calore in un’immagine termica e di tracciamento di traiettoria in una sequenza
di immagini.
4.2 Definizione di coefficiente di distribuzione
Per un corretto studio della risposta dell’algoritmo genetico, è necessario poter
classificare le immagini campione secondo una certa metrica. Si idealizza così
un valore da associare ad ogni immagine, detto coefficiente di distribuzione,
che indica in prima approssimazione la “ semplicità della struttura” dell’area da
ricercare.
Si definisce coefficiente di distribuzione associato all’intervallo di colore il valore:
c.d. =
dove,
nC è il numero dei punti nell’immagine appartenenti all’intervallo
di colore specificato, ovvero:
46
AC è l’area dell’insieme convesso13 più piccolo comprendente
tutti i punti con colore in
Più il c.d. si avvicina ad 1, più l’area obiettivo assume una forma compatta e
definita. Al decrescere di tale valore, i pixel di colore cercato formano insiemi
non connessi14 o non convessi.
4.3 Studio mediante cambiamento di parametri
In questa prima fase si è scelto di ripetere più prove, variando i parametri che
caratterizzano l’algoritmo: probabilità di incrocio (pCross), probabilità di
mutazione (pMut), numero di elementi del campione e lunghezza minima del
segmento di cromosoma da tagliare (lSeg).
Sono stati considerati ai fini dello studio:
il numero medio di punti trovati per ogni generazione (N punti)
la media e la varianza del valore di valutazione (vv) medio di ogni
generazione, ovvero:
dove e sono rispettivamente la media e la
varianza del valore di valutazione nella generazione i-esima;
13
Un insieme si dice convesso se, presi due punti arbitrari che ne fanno parte, è possibile costruire un segmento che li unisce, i cui punti sono anch’essi contenuti nell’insieme. 14
Un insieme si dice semplicemente connesso se, presi due punti arbitrari che ne fanno parte, è possibile costruire una curva che li congiunge, i cui punti sono anch’essi contenuti nell’insieme.
Figura 4.1: Immagini con diverso coefficiente di distribuzione associato al valore [255,0,162,232] (blu chiaro). Rispettivamente, da sinistra, i valori sono 1.00 , 0.80 , 0.40 e 0.24. In nero sono evidenziati gli insiemi convessi che contengono l’area obiettivo
47
la media delle coordinate cartesiane dei punti medi di ogni
generazione, ovvero:
dove è la media delle coordinate cartesiane della
generazione i-esima;
la media della varianza della distanza dal punto [0,0] delle
coordinate medie di ogni generazione, ovvero:
dove è la varianza della distanza delle coordinate dal
punto [0,0];
la percentuale di generazioni “improduttive” (%Gen.Im.), ovvero i
cui elementi presentano tutti un colore al di fuori dello spazio
specificato.
A lato di ciascun test è riportato l’andamento di media e varianza del valore di
valutazione al susseguirsi delle generazioni. La linea blu rappresenta il valore di
valutazione medio,la linea nera è una linea di tendenza di tale valore e la linea
rossa è la varianza. È stato ottenuto anche un grafico che mostra la posizione
del punto medio di ogni generazione (in blu).
L’algoritmo è stato lasciato evolvere per un numero prefissato di generazioni
(Ngen), in modo che si potessero stimare anche il numero di millisecondi
necessari all’esecuzione. In questo senso, è da precisare che il tempo di
lettura/scrittura dell’output su un file ed il tempo necessario al motore grafico
per visualizzare e modificare l’immagine sono stati valutati in media e
decrementati dal tempo totale. Tuttavia, per la stima del tempo di esecuzione
non sono stati calcolati i cicli di clock destinati ad altri processi in esecuzione
nello stesso istante sulla macchina.
Il calcolatore di test ha a disposizione una CPU AMD Turion®II Ultra Dual-
Core Mobile M600, 2.40 GHz e 2GB di RAM. Le immagini hanno dimensione
800x600 pixel.
48
4.3.1 Prima fase: 10 elementi per generazione
Si è scelta l’immagine riportata in figura 4.2.
Figura 4.2: Immagine del primo test.
L’area obiettivo è il disco rosso (più precisamente, di colore [255,237,28,36])
di centro [400,313]. Il coefficiente di distribuzione dell’immagine rispetto al
rosso è pari a 0.81. Si è scelta una popolazione di 10 elementi per ogni
generazione, fatti evolvere per 100 generazioni.
Test 1.a
% pCross 10
% pMut 0.0
lSeg(bit) 3
Tempo (ms) 31
N punti 2.64
E[E[vv]] 599.1
E[Var[vv]] 52.7
E[E[x,y]] [390,328]
E[Var[z]] 44
% Gen. Im. 51
Il comportamento dell’algoritmo è completamente imprevedibile. Le prime
generazioni cadono nelle vicinanze dell’area interessata, poi si evolvono al di
fuori di essa (si nota un valore di valutazione medio molto alto). Questo è
dovuto al fatto che ci sono pochi elementi nella popolazione e che i
0
200
400
600
800
0 20 40 60 80 100
49
parametri dell’algoritmo (bassa popolazione, bassa probabilità di incrocio,
bassa lunghezza del segmento di cromosoma) non permettono
l’avvicinamento presso i punti “migliori”. Fino alla generazione 31, ogni
punto generato ha un colore non idoneo. Successivamente, alcuni punti
ricadono all’interno dell’area obiettivo, per poi uscirne (questo a
dimostrazione dell’aleatorietà dell’evoluzione). La percentuale di generazioni
improduttive è molto alta, ed il numero di punti generati al di fuori dell’area
obiettivo è del 73.6%. Tuttavia, la media delle coordinate si avvicina al
valore atteso [400,313], seppur con una notevole varianza. Questo dato è
riconducibile all’eterogeneità dei campioni ottenuti, i cui punti si
La coordinata X varia da 288 a 375, mentre la coordinata Y varia da 321 a
503
La poca popolazione presente non permette, nella maggioranza dei casi, di
ottenere un’esecuzione efficiente (in termini di popolazioni improduttive
generate), né molto efficace (in termini di stabilizzazione dei punti generati).
Giunti a questo punto, sembra che in presenza di pochi elementi all’interno
delle generazioni (ipotizzabile nei casi di pochissima memoria a
disposizione), una buona strategia sia quella presentata nel test 1.c.
0
200
400
600
800
0 20 40 60 80 100
55
4.3.2 Seconda fase: 100 elementi ad ogni generazione
In questa fase si sono ripetuti gli stessi test sulla stessa immagine, con la
stessa area obiettivo, aumentando la popolazione a 100 elementi.
Test 2.a
% pCross 10
% pMut 0.0
lSeg(bit) 3
Tempo (ms) 350
N punti 55.4
E[E[vv]] 352.1
E[Var[vv]] 38.2
E[E[x,y]] [387,337]
E[Var[z]] 14.3
% Gen. Im. 0
In questo primo test, si è limitata l’influenza dei parametri sull’evoluzione
della popolazione. Tuttavia, l’aumento del numero di elementi di ogni
popolazione ha permesso la stabilizzazione dei punti nei pressi del disco
obiettivo, come si nota dalla rappresentazione delle coordinate medie. La
media dei valori di valutazione è più bassa rispetto ai test precedentemente
effettuati. Anche la varianza è nettamente diminuita. Le coordinate medie si
posizionano in un’intorno del punto [387,337], ovvero nei pressi del valore
atteso. È da notare l’assenza di generazioni improduttive ed una media di
55.4 punti trovati per ogni generazione.
0
100
200
300
400
500
600
700
800
0 20 40 60 80 100
56
Test 2.b
% pCross 10
% pMut 50
lSeg(bit) 3
Tempo (ms) 81
N punti 53.8
E[E[vv]] 365.0
E[Var[vv]] 38.1
E[E[x,y]] [387,336]
E[Var[z]] 14.6
% Gen. Im. 0
Test 2.c
% pCross 10
% pMut 0.1
lSeg(bit) 8
Tempo (ms) 68
N punti 39.5
E[E[vv]] 478
E[Var[vv]] 37.0
E[E[x,y]] [390,344]
E[Var[z]] 16.3
% Gen. Im. 0
0
100
200
300
400
500
600
700
800
0 20 40 60 80 100
0
200
400
600
800
0 20 40 60 80 100
57
Test 2.d
% pCross 10
% pMut 50
lSeg(bit) 8
Tempo (ms) 280
N punti 41.2
E[E[vv]] 464.5
E[Var[vv]] 37.7
E[E[x,y]] [394,344]
E[Var[z]] 15.6
% Gen. Im. 0
Test 2.e
% pCross 80
% pMut 0.1
lSeg(bit) 3
Tempo (ms) 130
N punti 54.2
E[E[vv]] 362.0
E[Var[vv]] 38.4
E[E[x,y]] [386,333]
E[Var[z]] 14.6
% Gen. Im. 0
0
200
400
600
800
0 20 40 60 80 100
0
100
200
300
400
500
600
700
0 20 40 60 80 100
58
Test 2.f
% pCross 90
% pMut 0.1
lSeg(bit) 8
Tempo (ms) 350
N punti 40.7
E[E[vv]] 468.5
E[Var[vv]] 37.9
E[E[x,y]] [396,348]
E[Var[z]] 15.4
% Gen. Im. 0
Nei successivi test, si nota come l’introduzione di valori diversi nei
parametri porti ad un peggioramento dei risultati. La presenza di 100 punti
sembra “dominare” sull’evoluzione dell’algoritmo, impedendo una
stabilizzazione accurata dei punti generati. Infatti, pur evidenziando un
aumento nel valor di valutazione medio, non si può dire altrettanto delle
varianze e della media delle coordinate. Questi valori, infatti, non sembrano
risentire di particolari variazioni. Lo schema di Holland che si profila è lo
stesso riportato nel test1.f.
In conclusione, si conclude che 100 elementi costituiscono una popolazione
troppo numerosa perché i parametri dell’algoritmo abbiano effetto sui punti
generati.
4.3.3 Terza fase: miglior combinazione di parametri
Sono stati effettuati 50 test, combinando un numero di elementi non
eccessivo (40-80) con una modifica dei parametri caratterizzanti l’algoritmo.
L’esecuzione è stata lasciata evolvere per 1000 generazioni.
0
100
200
300
400
500
600
700
800
0 20 40 60 80 100
59
I test che hanno riportato i risultati migliori si possono approssimare al test
descritto nella seguente tabella:
Si nota un valore di valutazione medio decisamente inferiore ai test 1 e 2, con
una bassa varianza. Anche la media delle coordinate si avvicina al valore
atteso, ed anche in questo caso si ha una bassa varianza. Il numero di punti
mediamente trovati su una popolazione è pari al 70.3%. Un risultato
migliore di questo non è stato ottenuto. Ciò porta a concludere che circa il
30% dei punti generati non è utilizzato.
Il tempo di esecuzione sembra dipendere solo dal numero di generazioni per
cui è lasciato evolvere l’algoritmo, ma non dai parametri di ingresso (si
confrontino a questo proposito i test 1.a, 1.b, 1.c e 2.b).
4.4 Studio attraverso immagini con diverso coefficiente di distribuzione
In questa fase di studio, è stato considerato il comportamento dell’algoritmo su
immagini con diverso valore di coefficiente di distribuzione. Obiettivo del test è
formulare alcune ipotesi sui parametri d’ingresso in funzione del coefficiente di
distribuzione per ottenere prestazioni paragonabili a quelle del test3.
Test 3
% pCross 80
% pMut 0.01
lSeg(bit) 5
Popolazione 75
Tempo (ms) 1500
N punti 52.7
E[E[vv]] 302.3
E[Var[vv]] 35.5
E[E[x,y]] [415,328]
E[Var[z]] 12.4
% Gen. Im. 0
0
100
200
300
400
500
600
0 200 400 600 800 1000
60
Le immagini su cui saranno effettuati i test sono le seguenti:
coefficiente di distribuzione rispetto al blu: 0.86
coefficiente di distribuzione rispetto al marrone: 0.46
coefficiente di distribuzione rispetto al verde: 0.45
coefficiente di distribuzione rispetto al bianco:0.29
coefficiente di distribuzione rispetto al giallo: 0.25
coefficiente di distribuzione rispetto al giallo: 0.25
61
I risultati ottenuti variando i parametri caratteristici dell’algoritmo sono i
seguenti:
so pCross: 80%
pMut: 10%
Pop: 75
lSeg: 3
I punti generati ricoprono pressoché l’intera area obiettivo, con una maggior concentrazione verso la parte inferiore dell’immagine. Pur con una breve lunghezza del segmento di taglio, si è ottenuto un risultato accettabile, in cui il 76% dei punti generati è stato utilizzato.
pCross: 90%
pMut: 50%
Pop: 75
lSeg: 3
Mutazione: In questo test si è verificato uno spreco dell’ 84% dei punti generati. Il risultato associato ad un incremento della probabilità di mutazione non è soddisfacente.
pCross: 10%
pMut: 60%
Pop: 100
lSeg: 3
Incremento popolazione: Non si notano particolari differenze dal primo caso. I punti generati sembrano concentrarsi nelle aree già individuate precedentemente. Tuttavia, pur aumentando la popolazione, si è registrato un incremento del numero di punti utilizzati in ogni generazione, con un risultato dell’ 80%.
pCross: 90%
pMut: 0.01%
Pop: 75
lSeg: 5
Evoluzione consigliata: I parametri fanno riferimento al test 3. La bassa mutazione ha concentrato le coordinate generate nella zona verticale centrale. L’area obiettivo è stata ricoperta in gran parte, ma con un numero inferiore di punti. Anche in questo caso, la percentuale di punti utilizzati in ogni generazione è alta, pari al 77%.
pCross: 10%
pMut: 0.0%
Pop: 75
lSeg: 3
Evoluzione libera: In questo test si sono volute far evolvere liberamente le generazioni, senza garantire particolari condizioni di stabilità. Tuttavia, anche in questo caso il risultato è stato soddisfacente in termini di copertura dell’immagine e di numero di punti utilizzati in ogni generazione (77%).
62
L’esperimento suggerisce che, data un’immagine con coefficiente di distribuzione
elevato, non vi sono particolari vincoli sui parametri, posto di non utilizzare
una probabilità di mutazione alta associata ad un’alta probabilità di incrocio.
pCross: 10%
pMut: 0.0%
Pop: 75
lSeg: 3
Evoluzione libera: I punti generati si sono distribuiti con molta concentrazione, e c’è stato un utilizzo del 50% dei punti generati.
pCross: 70%
pMut: 0.01%
Pop: 75
lSeg: 5
Evoluzione consigliata:
Anche in questo caso si è ottenuta una copertura pressoché globale dell’area obiettivo. I punti utilizzati in ogni generazione sono stati dell’ordine del 50%
pCross: 80%
pMut: 0.1%
Pop: 30
lSeg: 5
Diminuzione popolazione: Questo test è stato affrontato con pochi pixel per ogni generazione. Ciò non ha permesso un ricoprimento dell’area obiettivo paragonabile agli altri test. Tuttavia, la forma che si otterrebbe inviluppando tutti punti è simile a quella rilevabile dagli altri test.
pCross: 80%
pMut: 0.1%
Pop: 100
lSeg: 3
Incremento popolazione: Un incremento della popolazione porta (come potrebbe essere intuibile) ad un maggior ricoprimento dell’immagine. Tuttavia, circa l’84% dei punti generati ricade al di fuori dell’area obiettivo.
63
pCross: 10%
pMut: 60%
Pop: 50
lSeg: 3
Mutazione: Data la discreta popolazione, la mutazione porta la maggior parte dei punti comunque nelle vicinanze dell’area obiettivo. Il numero di punti utilizzati in ogni generazione è pari al 48%.
Eseguendo l’algoritmo su un’immagine con coefficiente di distribuzione minore, si
nota una perdita di prestazione in merito al numero di punti che ricadono
nell’area obiettivo in ogni generazione. Anche in questo caso, non si evidenzia
una strategia “migliore” nella scelta dei parametri. Si rileva, tuttavia, un
particolare degrado in merito al numero di punti utilizzati nel 4° test.
Un’elevata popolazione non accompagnata da una bassa probabilità di mutazione
o da una maggior lunghezza di taglio del cromosoma da luogo a punti al di
fuori dell’area obiettivo. A dimostrazione di ciò è stato effettuato il seguente
test, che vuole migliorare il secondo esperimento:
pCross: 70%
pMut: 0.01%
Pop: 100
lSeg: 5
Un ideale insieme semplicemente connesso che racchiuda i punti presenti, demarcherebbe con maggior precisione la forma dell’area obiettivo, seppur non vi sia una gran concentrazione di pixel generati nella metà più a destra dell’immagine. La percentuale di punti utilizzati è del 48%.
pCross: 10%
pMut: 0.0%
Pop: 75
lSeg: 3
Evoluzione libera:
Si nota una maggiore concentrazione dei punti sulla zona più a sinistra dell’immagine. La percentuale di punti utilizzati in ogni generazione e del 61%.
64
pCross: 70%
pMut: 0.01%
Pop: 75
lSeg: 5
Evoluzione consigliata:
L’evoluzione non è dissimile dalla precedente. Anche la percentuale dei punti utilizzati rimane simile, al 60%. Si nota una maggior distribuzione nelle aree obiettivo “tralasciate” dal test precedente.
pCross: 80%
pMut: 0.1%
Pop: 30
lSeg: 5
Diminuzione popolazione:
Il 59% dei punti generati è stato utilizzato. Tuttavia il numero di elementi per generazione sembra essere troppo basso, non permettendo l’esplorazione di tutta l’area interessata.
pCross: 80%
pMut: 0.1%
Pop: 100
lSeg: 5
Incremento popolazione:
Anche in questo caso, la copertura non è molto diversa dai primi test e rimane accettabile. La percentuale di pixel utili generati è del 62%.
pCross: 10%
pMut: 60%
Pop: 50
lSeg: 3
Mutazione:
L’evoluzione non porta sorprese, rispetto alle prove precedenti. La percentuale di punti utilizzati rimane intorno al 60%
In questi test, il coefficiente di distribuzione e dello 0.45, similmente all’immagine
precedente. Tuttavia, si nota un leggero miglioramento in termini di
percentuale di punti interni all’area obiettivo. Come per i precedenti
esperimenti, non si evince una combinazione di parametri “fortunata”, ma si è
certi di dover evitare una scarsa presenza di elementi nel campione. La forma
dell’area di interesse è più irregolare e più vasta rispetto all’immagine
precedente, tuttavia il comportamento dell’algoritmo è pressoché analogo,
65
considerato lo spazio di colore cercato. La forma ottenuta dai diversi insiemi è
simile.
Quest’immagine, però, dimostra una situazione limite per l’algoritmo genetico.
Infatti, per ricercare la zona relativa alle foglie, è necessario uno spazio di
colore troppo esteso per isolare le stesse dal resto dell’immagine. È stato
necessario limitare inferiormente lo spazio di colore a valori “non abbastanza
chiari” per poter ricoprire l’intera foglia, altrimenti anche le zone più chiare
dello sfondo avrebbero posseduto un colore interno all’intervallo di colore
cercato. Questo suggerisce che, per un efficace ricerca, è auspicabile l’assenza
di elementi esterni all’area obiettivo aventi colore interno all’intervallo cercato.
Poiché questa situazione non è sempre garantita, si deve cercare di minimizzare
l’ampiezza dell’intervallo di colore cercato, per escludere tutte quelle tonalità
indesiderate che altrimenti vi apparterrebbero. In queste esecuzioni, ad
esempio, non è stato possibile evitare che ogni area dello sfondo avesse un
colore al di fuori dell’intervallo cercato.
pCross: 10%
pMut: 0.0%
Pop: 75
lSeg: 3
Evoluzione libera:
Si nota una forte concentrazione di punti alla destra dell’immagine. L’assenza di mutazione ha reso difficile l’allontanamento da quest’area. La percentuale di punti utilizzati e del 35%
pCross: 70%
pMut: 0.01%
Pop: 75
lSeg: 5
Evoluzione consigliata:
Non si nota un particolare miglioramento rispetto alla situazione precedente. Anzi, la percentuale di punti utilizzati scende al 30%.
pCross: 80%
pMut: 0.1%
Pop: 30
lSeg: 5
Diminuzione popolazione:
Il risultato non è soddisfacente, poiché l’84% dei punti è stato generato al di fuori dell’area interessata.
66
pCross: 80%
pMut: 0.1%
Pop: 100
lSeg: 5
Incremento popolazione:
Anche in questo caso le prestazioni non sono buone, con una percentuale di punti utilizzati appena del 24%. Tuttavia, si nota come i punti bianchi alla sinistra dell’immagine siano stati “maggiormente considerati”.
pCross: 10%
pMut: 60%
Pop: 75
lSeg: 3
Mutazione:
Nessun miglioramento neppure in questa situazione, con una percentuale di punti utilizzati del 16%.
Ogni evoluzione su questa immagine porta risultati non soddisfacenti.
Innanzitutto, non è stato possibile isolare la figura della “palla”, poiché le
ombre sul lato sinistro avrebbero richiesto un’estensione dell’intervallo di
colore cercato che avrebbe compreso i colori della tribuna e di una parte del
prato. In secondo luogo, zone come la parete della casa sullo sfondo e le
finestre del condominio non sono state praticamente raggiunte durante
l’esecuzione, pur arrivando a valori molto alti di probabilità di mutazione.
Quest’immagine non si presta quindi ad una ricerca di colore per isolare una
forma. Nel caso si voglia ricercare un oggetto composto da più tonalità di
colore, è auspicabile che:
a. l’intervallo di colore ottenuto dall’oggetto non sia esteso rispetto
all’intervallo di colore generato dall’intera immagine;
b. non vi siano zone al di fuori dell’oggetto con tonalità di colore
comprese nell’intervallo di ricerca.
67
pCross: 10%
pMut: 0.0%
Pop: 75
lSeg: 3
Evoluzione libera:
Il test trova buona parte delle aree aventi i colori cercati. Tuttavia i pixel generati nella zona “bassa” dell’immagine non generano molti altri pixel adiacenti. La percentuale di punti utilizzati è del 54%.
pCross: 70%
pMut: 0.01%
Pop: 75
lSeg: 5
Evoluzione consigliata:
A parità di elementi generati, in questa situazione sono stati trovati meno pixel aventi un colore cercato. La percentuale di punti utilizzati scende al 50% per generazione.
pCross: 80%
pMut: 0.1%
Pop: 30
lSeg: 5
Diminuzione popolazione:
Si nota un’ulteriore diminuzione di pixel generati nell’area obiettivo. La parte inferiore è pressoché “inesplorata”. Il 49% dei punti è stato generato nell’area obiettivo.
pCross: 80%
pMut: 0.1%
Pop: 100
lSeg: 5
Incremento popolazione:
Costruendo due insiemi connessi sulle due porzioni interessate dai pixel generati, si otterrebbe una forma simile all’area obiettivo cercata. Il 51% dei punti è stato generato nell’area obiettivo.
pCross: 10%
pMut: 60%
Pop: 75
lSeg: 3
Mutazione:
L’alta probabilità di mutazione non ha portato a risultati diversi dai precedenti. Il 54% dei punti è stato generato nell’area obiettivo, ma è stata “tralasciata” la parte inferiore dell’immagine.
In questo caso, l’evoluzione dell’algoritmo sembra concentrarsi su una
determinata zona “già esplorata” piuttosto che evolvere anche verso nuove
aree. Un risultato accettabile si ha in presenza di un’elevata popolazione.
68
Un’immagine “spezzata” non sembra favorire una ricerca di essa tramite
l’algoritmo.
pCross: 10%
pMut: 0.0%
Pop: 75
lSeg: 3
Evoluzione libera:
L’evoluzione si concentra principalmente sulla zona inferiore-destra dell’immagine. Il 54% dei punti generati è stato utilizzato.
pCross: 70%
pMut: 0.01%
Pop: 75
lSeg: 5
Evoluzione consigliata:
Pur ricoprendo una buona parte dell’area interessata, i punti generati si addensano in un'unica zona. La percentuale di punti utilizzati e del 55%
pCross: 80%
pMut: 0.1%
Pop: 30
lSeg: 5
Diminuzione popolazione:
I punti generati si distribuiscono per tutta l’immagine, ma il loro numero è esiguo per ricoprire l’area come nei test precedenti. Il 52% dei punti è stato generato nell’area obiettivo.
pCross: 90%
pMut: 1.0%
Pop: 100
lSeg: 3
Incremento popolazione:
I punti generati ricoprono un area maggiore rispetto ai test precedenti. Il 56% di essi quindi non solo ricade nell’area obiettivo, ma ha una varianza maggiore all’interno di essa.
pCross: 10%
pMut: 60%
Pop: 75
lSeg: 3
Mutazione:
Il 57% dei punti generati ricade nell’area obiettivo. Il risultato è simile a quello ottenuto nel primo esperimento.
Il coefficiente di distribuzione dell’immagine rispetto al “giallo” è del 25%. A
differenza dell’immagine precedente, il colore cercato si estende su tutta l’area
dell’immagine senza seguire una determinata struttura. Anche in questo caso,
l’intervallo di colore comprende tonalità di oggetti “indesiderati”. Si nota come
69
un’elevata popolazione, un’evoluzione libera o un’alta probabilità di mutazione
forniscono risultati simili. Questo suggerisce che nel caso si cerchi un colore
che è distribuito nell’immagine senza una certa struttura, è preferibile
mantenere una grande eterogeneità del campione:
generando popolazioni con un elevato numero di elementi
scegliendo un’alta probabilità di mutazione (50-60%)
scegliendo una breve lunghezza di taglio del segmento di
cromosoma (1-4 bit).
Si è effettuato quindi un test sfruttando questi tre accorgimenti, ottenendo il
seguente risultato:
pCross: 50%
pMut: 50%
Pop: 100
lSeg: 5
I punti generati si distribuiscono in tutte le zone interessate, con una concentrazione mediamente maggiore rispetto ai test precedenti. Il 55% dei punti generati si trova nell’area obiettivo.
4.4.1 Riepilogo
Questi differenti test portano ad affermare che:
L’efficienza (in termini di generazioni punti “utilizzati”) e l’efficacia (in
termini di ricoprimento dell’area obiettivo) dell’algoritmo è
proporzionale a:
o coefficiente di distribuzione
o struttura dell’area obiettivo cercata
o assenza di aree indesiderate aventi tonalità di colore interne
all’intervallo cercato
o minimalità dell’ampiezza dell’intervallo di colore da cercare
In presenza di aree obiettivo vaste rispetto all’immagine intera
(ricoprenti o estese per oltre il 70% di essa), è consigliabile scegliere
un’alta probabilità di mutazione, un alto numero di elementi nelle
70
popolazioni ed una bassa lunghezza di taglio del segmento di
cromosoma
Se si vuole ricercare una forma, l’algoritmo fornisce buoni risultati
soltanto se questa dà luogo ad un insieme connesso e migliora con alti
coefficienti di distribuzione (maggiori di 70), tantopiù se l’insieme è anche
convesso. Per forme più irregolari, si consiglia l’utilizzo di un algoritmo
di segmentazione.
4.5 Studio su di un ridotto numero di generazioni
Si vuole studiare il comportamento dell’algoritmo in presenza di un ridotto
numero di generazioni lasciate evolvere. In particolare, si è bloccata
l’esecuzione alla 10°, alla 30° ed alla 50°.
La caratterizzazione del test è data dal valore dei parametri in ingresso, dalla
percentuale di punti generati all’interno dell’area obiettivo e dalla disposizione
di essi nell’immagine.
Si sono utilizzate le immagini precedentemente mostrate.
I risultati ottenuti sono riassunti nella seguente tabella:
Num Gen Parametri % Punti Area ricoperta
10
pCross: 90%
pMut: 0.1%
pop: 75
lSeg: 5
38.1%
10
pCross: 90%
pMut: 0.1%
pop: 75
lSeg: 3
80.0%
71
10
pCross: 90%
pMut: 0.01%
pop: 75
lSeg: 3
37.9%
10
pCross: 90%
pMut: 0.1%
pop: 75
lSeg: 3
44.3%
10
pCross: 90%
pMut: 50%
pop: 100
lSeg: 3
4.9%
10
pCross: 90%
pMut: 0.1%
pop: 75
lSeg: 3
46.5%
10
pCross: 90%
pMut: 10%
pop: 75
lSeg: 3
46.4%
30
pCross: 90%
pMut: 0.1%
pop: 75
lSeg: 5
50.6%
72
30
pCross: 90%
pMut: 0.1%
pop: 75
lSeg: 3
77.1%
30
pCross: 90%
pMut: 0.01%
pop: 75
lSeg: 3
39.2%
30
pCross: 90%
pMut: 0.1%
pop: 75
lSeg: 3
54.7%
30
pCross: 90%
pMut: 50%
pop: 100
lSeg: 3
1.2%
30
pCross: 90%
pMut: 0.1%
pop: 75
lSeg: 3
47.5%
30
pCross: 90%
pMut: 10%
pop: 75
lSeg: 3
55.0%
73
50
pCross: 90%
pMut: 0.1%
pop: 75
lSeg: 5
61.3%
50
pCross: 90%
pMut: 0.1%
pop: 75
lSeg: 3
76.7%
50
pCross: 90%
pMut: 0.01%
pop: 75
lSeg: 3
46.4%
50
pCross: 90%
pMut: 0.1%
pop: 75
lSeg: 3
56.3%
50
pCross: 90%
pMut: 50%
pop: 100
lSeg: 3
0.9%
50
pCross: 90%
pMut: 0.1%
pop: 75
lSeg: 3
55.8%
74
50
pCross: 90%
pMut: 10%
pop: 75
lSeg: 3
55.5%
Di seguito è riportato il tempo medio, minimo e massimo in cui sono stati
eseguiti i precedenti test, in riferimento al numero di popolazioni generate:
Numero Generazioni
Tempo medio (ms)
Tempo minimo (ms)
Tempo massimo (ms)
10 35 24 64
30 85 62 100
50 136 122 187
L’evoluzione in 10 popolazioni fornisce un’apprezzabile risposta sulla presenza
o meno dell’intervallo di colore cercato. Non è adatta a fornire indicazioni su di
un’eventuale forma cercata.
L’evoluzione in 30 popolazioni fornisce anch’essa una soddisfacente risposta
sulla presenza dell’intervallo di colore cercato. E’ possibile riconoscere una
forma simile a quella cercata solo nel caso di un’immagine con coefficiente di
distribuzione elevato (superiore a 0.50). Tuttavia la distribuzione dei punti si
concentra in una determinata area, quindi il risultato non è accettabile per
forme rappresentanti insiemi semplicemente connessi o addirittura disgiunti.
L’evoluzione con 50 popolazioni fornisce risultati dell’ordine del test 1, in cui
l’area obiettivo è maggiormente ricoperta e l’eventuale forma è approssimabile
anche nel caso di insiemi semplicemente connessi.
Si noti come nessuno di questi test abbia fornito un risultato accettabile per la
quinta immagine (pallone e campo da calcio). Infatti, pur riuscendo a dare una
risposta sulla presenza dell’intervallo di colore cercato, la percentuale di punti
inutilizzati è estremamente alta.
75
4.6 Applicazione ad un’immagine termica
Come anticipato all’inizio del capitolo 3, lo scopo di questo algoritmo è quello
di fornire un insieme di punti appartenenti ad un intervallo di colore
specificato. Questo dato può essere interpretato semplicemente per ottenere
informazioni sulla presenza o meno di alcune tonalità di colore all’interno
dell’immagine.
In un secondo momento, è possibile tentare di ricostruire la forma dell’area
obiettivo, attraverso un inviluppo dei punti trovati. A questo proposito, è stato
utilizzato l’algoritmo di Graham per l’inviluppo convesso (Graham, Gennaio
1972), una cui implementazione (all’interno della libreria “FastGEO”) è
scaricabile al sito:
http://www.partow.net/projects/fastgeo/index.html
Si noti che l’inviluppo proposto fornisce un insieme convesso: non è adatto
quindi ad approssimare forme fortemente non convesse, ma solo ad indicare
una regione entro la quale è presente l’intervallo di colore cercato.
Si vuole prima di tutto ricercare la presenza o meno di aree più calde di 46 °C
sulla seguente immagine di un microprocessore:
L’algoritmo è stato inizializzato con i seguenti parametri:
In cui, rilevando le tonalità di colore dalla legenda, lo spazio di colore cercato è
stato inizializzato a:
[255,255,255,255] corrispondente al colore:
[255,218, 82, 86] corrispondente al colore:
L’esecuzione ha generato 81812 punti aventi un colore appartenente all’insieme
cercato.
Questo conferma la presenza di un’area con temperatura superiore a 46° C.
Il risultato è rappresentato nella seguente figura:
Figura 4.3: Risultato della ricerca dell'intervallo interessato
Un inviluppo convesso attraverso l’algoritmo di Graham dell’insieme fornisce
il seguente risultato:
Figura 4.4: Inviluppo convesso del risultato
77
4.7 Applicazione per il rilevamento di una traiettoria
Data una sequenza di immagini, si vuole identificare un oggetto caratterizzato
da ben note tonalità di colore, per poi tracciarne la traiettoria.
Come evidenziato al termine degli esperimenti effettuati in precedenza,
l’oggetto dovrà essere composto di tonalità di colore “vicine tra loro”, per non
dar luogo a rilevamenti di aree appartenenti alle zone circostanti.
Si vuole specificare che questa applicazione è possibile grazie ad una modifica
nel codice del software relativo alla sola gestione e visualizzazione dei punti
forniti dall’algoritmo genetico. Esso infatti non accede direttamente
all’immagine fornita inizialmente. La modifica al run-time dell’immagine,
quindi, non richiede cambiamenti nel codice dell’algoritmo.
Di seguito è mostrata la successione una immagini in cui si vuole tracciare la
traiettoria della pallina da biliardo gialla.
78
L’algoritmo è stato inizializzato con i seguenti parametri:
pCross 90%
pMut 0.1%
Pop 75
lSeg 3
Di seguito sono riportati i risultati relativi a diverse frequenze di frame per
secondo (fps):
fps Risultato fps Risultato
2
5
25
50
100
200
500
1000
5000
10000
79
Come si nota, con l’aumentare della frequenza dei frame, il numero di punti
trovati cala. I punti risultanti dall’algoritmo riescono a tracciare, nella maggior
parte dei casi, l’effettiva traiettoria seguita dalla pallina, anche se in maniera
sempre meno precisa al crescere dei fps.
Il risultato nel complesso è soddisfacente fino a 1000 fps.
Un interessante sviluppo, non implementato, sarebbe l’esecuzione
dell’algoritmo su un video.
80
81
Conclusioni
L’algoritmo sviluppato riesce a fornire una soluzione al problema della
presenza di un determinato intervallo di colore. Dagli ultimi test, si nota che
anche con pochi passi evolutivi (tratto caratteristico di un Algoritmo Genetico)
la presenza di una tonalità di colore ricercata viene confermata. I risultati
ottenuti a riguardo sono quindi soddisfacenti.
Il rilevamento della forma di un oggetto avente un certo colore, invece, risulta
di più limitata efficacia. Infatti lo studio porta ad affermare che, in questo caso,
l’efficacia dell’algoritmo dipende da:
1 Semplicità della forma: durante l’esecuzione viene rilevata una buona
parte dell’area della forma solo nel caso in cui questa costituisca un
insieme connesso e per lo più convesso;
2 Tendenza alla monocromaticità della forma: l’algoritmo fornisce
risultati migliori in presenza di un intervallo di colore ristretto;
3 Assenza di zone indesiderate dello stesso colore della forma ricercata;
4 Scelta dei parametri: sono state evidenziate combinazioni inopportune
dei parametri caratteristici dell’algoritmo; tuttavia non è stato possibile
garantire un metodo “sicuro” per la ricerca in ogni tipo di immagine. E’
quindi auspicabile una conoscenza a priori sui caratteri della forma
ricercata.
Questi risultati portano a preferire un algoritmo di segmentazione, come la
segmentazione a bacini o la tecnica dei contorni attivi nei casi in cui le ipotesi
riportate non sono vere o verificabili. Inoltre, si ricorda che per ottenere una
forma è necessario applicare un ulteriore algoritmo per inviluppare i punti
trovati e ciò richiede un ulteriore tempo d’attesa ed occupazione di memoria
fisica.
L’applicazione al rilevamento di una traiettoria si è mostrata invece
soddisfacente nei risultati. È una dimostrazione della “capacità di adattamento”
di un Algoritmo Genetico al variare dell’immagine su cui è applicato.
In conclusione, le prestazioni ottenibili in ambito matematico-geometrico
(ambienti in cui sono nati gli algoritmi genetici) sono riproponibili in modo
82
limitato nel problema proposto. Tuttavia, in condizioni favorevoli, l’Algoritmo
Genetico garantisce efficacia se non si vuole ottenere un risultato ottimo, ma ci
si accontenta di una “buona” soluzione.
83
Appendice A Codice dell’algoritmo
.
pkgColouredImages.MyARGB
1 package pkgColouredImages; 2 import java.awt.Color; 3 4 /** 5 * Class that implements the rapresentation of an ARGB item. 6 * @see <A HREF="http://en.wikipedia.org/wiki/RGBA_color_space">ARGB information</A> 7 * @author Bidinost Andrea 8 */ 9
10 public class MyARGB { 11 12 private int A; 13 private int R; 14 private int G; 15 private int B; 16 17 /** 18 * Make an ARGB object from a decimal representation. 19 * @param ColourIndex int number that represent the ARGB value 20 */ 21 public MyARGB(int ColourIndex) { 22 A = (ColourIndex >> 24) & 0xff; 23 R = (ColourIndex >> 16) & 0xff; 24 G = (ColourIndex >> 8) & 0xff; 25 B = (ColourIndex) & 0xff; 26 } 27 28 /** 29 * Make an ARGB object with the specified values. 30 * @param a Alpha value 31 * @param r Red value 32 * @param g Green value 33 * @param b Blue value 34 */ 35 public MyARGB(int a, int r, int g, int b) { 36 A = a; 37 R = r; 38 G = g; 39 B = b; 40 } 41 42 /** 43 * 44 * @return Returns alpha value of the current instance 45 */ 46 public int getA() 47 { return A; } 48 49 /** 50 * 51 * @return Returns blue value of the current instance 52 */ 53 public int getB() 54 { return B;} 55 56 /** 57 * 58 * @return Returns green value of the current instance 59 */ 60 public int getG() 61 { return G; } 62 63 /** 64 * 65 * @return Returns red value of the current instance
84
66 */ 67 public int getR() 68 { return R; } 69 70 /** 71 * @return Returns the index colour of the current instance 72 */ 73 public int getColourIndex() 74 { return ((A<<24) & 0xff000000) + ((R << 16) & 0x00ff0000) + ((G << 8 ) & 0x0000ff00) 75 + (B & 0x000000ff); } 76 77 /** 78 * Returns the distance of each attribute from the provided parametr. 79 * @param argb MyARGB object to compare 80 * @return Returns an array of 4 elements, each one represent the gap between 81 * the values of the respective variables 82 */ 83 84 public int[] getDeltaARGB(MyARGB argb) { 85 int[] distance = new int[4]; 86 distance[0] = Math.abs(A - argb.getA()); 87 distance[1] = Math.abs(R - argb.getR()); 88 distance[2] = Math.abs(G - argb.getG()); 89 distance[3] = Math.abs(B - argb.getB()); 90 91 return distance; 92 } 93 94 /** 95 * Returns true if the instance is in the provided range 96 * @param ext1 one extreme colour for the interval 97 * @param ext2 other extremee colour for the interval 98 * @return Returns true if the instance has a colour between ext1 and ext2, 99 * false otherwise
100 */ 101 public boolean isInRange(MyARGB ext1, MyARGB ext2) { 102 if(A >= Math.min(ext1.getA(), ext2.getA()) && A <= Math.max(ext1.getA(),ext2.getA())) 103 if(R >= Math.min(ext1.getR(), ext2.getR()) && R <= Math.max(ext1.getR(),ext2.getR())) 104 if(G >= Math.min(ext1.getG(), ext2.getG()) && G <= Math.max(ext1.getG(),ext2.getG())) 105 if(B >= Math.min(ext1.getB(), ext2.getB()) && B <= Math.max(ext1.getB(),ext2.getB())) 106 return true; 107 return false; 108 } 109 110 /** 111 * @return Returns the sequence of dimension's value A,R,G,B 112 */ 113 @Override 114 public String toString() { 115 return "A: " + A + " R: "+R +" G: " + G + " B: " + B; } 116 117 /** 118 * @return Returns the color of the current instance 119 */ 120 public Color getColor() 121 { return (new Color(this.getColourIndex(),true)); } 122 }
10 import java.awt.Graphics2D; 11 12 /** 13 * Represents targhet image on which start the ColourSearcher. 14 * @author Andrea Bidinost 15 */
85
16 public class MyImage 17 { 18 BufferedImage originalImg; 19 String imgPath; 20 21 /** 22 * Create a new MyImage object starting with a file. 23 * @param path FilePath (absolute) of the targhet image. 24 * @throws IOException 25 */ 26 public MyImage(String path) throws IOException { 27 File ImgFile = new File(imgPath = path); 28 originalImg = ImageIO.read(ImgFile); 29 } 30 31 /** 32 * Create a new MyImage object starting with a BufferedImage. 33 * @param img Image from a BufferedImage. 34 */ 35 public MyImage(BufferedImage img) { 36 originalImg = img; 37 imgPath = null; 38 } 39 40 /** 41 * Get the ARGB value at the cooridnate (point) 'p'. 42 * @param p Point on which return the ARGB value. 43 * @return ARGB' value at point p. 44 */ 45 public MyARGB getARGBatPoint(Point p) { 46 return (new MyARGB(originalImg.getRGB(p.x,p.y))); } 47 48 /** 49 * Returns a "pointed image" that represent the distribution of current 50 * genetic pixel population on the image. 51 * @param pois List of point founded by the algorithm. 52 * @return Returns a copy of the original image with "pois" at the pixel 53 * founded. 54 */ 55 public BufferedImage getPointedImage(ArrayList<Point> pois,Color backgroundPois) { 56 if(pois == null) 57 return originalImg; 58 59 BufferedImage imgTmp = new BufferedImage(originalImg.getWidth(), 60 originalImg.getHeight(),originalImg.getType()); 61 imgTmp.getGraphics().drawImage(originalImg,0,0,null); 62 Graphics2D g = (Graphics2D)imgTmp.getGraphics(); 63 g.setColor(backgroundPois); //mark the point with thata color 64 for(Point gp: pois) 65 { g.fillRect(gp.x,gp.y,(int)(originalImg.getWidth()/300, 66 (int)(originalImg.getHeight()/300)); 67 g.drawRect(gp.x,gp.y,(int)(originalImg.getWidth()/300), 68 (int)(originalImg.getHeight()/300)); 69 } 70 return imgTmp; 71 } 72 73 /** 74 * @return Returns the first image uploaded into the algorithm 75 */ 76 public BufferedImage getOriginalImage(){ 77 return originalImg; } 78 79 /** 80 * @return Returns the width of the image 81 */ 82 public int getWidth() 83 { return originalImg.getWidth();} 84 85 /** 86 * @return Returns the height of the image 87 */ 88 public int getHeight() 89 { return originalImg.getHeight(); } 90
86
91 /** 92 * @return Returns the path of the file containing the image 93 */ 94 public String getPath() 95 { return imgPath; } 96 }
4 /** 5 Implements the Evaluation Function 6 @author Andrea Bidinost 7 */ 8 public class GenPixelEvaluator 9 {
10 /** 11 Compute the Evaluation Value of the pixel comparing the targhet colour 12 range. 13 @param gp GeneticPixel to evaluate. 14 @param ext1Color An extreme bound of the colour range. 15 @param ext2Color An extreme bound of the colour range. 16 @return Returns the evaluation value over the GeneticPixel gp. 17 */ 18 public static int computeEV(GeneticPixel gp,MyARGB ext1Color, MyARGB ext2Color) 19 { 20 int[] gapFromExt1, gapFromExt2 = new int[4]; 21 int evaluation = 0;
1 package pkgGeneticColourItems; 2 import java.awt.Point; 3 import java.util.ArrayList; 4 import pkgColouredImages.MyARGB; 5 6 /** 7 * Represents a pixel (point and ARGB) and its genetic representation by 8 * genotype (a 64-bit sequence) 9 * @author Andrea Bidinost
10 */ 11 12 public class GeneticPixel implements Comparable 13 { 14 private Point coordinate; 15 private MyARGB argb; 16 private long genotype; 17 private int evaluation; 18 19 /** 20 * Create a pixel that will be a member of a population, starting with 21 * a Point. 22 * @param p Point on the targhet image. 23 * @param argb ARGB value on the pixel's coordinate. 24 * @param pInterval Number of bits to split a point's coordinate to make 25 * the genotype. 26 */ 27 public GeneticPixel(Point p,MyARGB argb, short pInterval) { 28 coordinate = p; 29 genotype = pointToBits(p,pInterval);
87
30 this.argb = argb; 31 evaluation = Integer.MAX_VALUE; 32 } 33 34 /** 35 * Create a pixel that will be a member of a population, starting with 36 * its genotype representation. 37 * @param bits 64-bit sequence representing the genotype. 38 * @param argb ARGB value on this pixel. 39 * @param pInterval Number of bits to split a point's coordinate to make 40 * the genotype. 41 */ 42 public GeneticPixel(long bits,MyARGB argb, short pInterval) { 43 coordinate = bitsToPoint(bits,pInterval); 44 genotype = bits; 45 this.argb = argb; 46 evaluation = Integer.MAX_VALUE; 47 } 48 49 /** 50 * Convert a couple of coordinate (point) into a genotype (sequence of 64 51 * bits). 52 * @param p Point that will be codified. Each number is a 32 bit integer. 53 * @param pInterval Number of bits in a "point's coordinate"-segment. 54 * @return Returns the genotype codified starting with point p. 55 */ 56 public static long pointToBits(Point p, short pInterval) { 57 if(! (pInterval != 0) ) 58 throw new IllegalArgumentException("pInterval should not be zero!"); 59 60 long result = 0; 61 long tmpX = 0; 62 long tmpY = 0; 63 short remainOnPoint = Integer.SIZE; 64 short remainOnBits = Long.SIZE; 65 int pointCommonMask = (int)Math.pow(2,pInterval)-1; 66 67 while ( (int)(remainOnPoint/pInterval) >0 ) 68 { 69 remainOnPoint -= pInterval; 70 tmpX = (p.x >> remainOnPoint) & pointCommonMask; 71 tmpY = (p.y >> remainOnPoint) & pointCommonMask; 72 remainOnBits -= pInterval; 73 result += (tmpX << remainOnBits); 74 remainOnBits -= pInterval; 75 result+= (tmpY << remainOnBits); 76 } 77 78 tmpX = p.x & ( (int)Math.pow(2, remainOnPoint)-1); 79 tmpY = p.y & ( (int)Math.pow(2,remainOnPoint) -1); 80 remainOnBits /= 2; 81 result += tmpX << remainOnBits; 82 result += tmpY; 83 return result; 84 } 85 86 /** 87 * Convert the genotype (sequence of 6 bits represented) into a couple of 88 * coordinate (point). 89 * @param b Genothype that will be de-codified in a point's coordinate. 90 * @param pInterval Number of bits in a "point's coordinate"-segment. 91 * @return Returns the point de-codified starting with the genotype b. 92 */ 93 public static Point bitsToPoint(long b, short pInterval) { 94 if(! (pInterval != 0)) 95 throw new IllegalArgumentException("pInterval should not be zero!"); 96 97 Point result = new Point(0,0); 98 short remainOnBits = Long.SIZE; 99 short remainOnPoint = Integer.SIZE;
100 int bitsCommonMask = (int)Math.pow(2,pInterval)-1; 101 int tmpX, tmpY; 102 103 while( (remainOnBits/(2*pInterval)) > 0) 104 {
88
105 remainOnBits -= pInterval; 106 tmpX =(int)((b >> remainOnBits) & bitsCommonMask); 107 remainOnBits -= pInterval; 108 tmpY =(int)((b >> remainOnBits) & bitsCommonMask); 109 110 remainOnPoint -= pInterval; 111 result.x += tmpX << remainOnPoint; 112 result.y += tmpY << remainOnPoint; 113 } 114 115 remainOnBits /= 2; 116 int msk = (int)Math.pow(2, remainOnBits) -1; 117 result.x += (b >> remainOnBits) & msk; 118 result.y += b & msk; 119 120 return result; 121 } 122 123 /** 124 * Get the GeneticPixel coordinates. 125 * @return Coordinate of the instanced-pixel. 126 */ 127 public Point getCoordinate() 128 { return new Point(coordinate.x, coordinate.y);} 129 130 /** 131 * Get the ARGB associated at this pixel. 132 * @return MyARGB object. 133 */ 134 public MyARGB getARGB() 135 { return this.argb; } 136 137 /** 138 * Get the Evaluation Value of the instance. 139 * @return Evaluation (non negative int) of teh instanced-pixel. 140 */ 141 public int getEvaluation() 142 { return evaluation; } 143 144 /** 145 * Get the genotype of the instance. 146 * @return Genotype (seqence of 64 bits) of the instanced-pixel. 147 */ 148 public long getGenotype() 149 { return genotype; } 150 151 /** 152 * Set the Evaluation Value of the instance. 153 * @param e Non negative value of the Evaluation Function on this pixel. 154 */ 155 public void setEvaluation(int e) { 156 if(e< 0) 157 throw new IllegalArgumentException("parameter must be not-negative"); 158 evaluation = e; 159 } 160 161 /** 162 * Inverts the vaule of a specific bit in the provided sequence. 163 * @param bits Sequence that from which obtain result sequence. 164 * @param invertPoint Point on which invert the bit. 165 * @return Return 'bits' with bit inverted at 'invertPoint' . 166 */ 167 public static long invertBitAt(long bits, short invertPoint) { 168 if(invertPoint< 0 || invertPoint >63) 169 throw new IllegalArgumentException("'position' must be in [0,63]"); 170 171 long result; 172 result = bits ^ (long)Math.pow(2,invertPoint); 173 return result; 174 } 175 176 /** 177 * Cross provided GeneticPixel cutting on crossPoint and make 2 children. 178 * @param dad GeneticPixel that will be cut and cross with 'mum'. 179 * @param mum GeneticPixel thath will be cut and cross with 'dad'.
89
180 * @param crossPoint Point on which cut the genotypes to make another gene. 181 * @return Return two genes(sequence of 64 bits) made crossing the genes. 182 */ 183 public static ArrayList<Long> crossGenotypes(GeneticPixel dad, GeneticPixel mum, 184 short crossPoint) { 185 if(crossPoint < 0 || crossPoint > 63) 186 throw new IllegalArgumentException("'position' must be in [0,63]"); 187 188 ArrayList<Long> newGPxl = new ArrayList<Long>(2); 189 long genotypeMask=(long)Math.pow(2,crossPoint)-1; 190 long notGenotypeMask = (long)Math.pow(2,64) -1 -genotypeMask; 191 192 newGPxl.add((dad.getGenotype() & genotypeMask) 193 + (mum.getGenotype() & notGenotypeMask)); 194 newGPxl.add((mum.getGenotype() & genotypeMask) 195 + (dad.getGenotype() & notGenotypeMask)); 196 197 return newGPxl; 198 } 199 200 @Override 201 public int compareTo(Object anotherGP) { 202 if(! (anotherGP instanceof GeneticPixel)) 203 throw new ClassCastException("'anotherGP' must be a GeneticPixel"); 204 205 int anotherEv = ((GeneticPixel)anotherGP).getEvaluation(); 206 return this.evaluation - anotherEv; 207 } 208 209 @Override 210 public String toString() 211 { return "\nPoint: " + stringPoint(this.coordinate) + "\nGenotype: " 212 + this.genotype + "\nARGB: " + this.argb;} 213 214 215 /** 216 * Gets the string representation of a specified point 217 * @param p 218 * @return Return the string representation of 'p' 219 */ 220 public static String stringPoint(Point p) 221 { return "[ "+p.x+" , "+p.y+" ]";} 222 223 }
.
pkgGeneticColourItems.GeneticOperations
1 package pkgGeneticColourItems; 2 import java.util.ArrayList; 3 import java.util.Random; 4 5 /** 6 * Implements most common genetic operations among a genes, like Crossover 7 * and Mutation. 8 * @author AndreaBidinost 9 */
10 public class GeneticOperations 11 { 12 /** 13 * Implements crossover operations over a couple of genes, with probability 14 * pCrossover. 15 * @param pop Population where choose the parents. 16 * @param pCrossover Crossover probability. 17 * @param length Maximum length of a genotype (based on the targhet image). 18 * @return Returns the 2 children (if exists) into an ArrayList or null. 19 */ 20 public static ArrayList<Long> crossover(Population pop, double pCrossover, int length) { 21 if(Math.random() > pCrossover) 22 { return null; } 23 24 int popPositionDad, popPositionMum; 25 GeneticPixel dadGp, mumGp; 26 ArrayList<Long> result = new ArrayList<Long>(2); 27 Random casualGenerator = new Random(); 28
90
29 /* Choose randomly 2 elements from the population, generating a random 30 * number with gaussian distribution on [0,1] and resize that 31 * into the population's range of indexes 32 */ 33 34 popPositionDad = Math.min((int)(Math.abs(casualGenerator.nextGaussian()) 35 *pop.getSize()/2.55),pop.getSize()-1); 36 popPositionMum = Math.min((int)(Math.abs(casualGenerator.nextGaussian()) 37 *pop.getSize()/2.55),pop.getSize()-1); 38 try{ 39 dadGp = pop.getAt(popPositionDad); 40 mumGp = pop.getAt(popPositionMum);} 41 catch (java.lang.ArrayIndexOutOfBoundsException a) 42 { throw new java.lang.ArrayIndexOutOfBoundsException(); } 43 44 result = GeneticPixel.crossGenotypes(dadGp,mumGp, 45 (short)(casualGenerator.nextInt(length))); 46 47 return result; 48 } 49 50 /** 51 * Implements the mutate operations over a genotype. 52 * @param genotype bits on which mutate a single bit. 53 * @param pMutate Mutate probability. 54 * @param length Maximum length of a genotype (based on the targhet image). 55 * @return Returns a new genotype as the mutation of provided genotype. 56 */ 57 public static long mutate(long genotype, double pMutate, int length) { 58 Random generator = new Random(); 59 long result = genotype; 60 61 for(short g = 0; g<= (int)(Math.log(length)/Math.log(2));g++) 62 { 63 if(Math.random() < pMutate) 64 { result = GeneticPixel.invertBitAt(result,g); } 65 } 66 67 return result; 68 } 69 }
.
pkgGeneticColourItems.Population
1 package pkgGeneticColourItems; 2 import java.util.ArrayList; 3 import java.util.Collections; 4 5 /** 6 * Represents a set of many GeneticPixel items. 7 * @author Andrea Bidinost 8 */ 9 public class Population
10 { 11 private ArrayList<GeneticPixel> generation; 12 private int minEv; 13 private int maxEv; 14 private int meanX, varX; 15 private int meanY, varY; 16 private double meanEv; 17 private double varEv; 18 19 /** 20 * Sets the attribute value and make an empity population. 21 */ 22 public Population() { 23 generation = new ArrayList<GeneticPixel>(); 24 minEv = Integer.MAX_VALUE; 25 maxEv = 0; 26 meanX = varX = meanY = varY = 0; 27 meanEv = varEv = 0.0; 28 } 29 30 /** 31 * Add a GenethicPixel to the population.
91
32 * @param gp GeneticPixel that will be add. 33 */ 34 public void add(GeneticPixel gp) { 35 generation.add(gp); 36 minEv = Math.min(minEv,gp.getEvaluation()); 37 maxEv = Math.max(maxEv,gp.getEvaluation()); 38 } 39 40 /** 41 * Get the GeneticPixel in position 'idx'. 42 * @param idx. 43 * @return Returns the item in 'idx' position of the population 44 **/ 45 public GeneticPixel getAt(int idx) { 46 return generation.get(idx); } 47 48 /** 49 * Compute means and variances of: population's Evaluation value,x position 50 * and y position. 51 */ 52 public void computeStatistic() { 53 for(int i=0; i<generation.size(); i++) 54 { 55 meanEv += generation.get(i).getEvaluation(); 56 meanX += generation.get(i).getCoordinate().x; 57 meanY += generation.get(i).getCoordinate().y; 58 } 59 meanEv/=generation.size(); 60 meanX /= generation.size(); 61 meanY /= generation.size(); 62 63 for(int i=0; i<generation.size(); i++) 64 { 65 varEv += Math.pow(generation.get(i).getEvaluation() - meanEv,2); 66 varX += Math.pow(generation.get(i).getCoordinate().x - meanX,2); 67 varY += Math.pow(generation.get(i).getCoordinate().y - meanY, 2); 68 } 69 varEv = Math.sqrt(varEv)/generation.size(); 70 varX = (int) Math.sqrt(varX)/generation.size(); 71 varY = (int) Math.sqrt(varY)/generation.size(); 72 } 73 74 /** 75 * Get the population's size. 76 * @return Returns number of GeneticPixel in the population. 77 */ 78 public int getSize() 79 { return generation.size(); } 80 81 /** 82 * Get the minimun of the current evaluation's values. 83 * @return Returns the minimum of the current evaluation's values. 84 */ 85 public double getMinEv() 86 { return minEv; } 87 88 /** 89 * Get the maximum of the current evaluation's values. 90 * @return Returns the maximum of the current evaluation's values. 91 */ 92 public double getMaxEv() 93 { return maxEv; } 94 95 /** 96 * Get the mean of the current evaluation's values. 97 * @return Returns the mean of the current evaluation's values. 98 */ 99 public double getMeanEv()
100 { return meanEv;} 101 102 /** 103 * Get the variance of the current evaluation's values. 104 * @return Returns the variance of the current evaluation's values. 105 */ 106 public double getVarEv()
92
107 { return varEv; } 108 109 /** 110 * Get the mean of the current x-position's values. 111 * @return Returns the mean of the current x-position's values. 112 */ 113 public int getMeanX() 114 { return meanX; } 115 116 /** 117 * Get the mean of the current y-position's values. 118 * @return Returns the mean of the current y-position's values. 119 */ 120 public int getMeanY() 121 { return meanY; } 122 123 /** 124 * Get the variance of the current x-position's values. 125 * @return Returns the variance of the current x-position's values. 126 */ 127 public int getVarX() 128 { return varX; } 129 130 /** 131 * Get the variance of the current y-position's values. 132 * @return Returns the variance of the current y-position's values. 133 */ 134 public int getVarY() 135 { return varY; } 136 137 /** 138 * Sort the population. 139 * @see <A HREF="http://docs.oracle.com/javase/1.4.2/docs/api/java/util/ 140 * Collections.html">Collection.Sort algorithm explaination</A> 141 */ 142 public void sortPopulation() 143 { Collections.sort(generation); } 144 145 /** 146 * Get all the current population's elements. 147 * @return Returns a list of the current elements. 148 */ 149 public ArrayList<GeneticPixel> getAllPixels() { 150 return generation; } 151 }
10 * Program's entry point. Sets the environement and starts the generations. 11 * At every generations, returns the points that meet the targhet colour, 12 * if exists. 13 * @author Andrea Bidinost 14 */ 15 public class Searcher { 16 17 private MyImage targhetImage; 18 private short segmentDimension; 19 private int nPeople; 20 private MyARGB lowColor; 21 private MyARGB highColor; 22 private Population currPop; 23 private Population nextPop; 24 private int geneLength; 25 26 /** 27 * Initialize the attributes.
93
28 * @param targhetImage Image on wich search some colours. 29 * @param segDim Length of genotype's sequence that will be cut at the 30 * crossover time. 31 * @param nPeople Number of element in a population 32 * @param lowTarghetColor Lower extreme of the targhet colour interval 33 * @param highTarghetColor Higher extreme of the targhet colour interval 34 */ 35 public Searcher(MyImage targhetImage, short segDim, int nPeople,MyARGB lowTarghetColor, 36 MyARGB highTarghetColor) { 37 this.targhetImage = targhetImage; 38 this.segmentDimension = segDim; 39 this.nPeople = nPeople; 40 this.lowColor = lowTarghetColor; 41 this.highColor = highTarghetColor; 42 geneLength = Math.max(intUpLog(2, targhetImage.getHeight()), 43 intUpLog(2, targhetImage.getWidth())); 44 } 45 46 /** 47 * Create the first generation of the population. 48 * @return Returns the oints that meets the targhet colour range (if exist). 49 */ 50 public ArrayList<Point> makeFirstGeneration() { 51 ArrayList<Point> result = new ArrayList<Point>(); 52 ArrayList<Point> casualPoints = new ArrayList<Point>(nPeople); 53 Random r = new Random(); 54 currPop = new Population(); 55 GeneticPixel tmpGp; 56 int width, height; 57 width = targhetImage.getOriginalImage().getWidth(); 58 height = targhetImage.getOriginalImage().getHeight(); 59 60 // Make nPeople random point 61 for (int i = 0; i < nPeople; i++) { 62 casualPoints.add(new Point(r.nextInt(width), r.nextInt(height))); 63 } 64 65 // Build the GeneticPixel from the points 66 for (Point p : casualPoints) { 67 tmpGp = new GeneticPixel(p, targhetImage.getARGBatPoint(p), 68 segmentDimension); 69 currPop.add(tmpGp); 70 if (tmpGp.getARGB().isInRange(lowColor, highColor)) { 71 result.add(p); 72 } 73 tmpGp.setEvaluation(GenPixelEvaluator.computeEV(tmpGp, lowColor, 74 highColor)); 75 } 76 77 currPop.sortPopulation(); 78 return ((result.isEmpty()) ? null : result); 79 } 80 81 /** 82 * Make the next generations, using crossover and mutation operations. 83 * @param pCrossover Probability of crossover. 84 * @param pMutation Probability of mutation. 85 * @return Points that meets the targhet colour range 86 */ 87 public ArrayList<Point> makeNextGeneration(double pCrossover, double pMutation) { 88 ArrayList<Point> result = new ArrayList<Point>(); 89 ArrayList<Long> childrens = new ArrayList<Long>(2); 90 GeneticPixel tmpGp; 91 92 nextPop = new Population(); 93 94 95 while (nextPop.getSize() < nPeople) { 96 // Make the children using 2 random parents 97 childrens = GeneticOperations.crossover(currPop, pCrossover,2 * geneLength); 98 99 if (childrens == null) {
100 continue; 101 } 102
94
103 //For the first child... 104 //mutate, add to nextPop, verify if it's in the image's range. 105 //Check if it's a good point and compute it's evaluation. 106 //Else, make a new casual point and insert into the population. 107 108 childrens.set(0, GeneticOperations.mutate(childrens.get(0), 109 pMutation, 2 * geneLength)); 110 if (okCheckRange(childrens.get(0))) { 111 tmpGp = new GeneticPixel(childrens.get(0),targhetImage.getARGBatPoint( 112 GeneticPixel.bitsToPoint(childrens.get(0), 113 segmentDimension)), segmentDimension);} 114 else { 115 Point tmpP; 116 Random r = new Random(); 117 tmpGp = new GeneticPixel(tmpP = new Point(r.nextInt( 118 targhetImage.getWidth()),r.nextInt( targhetImage. getHeight())), 119 targhetImage.getARGBatPoint(tmpP), segmentDimension); 120 } 121 122 if (tmpGp.getARGB().isInRange(lowColor, highColor)) { 123 result.add(tmpGp.getCoordinate()); 124 } 125 tmpGp.setEvaluation(GenPixelEvaluator.computeEV(tmpGp, lowColor, 126 highColor)); 127 nextPop.add(tmpGp); 128 129 //For the second child...(if there's space in the population) 130 //mutate, add to nextPop, verify if it's in the image range. 131 // Else, make a new casual point and insert into the population. 132 133 if ((nextPop.getSize() == nPeople)) { 134 break; 135 } 136 childrens.set(1, GeneticOperations.mutate(childrens.get(1),pMutation, 2 * geneLength)); 137 138 if (okCheckRange(childrens.get(1))) { 139 tmpGp = new GeneticPixel(childrens.get(1), 140 targhetImage.getARGBatPoint(GeneticPixel.bitsToPoint(childrens.get(1), 141 segmentDimension)), segmentDimension); 142 } 143 144 if (tmpGp.getARGB().isInRange(lowColor, highColor)) { 145 result.add(tmpGp.getCoordinate()); 146 } 147 tmpGp.setEvaluation(GenPixelEvaluator.computeEV(tmpGp, lowColor,highColor)); 148 nextPop.add(tmpGp); 149 } 150 151 nextPop.sortPopulation(); 152 currPop = nextPop; 153 return ((result.isEmpty()) ? null : result); 154 } 155 156 /* 157 * Check if the provided genotype reperesent a point into the image's area. 158 */ 159 private boolean okCheckRange(long l) { 160 Point p = GeneticPixel.bitsToPoint(l, segmentDimension); 161 if (p.x >= 0) { 162 if (p.x < targhetImage.getWidth()) { 163 if (p.y >= 0) { 164 if (p.y < targhetImage.getHeight()) { 165 return true; 166 } 167 } 168 } 169 } 170 return false; 171 } 172 173 /** 174 * Get the list of current population's points. 175 * @return Returns the list of current population's points. 176 */ 177 public ArrayList<Point> getAllPoints() {
95
178 ArrayList<Point> result = new ArrayList<Point>(nPeople); 179 ArrayList<GeneticPixel> ag = currPop.getAllPixels(); 180 181 for (GeneticPixel gp : ag) { 182 result.add(gp.getCoordinate()); 183 } 184 185 return result; 186 } 187 188 /* 189 * Implements the ceiling of base 'base' logaritm of 'argument' 190 */ 191 private int intUpLog(int base, int argument) { 192 return (int) (Math.log10(argument) / Math.log10(base)) + 1; 193 } 194 195 /** 196 * Get the current population's statistics. 197 * @return Returns a string conaining the value of the current population's 198 * attribute: 199 * Evaluation value range of values, it's mean and variance; 200 * Mean and variance of coordinate XY. 201 */ 202 public String getStatistics() { 203 currPop.computeStatistic(); 204 205 String result = "Evaluation range: " + "(" + currPop.getMinEv() + " ; " 206 + currPop.getMaxEv() + " )\n"; 207 208 result += "Evaluation Mean: " 209 + (new Double(currPop.getMeanEv())).intValue() 210 + " ; Evaluation Variance: " 211 + (new Double(currPop.getVarEv())).intValue() + "\n"; 212 213 result += "CoordinateX Mean: " 214 + (new Double(currPop.getMeanX())).intValue() 215 + " ; CoordinateX Variance: " 216 + (new Double(currPop.getVarX())).intValue() + "\n"; 217 218 result += "CoordinateY Mean: " 219 + (new Double(currPop.getMeanY())).intValue() 220 + " ; CoordinateY Variance: " 221 + (new Double(currPop.getVarY())).intValue() + "\n"; 222 223 return result; 224 } 225 }
.
pkgPrimitiveWrapper.MyBoolean
1 package pkgPrimitiveWrapper; 2 3 /** 4 * Wrapper boolean class 5 * @author Bidinost Andrea 6 */ 7 public class MyBoolean { 8 private boolean b; 9
10 /** 11 * Create a new instance with 'false' as default value 12 */ 13 public MyBoolean() 14 { b=false;} 15 16 /** 17 * Create a new instance with 'a' as a default value 18 * @param a Boolean value to initialize the instance 19 */ 20 public MyBoolean(boolean a) 21 { b=a;} 22 23 /** 24 * Set value of the current instance
96
25 */ 26 public void setFalse() 27 { b=false;} 28 29 /** 30 * Set current instance as 'true' 31 */ 32 public void setTrue() 33 { b=true;} 34 35 /** 36 * Set the current instance as 'a' 37 * @param a Boolean value to change the instance 38 */ 39 public void setAs(boolean a) 40 { b = a; } 41 42 /** 43 * Get the current instance value 44 * @return Returns the value of the current instance 45 */ 46 public boolean getValue() 47 { return b; } 48 49 }
10 * Class for read/write operation on a file 11 * @author Bidinost Andrea 12 */ 13 public class MyFileOperator { 14 private String outputFile; 15 private BufferedWriter writerOnOutput; 16 private BufferedReader readerOnOutput; 17 18 /** 19 * Initialize a writer and a reader on a text file 20 * @param path Path of the I/O file 21 * @throws IOException 22 */ 23 public MyFileOperator(String path) throws IOException { 24 writerOnOutput = new BufferedWriter(new FileWriter(outputFile = path)); 25 readerOnOutput = new BufferedReader(new FileReader(outputFile)); 26 } 27 28 /** 29 * Write a string on the file and add a new line character at the end. 30 * @param s String that will be wrote 31 * @throws IOException 32 */ 33 public void writeln(String s) throws IOException 34 { writerOnOutput.write(s);} 35 36 /** 37 * Read a string from the file 38 * @return Returns the string read from the file, until a new line character 39 * @throws IOException 40 */ 41 public String readln() throws IOException 42 { return readerOnOutput.readLine(); } 43 44 /** 45 * Close the writer operator. 46 * @throws IOException 47 */ 48 public void closeWrite() throws IOException 49 { writerOnOutput.close();} 50 51 /** 52 * Close the reader operator. 53 * @throws IOException 54 */ 55 public void closeRead() throws IOException 56 { readerOnOutput.close();} 57 58 /** 59 * Restarts the writer operator on the same file. 60 * @throws IOException 61 */ 62 public void writeRestart() throws IOException 63 { writerOnOutput = new BufferedWriter(new FileWriter(outputFile));} 64 65 /** 66 * Restart the reader operator on the same file 67 * @throws FileNotFoundException 68 */ 69 public void readReastart() throws FileNotFoundException
103
70 { readerOnOutput = new BufferedReader(new FileReader(outputFile));} 71 }