25 luglio 2017 - laboratorio
Linguaggi e Traduttori
Prof. Marco Gavanelli
25 luglio 2017
Esercizio 1 (punti 15)
Un'immagine a scala di grigio è costituita da una matrice di interi, in cui il valore 0 rappresenta il nero, e gli altri valori rappresentano varie sfumature di grigio (più il numero è grande, più chiaro è il pixel).
È richiesto di creare una funzione Haskell di ordine superiore che permetta di applicare dei filtri ad un'immagine. L'immagine va rappresentata come matrice di interi, ovvero ha tipo [[Int]].
La funzione filtro ha questa interfaccia:
|
e produce una nuova matrice che ha la stessa dimensione di quella originaria. Gli elementi della matrice di uscita sono ottenuti applicando la funzione data come primo parametro della filtro agli elementi adiacenti in orizzontale della matrice di ingresso. Più in dettaglio, se la matrice di ingresso è
|
allora applicando filtro f alla matrice, si ottiene una matrice
|
In altre parole la funzione interna va applicata a tutti i pixel di coordinate (x,y)−(x+1,y) dell'immagine.
Ad esempio, filtro f [[1,2,3],[4,5,6]] produce una matrice
|
In questo esempio, l'ultima colonna della matrice è rimasta identica all'ultima colonna della matrice iniziale; lo studente può scegliere il valore da mettere nell'ultima colonna (qualunque valore va bene).
Ad esempio, il filtro "sfuocatura" sostituisce ogni pixel con la media dei due pixel adiacenti in orizzontale. Se viene data una matrice [[10,2,7],[4,0,60]], il filtro "sfuocatura" dovrà quindi produrre la matrice [[6,4,7],[2,30,60]] (di nuovo, il valore nell'ultima colonna non è importante). Per calcolare la divisione intera si può usare la funzione quot ("quotient").
Il filtro "contorni" sostituisce ogni pixel con la differenza in valore assoluto dei due pixel adiacenti in orizzontale. Se viene data una matrice [[10,10,7,7],[4,0,60,50]], il filtro "contorni" dovrà quindi produrre la matrice [[0,3,0,7],[4,60,10,50]] (di nuovo, il valore nell'ultima colonna non è importante).
Si implementi la funzione filtro e la si usi per implementare le funzioni sfuocatura e contorni. Le funzioni sfuocatura e contorni hanno come interfaccia [[Int]] -> [[Int]].
Esercizio 2 (punti 5)
Si applichino i filtri dell'esercizio precedente all'immagine nel file immagine.pgm, in formato PGM.
Nel formato PGM, le immagini sono rappresentate come file di testo. Inizialmente il file contiene, separati da spazi:
- la stringa
"P2"
- la larghezza W dell'immagine (intero)
- l'altezza H dell'immagine (intero)
- il numero S di sfumature
Ci sono poi W×H numeri interi che vanno da 0 a S; i numeri rappresentano l'intensità di ciascun pixel dell'immagine:
- 0 rappresenta il colore nero,
- S rappresenta il bianco
- e i numeri intermedi rappresentano le varie tonalità di grigio.
Ad esempio, il seguente file:
P2 | 5 | 5 | 9 | |
0 | 0 | 0 | 0 | 0 |
0 | 9 | 0 | 0 | 0 |
0 | 9 | 7 | 0 | 0 |
0 | 9 | 7 | 5 | 0 |
0 | 9 | 7 | 5 | 3 |
rappresenta l'immagine
Utilizzando le funzioni dell'esercizio 1, si scriva un programma Haskell che, dato il file immagine.pgm, crea i due nuovi file sfuocata.pgm e contorni.pgm, ottenuti rispettivamente applicando i filtri "sfuocatura" e "contorni" all'immagine immagine.pgm.
Soluzione
import System.IO main = do mss <- readpgm "immagine.pgm" writepgm (filtro blur mss) "blurred.pgm" writepgm (filtro edge mss) "edge.pgm" leggiInt x = read x :: Int readpgm fileName = do stream <- readFile "immagine.pgm" let ws = words stream sizex = read (ws !! 1) :: Int return (to_matrix sizex (drop 4 ws)) to_matrix sizex [] = [] to_matrix sizex ms = (map leggiInt (take sizex ms)):to_matrix sizex (drop sizex ms) writepgm mss fileName = do outh <- openFile fileName WriteMode hPutStr outh ("P2 "++((show.length.head) mss)++" "++((show.length) mss)++" "++(show (maxMatrix mss))++"\n") saveMatrix outh mss hClose outh saveList handle ls = do sequence (map (\x -> hPutStr handle ((show x)++" ")) ls) hPutStr handle "\n" saveMatrix handle mss = do sequence (map (saveList handle) mss) maxMatrix mss = foldl max 0 (map maxlist mss) maxlist ls = foldl max 0 ls filtro :: (Int -> Int -> Int) -> [[Int]] -> [[Int]] filtro f mss = map (mapint f) mss mapint f [a] = [a] mapint f (a:b:xs) = (f a b):mapint f (b:xs) blur a b = quot (a+b) 2 edge a b = abs (a-b)