Salta ai contenuti. | Salta alla navigazione

Strumenti personali

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:

filtro :: (Int − > Int − > Int) − > [[Int]] − > [[Int]]

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 è

a1,1
a1,2
...
a1,n−1
a1,n
a2,1
a2,2
...
a2,n−1
a2,n
...
am,1
am,2
...
am,n−1
am,n

allora applicando filtro f alla matrice, si ottiene una matrice

f (a1,1, a1,2)
f(a1,2,a1,3)
...
f(a1,n−1,a1,n)
a1,n
f(a2,1, a2,2)
f(a2,2,a2,3)
...
f(a2,n−1, a2,n)
a2,n
...
f(am,1, am,2 )
f( am,2, am,3)
...
f( am,n−1, am,n)
am,n

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

[[(f 1 2),(f 2 3), 3],[(f 4 5), (f 5 6), 6]].

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

esempio.png

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)