Responsabili:
Termen de predare: 15.01.2017 23:59
Pentru fiecare zi (24 de ore) de întârziere, se vor scădea 10 puncte din nota acordată. Deadline-ul hard este 18.01.2017 23:59.
Actualizări:
Scopul temei:
Procesarea de imagini se refera la aplicarea unor algoritmi specifici pe continutul unei imagini pentru a obtine anumite efecte (blur, sharpening, etc.) sau rezultate (face detection/recognition, etc.). In aceasta tema vom lucra cu unul dintre cele mai simple formate de imagini si anume formatul BMP.
O imagine BMP are următoarea structură:
Header-ele pe care le puteți folosi în implementare se află în scheletul de cod asociat temei.
Veti avea de rezolvat 4 task-uri. La primele 3 task-uri o sa procesati o singura imagine. Numele acesteia o sa fie citit de pe prima linie din fisierul de intrare (vezi formatul datelor de intrare). La task-ul 4 o sa lucrati cu un format binar special (mai multe detalii in sectiunea corespunzatoare task-ului 4).
Acest task presupune transformarea unei imagini color intr-o imagine alb-negru. Fisierul .bmp la care se gaseste imaginea se va citi de pe prima linie a fisierului de intrare, numit input.txt. Daca numele imaginii este <nume>.bmp atunci imaginea alb-negru se va scrie in fisierul <nume>_black_white.bmp (de exemplu, daca prima linie din fisierul input.txt este image.bmp atunci imaginea alb negru se va scrie in fisierul image_black_white.bmp). Procedeul prin care o imagine color se transforma intr-o imagine alb-negru este urmatorul: fiecare pixel din imaginea color, fie acesta (R, G, B), va deveni (X, X, X) unde X = [ (R + G + B) / 3] unde prin [] se intelege parte intreaga (inferioara). De exemplu pixelul (3, 2, 2) va deveni (2, 2, 2), iar pixelul (10, 20, 30) va deveni (20, 20, 20).
Exemplu: Daca imaginea color arata astfel:
Dupa transformare ar trebui sa arate astfel:
In cadrul acestui task va trebui sa aplicati anumite filtre pe o imagine. Un filtru este o matrice (in cazul acestei teme matricea va avea mereu 3 linii si 3 coloane) care este aplicata fiecarui pixel din imagine pentru a obtine noul pixel. In continuare o sa vedem ce inseamna sa aplici o matrice (filtru) unui pixel. Fie $(R_{22},G_{22},B_{22})$ un pixel din imagine care are urmatorii vecini:
$$ \begin{bmatrix} (R_{11},G_{11},B_{11}) & (R_{12},G_{12},B_{12}) & (R_{13},G_{13},B_{13}) \\ (R_{21},G_{21},B_{21}) & (R_{22},G_{22},B_{22}) & (R_{23},G_{23},B_{23}) \\ (R_{31},G_{31},B_{31}) & (R_{32},G_{32},B_{32}) & (R_{33},G_{33},B_{33}) \end{bmatrix} $$
si fie filtrul:
$$ A = \begin{bmatrix} a_{11} & a_{12} & a_{13} \\ a_{21} & a_{22} & a_{23} \\ a_{31} & a_{32} & a_{33} \end{bmatrix} $$
Atunci, in imaginea rezultata in urma aplicarii filtrului A, pixel-ul $(R_{22},G_{22},B_{22})$ va fi inlocuit cu $(R'_{22},G'_{22},B'_{22})$ unde:
$$ R'_{22} = \sum_{i=1}^3 \sum_{j=1}^3 R_{ij}a_{ij} $$ $$ G'_{22} = \sum_{i=1}^3 \sum_{j=1}^3 G_{ij}a_{ij} $$ $$ B'_{22} = \sum_{i=1}^3 \sum_{j=1}^3 B_{ij}a_{ij} $$
Sa presupunem ca avem urmatoarea imagine:
(2 2 2) (3 3 3) (0 0 0) (0 0 0) (10 10 10) (1 1 1) (0 0 0) (0 0 0) (0 0 0) (0 0 0) (50 50 5) (0 0 0) (0 0 0) (0 0 0) (240 0 240) (0 0 0)
Pentru imaginea de mai sus, fisierul BMP ar arata astfel (ignorand cele 2 headere):
(0 0 0) (0 0 0) (240 0 240) (0 0 0) No padding (0 0 0) (0 0 0) (50 50 5) (0 0 0) No padding (10 10 10) (1 1 1) (0 0 0) (0 0 0) No padding (2 2 2) (3 3 3) (0 0 0) (0 0 0) No padding
Pe imaginea de mai sus dorim sa aplicam urmatorul filtru:
$$ \begin{bmatrix}0 & 1 & 0\\1 & 1 & 1\\0 & 1 & 0 \end{bmatrix} $$
Imaginea rezultata va fi:
(15 15 15) (6 6 6) (3 3 3) (0 0 0) (13 13 13) (14 14 14) (51 51 6) (0 0 0) (10 10 10) (51 51 6) (255 50 245) (50 50 5) (0 0 0) (240 0 240) (255 50 245) (240 0 240)
Pentru rezolvarea acestui task va trebui sa aplicati 3 filtre de edge-detection. Acestea sunt:
$$ F_1 = \begin{bmatrix}-1 & -1 & -1\\-1 & 8 & -1\\-1 & -1 & -1 \end{bmatrix} F_2 = \begin{bmatrix}0 & 1 & 0\\1 & -4 & 1\\0 & 1 & 0 \end{bmatrix} F_3 = \begin{bmatrix}1 & 0 & -1\\0 & 0 & 0\\-1 & 0 & 1 \end{bmatrix} $$
Aceste filtre se vor aplica pe rand imaginii alb-negru obtinute la Task-ul 1. Imaginea obtinuta prin aplicarea lui $F_1$ imaginii alb-negru se va salva in fisierul <nume>_f1.bmp, imaginea obtinuta prin aplicarea lui $F_2$ imaginii alb-negru se va salva in fisierul <nume>_f2.bmp, iar imaginea obtinuta prin aplicarea lui $F_3$ imaginii alb-negru se va salva in fisierul <nume>_f3.bmp.
Ne propunem sa realizam o compresie simpla pentru imaginile BMP. La un nivel inalt, algoritmii de compresie se impart in doua categorii: lossless si lossy. Compresia imaginilor este o compresie lossy. Nu se poate aplica o compresie lossless, pe o imagine, care sa aiba un grad ridicat de compresie deoarece algoritmii de compresie lossless se bazeaza pe eliminarea reduntantei statistice, care in cazul unei imagini este mica (deoarece intr-o imagine, putem intalnii, orice valoare cu aceeasi probabilitate). De exemplu, formatul JPEG presupune o compresie de tip loosy. Algoritmul de compresie pe care il vom aplica in aceasta tema este unul minimalist si se bazeaza pe urmatoarea idee: pixeli invecinati care sunt putin diferiti (culoarea este asemanatoare) pot fi grupati in pixeli cu aceeasi culoare fara sa se observe o diferenta majora la vizualizarea imaginii. Ganditi-va ca avem urmatoarea imagine
Se observa ca exista apoximativ 3 nuante de culoare: albastru inchis, albastru deschis si verde. In loc sa salvam fiecare pixel separat in fisier putem sa specificam doar cele trei zone si sa spunem ca fiecare are o anumita culoare. Astfel, se va pierde din calitate (compresie loosy) dar se va castiga spatiu. Cat se pierde din calitate este direct proportional cu cat de mare este pragul pentru care vom considera ca doi pixeli fac parte din aceeasi zona.
Algoritmul de compresie pe care o sa il implementati (si descrie formal ceea ce am spus mai sus) este urmatorul:
1) Se alege un pixel din imagine care nu a fost inclus in nicio zona. Fie acest pixel $ (R, G, B) $. Daca toti pixelii au fost inclusi intr-o zona atunci algoritmul s-a terminat;
2) Pornind de la acest pixel se detemina zona de pixeli care satisface simultan urmatoarele conditii:
3) Toti pixelii din zona determinata vor avea culoarea pixelului de la pasul 1) adica $ (R, G, B) $.
4) Dupa deteminarea noii zone se reia algoritmul incepand cu pasul 1).
Modul in care alegem pixelul la pasul 1) poate inflenta calitatea algoritmului. Pentru aceasta tema vom aplica urmatoarea metoda de selectie: daca exista mai multi pixeli care nu au fost deja inclusi intr-o zona, se va alege acel pixel care se afla pe linia mai mica, iar in caz de egalitate (pixeli pe aceeasi linie) se va alege cel care se afla pe coloana mai mica. Atentie! La fel ca si la Task-ul 1 prima linie este linia cea mai de sus din imagine (adica cea mai de jos din fisier) iar prima coloana este coloana cea mai la stanga in imagine.
Sa consideram urmatoarea imagine (si threshold = 10):
(10 10 10) (12 10 13) (10 10 10) (30 30 30) (30 29 31) (10 10 10) (12 15 10) (10 10 10) (30 28 30) (12 10 13) (11 11 11) (11 12 11) (10 10 10) (30 33 30) (12 11 13) (12 12 12) (12 10 12) (10 10 10) (30 30 31) (12 10 13)
Initial nici un pixel nu este inclus in vreo zona. Se alege pixelul din coltul stanga-sus de valoare (10 10 10) deoarece acesta se afla pe cea mai mica linie (si pe cea mai mica coloana). Se determina zona maximala din care acesta face parte:
(10 10 10) (12 10 13) (10 10 10) (30 30 30) (30 29 31) (10 10 10) (12 15 10) (10 10 10) (30 28 30) (12 10 13) (11 11 11) (11 12 11) (10 10 10) (30 33 30) (12 11 13) (12 12 12) (12 10 12) (10 10 10) (30 30 31) (12 10 13)
Alegem din nou un pixel care nu a fost inclus intr-o zona conform algoritmului de selectie. Acest pixel este cel de pe linia 1 si coloana 4 (indexarea incepe la 1) de valoare (30 30 30). Se determina zona maximala din care acesta face parte (colorata cu verde):
(10 10 10) (12 10 13) (10 10 10) (30 30 30) (30 29 31) (10 10 10) (12 15 10) (10 10 10) (30 28 30) (12 10 13) (11 11 11) (11 12 11) (10 10 10) (30 33 30) (12 11 13) (12 12 12) (12 10 12) (10 10 10) (30 30 31) (12 10 13)
Alegem din nou un pixel care nu a fost inclus intr-o zona conform algoritmului de selectie. Acest pixel este cel de pe linia 2 si coloana 5 (indexarea incepe la 1) de valoare (12 10 13). Se determina zona maximala din care acesta face parte (colorata cu albastru):
(10 10 10) (12 10 13) (10 10 10) (30 30 30) (30 29 31) (10 10 10) (12 15 10) (10 10 10) (30 28 30) (12 10 13) (11 11 11) (11 12 11) (10 10 10) (30 33 30) (12 11 13) (12 12 12) (12 10 12) (10 10 10) (30 30 31) (12 10 13)
Am determinat astfel 3 zone in imagine. Dupa ce se inlocuieste in fiecare zona culoarea pixelilor cu cea a pixelului initial (determinat la pasul 1) obtinem imaginea:
(10 10 10) (10 10 10) (10 10 10) (30 30 30) (30 30 30) (10 10 10) (10 10 10) (10 10 10) (30 30 30) (12 10 13) (10 10 10) (10 10 10) (10 10 10) (30 30 30) (12 10 13) (10 10 10) (10 10 10) (10 10 10) (30 30 30) (12 10 13)
Aceasta imagine nu o vom scrie intr-un fiser .bmp, ci intr-un fisier binar dupa urmatorul format:
1) Cele doua header-e din formatul BMP se scriu nemodificate;
2) Incepand de la valoarea byte-ul de offset din header (adica unde ar fi trebuit sa inceapa matricea de pixeli din fomatul BMP) se for scrie tupluri (nr_linie, nr_coloana, R, G, B) cu urmatoarea semnificatie:
In fisier se vor scrie doar pixelii care sunt la granita unei zone cu alta zona. Adica se vor scrie doar pixelii de pe marginea fiecarei zone. Ordinea in care acestia se vor scrie in fisier este crescator pe linii, iar in caz de egalitate crescator pe coloane.
Pentru exemplul de mai sus ceea ce se va scrie in fiserul binar dupa ce se scriu cele doua header-e BMP este:
(1, 1, 10, 10, 10) (1, 2, 10, 10, 10) (1, 3, 10, 10, 10) (1, 4, 30, 30, 30) (1, 5, 30, 30, 30) (2, 1, 10, 10, 10) (2, 3, 10, 10, 10) (2, 4, 30, 30, 30) (2, 5, 12, 10, 13) (3, 1, 10, 10, 10) (3, 3, 10, 10, 10) (3, 4, 30, 30, 30) (3, 5, 12, 10, 13) (4, 1, 10, 10, 10) (4, 2, 10, 10, 10) (4, 3, 10, 10, 10) (4, 4, 30, 30, 30) (4, 5, 12, 10, 13)
Aplicarea algoritmului de compresie se realizeaza pe imaginea al carei nume se gaseste pe primul rand in fisierul input.txt (cea pe care am lucrat si la primul task). Valoarea de prag (threshold) care se va utiliza in cadrul algoritmului se va citi de pe linia 2 din fisierul input.txt. Datele in format binar, rezultate in urma compresiei, se vor scrie in fisierul compressed.bin.
Se da un fisier binar in formatul celui de la Task-ul 3 (imagine comprimata). Sa se aplice algoritmul de decompresie. Numele fisierului din care cititi datele comprimate se gaseste in fisierul input.txt pe linia a treia. Imagina decomprimata se va scrie in format BMP in fisierul decompressed.bmp. Practic, trebuie sa delimitati zonele si sa atribuiti fiecarui pixel dintr-o zona culoarea marginii zonei (toata marginea va avea aceeasi culoare, deoarece asa am definit compresia in Task-ul 3). Daca o imagine este comprimata si apoi decomprimata, imaginea rezultata nu va fi egala cu imaginea initiala (loosy compression) ci va pierde din calitate. Pe de alta parte, un BMP de 6MBytes dupa compresie poate ocupa si 300KBytes (vezi fisierele din arhiva de testare).
Fisierul de intrare se numeste input.txt. Acesta are urmatoarea structura:
Exemplu:
image.bmp 25 arhive.bin
Ca output pentru exemplul de mai sus se vor scrie fisierele: image_black_white.bmp, image_f1.bmp, image_f2.bmp, image_f3.bmp, compressed.bin si decompressed.bmp.
Resursele pentru tema se pot descarca de aici. Sunt prezente: