Table of Contents

Tema 3. Image processing

Atentie! deadline-ul soft coincide cu cel hard! Prin urmare, nu se vor mai accepta submisii dupa data de 26.01.2020!

Actualizări:

Scopul temei:

Introducere

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.

Urmatiti cu foarte mare atentie exemplul de aici si incercati sa intelegeti cum e reprezentata o imagine BMP inainte de a incepe implementarea. Daca e ceva neclar, puteti intreba oricand pe forum.

Puteti folosi utilitare precum xxd sau hexdump pentru a putea vizualiza continutul unui fisier binar (in cazul nostru, a unei imagini bmp). Vedeti si raspunsurile de aici .

Luați în considerare cum veți stoca în memorie matricea imaginii!

Cerinte

Veti avea de rezolvat 5 task-uri obligatorii si un task bonus.

Exemple de imagini in format bmp si de input-uri pentru task-uri gasiti in directorul input din checker.

Cand scrieti imagini in format BMP, intre ultimul byte din header si byte-ul la care incepe matricea de pixeli (adica pana la byte-ul de offset) trebuie sa scrieti peste tot byte-ul 0.

Task 0 - Interactive Console

Se va implementa un parser al liniei de comandă pentru a putea lucra interactiv cu transformările descrise în cerințele de mai jos și pentru a putea vedea la fiecare pas output-ul rezultat. Programul scris va citi în continuu de la standard input și va putea primi următoarele comenzi.

Se garantează faptul că atât operațiile cât și parametrii trimiși la input sunt corecte.

Task 1 - Basic Commands

Pentru acest task vom implementa primele doua operatii de baza necesare unui editor de imagini:

Daca operatia e de salvare atunci fisierul in care se va salva imaginea va avea numele si extensia: <name>.bmp

Exemplu:

Input: edit poza1.bmp

Input: save ./output/poza_editata.bmp

Va crea fisierul poza_editata.bmp in folderul output(existent).

output

├── poza_editata.bmp

Pentru lucrul cu structurile de date cititi mai multe detalii aici.

Pentru a lucra cu fisiere veti folosi urmatoarele metode:

fopen, fwrite, fread, fclose

Veti deschide fisierele bmp cu ajutorul functiei fopen utilizand modul de access “rb”. Pentru fisierul de output veti utiliza modul de access “wb”.

fwrite si fread au antetul functiei similare.

size_t fread(void *restrict ptr, size_t size, size_t nmemb, FILE *restrict stream);

size_t fwrite(const void *restrict ptr, size_t size, size_t nmemb, FILE *restrict stream);

Ambele functii intorc numarul de elemente citite, respectiv scrise.

  • Primul parametru reprezinta buffer-ul unde se vor pune elementele citite/se vor lua elementele pentru a fi scrise in fisier.
  • Al doilea parametru reprezinta dimensiunea elementului citit din fisier. Daca vrem sa citim din fisier un unsigned int atunci functia de fread va fi apelata in felul urmator fread(&x, sizeof(unsigned int), 1, fr).
  • Al treilea parametru reprezinta numarul de elemente citite/scrise.
  • Al patrulea parametru reprezinta fisierul.

Inainte sa inchideti programul asigurati-va ca ati inchis toate fisierele deschise cu fopen! Pentru a inchide un fisier deschis folositi fclose unde pasati pointer-ul structurii FILE deschise.

Task 2 - Overlap Images

Pentru acest task vom implementa următoarele doua operații:

y si x sunt doua unsgined int care pot avea valori intre 0 si UINT_MAX

Ele reprezinta coordonatele punctului stanga-jos, in matricea imaginii din edit mode, de la care se va introduce noua imagine.

Atentie la notarea coordonatelor

dim 1024 × 768

  • 1024 de pixeli pe fiecare linie
  • 768 de linii

In cazul y si x - coordonata y reprezinta pozitia de pe linia si x linia din matrice.

Task 3 - Draw Lines

Pentru acest task vom implementa următoarele cinci operații:

R G B au valori intre 0 și 255, valoarea default este 0 0 0

x are valori impare intre 1 si 255, valoarea default este 1

La desenarea cu un line_width diferit de 1, pixelul principal va fi incadrat intr-un patrat de latura x

Exemplu:

Pentru line_width = 3, pixelul principal este cel de culoare verde. La desenare, atat pixelul principal, cat si pixelii ce formeaza patratul(si interiorul lui) vor primi culoarea setata.

Pentru trasarea liniilor ce unesc doua puncte ce nu sunt paralele cu Ox sau Oy, se va folosi o functie de gradul I cu formula

(y - yA) / (yB - yA) = (x - xA) / (xB - xA).

Se stabileste pe ce axa se afla intervalul maxim (x max - x min) sau (y max - y min).

Se va parcurge de la minim la maxim intervalul de lungime maxima [x min, x max] sau [y min, y max] si pe baza formulei calculate PE INTREGI se afla a doua coordonata a punctului desenat.

Exemplu:

Pentru punctele (1, 1) si (2, 5), intervalul mai mare este cel de pe axa Oy.

Deci formula prin care vom afla x-ul corespunzator fiecarui y din intervalul [1, 5] este x = (y + 3) / 4.

y = 1 → x = 1

y = 2 → x = 1

y = 3 → x = 1

y = 4 → x = 1

y = 5 → x = 2

Pentru a evita erorile de rotunjire, punctele initiale primite ca parametru se vor desena indiferent de rezultatul functiei.

Daca intervalele sunt egale, atunci dreapta rezultata este de forma f(x) = x + C sau f(x) = -x + C, unde nu conteaza modul in care va fi desenata linia.

Task 4 - Fill color

Pentru acest task vom implementa operația finală:

În urma operației, pixelul de la pozitia (y, x) va fi suprascris cu pixeli setati prin comanda set draw_color R G B. Operația va fi repetată recursiv pentru toți vecinii acestuia (stânga, dreapta, sus, jos) care aveau aceeași culoare cu pixelul original din (y, x).

Dacă pixelul original avea tot culoarea (r, g, b), operația nu produce nici un efect.

Exemplu

Imaginea Originală:

(0, 0, 255) (10, 10, 10) (255, 0, 0)    (10, 10, 10)
(10, 10, 10) (0, 255, 0) (10, 10, 10)  (10, 10, 10)
(10, 10, 10) (10, 10, 10) (10, 10, 10) (10, 15, 10)

Instrucțiunea:

set draw_color 42 42 42
fill_color 1 2

În urma aplicării operației, toți vecinii accesibili din poziția (1, 2), având culoarea (10, 10, 10), au fost suprascriși cu un pixel de valoarea (42, 42, 42). Pixelul de pe poziția (0, 1) a rămas neschimbat.

Imaginea Obținută:

(0, 0, 255)  (10, 10, 10)  (255, 0, 0)  (42, 42, 42)
(42, 42, 42) (0, 255, 0)  (42, 42, 42) (42, 42, 42)
(42, 42, 42) (42, 42, 42) (42, 42, 42) (10, 15, 10)

Task 5 - Clean Valgrind BONUS (20p)

Intrucat unul din scopurile principale ale acestei teme este alocarea dinamica a memoriei, pentru a rezolva acest task trebuie sa nu aveti nicio eroare sau leak de memorie la rularea utilitarului valgrind pe aceasta.

Utilitarul se va rula folosind urmatoarea comanda:

 valgrind --tool=memcheck --leak-check=full --error-exitcode=1 ./bmp < input_file 

Atentie! Numele executabilului rezultat in urma comenzii

 make build 

trebuie sa fie neaparat bmp!

Atentie! Pentru a putea primi punctaj pe acest task trebuie sa aveti punctaj maxim pe restul cerintelor!

Resurse si checker-ul local

Resursele pentru tema se pot descarca:

Trimitere tema

Tema va fi trimisa folosind vmchecker, cursul Programarea Calculatoarelor, tema image_processing.

Punctajul:

Restrictii si precizari

Temele care nu folosesc alocare dinamica vor avea o depunctare de pana la 50 de puncte din punctajul temei, in functie de gravitate! De asemenea, nu va fi acordat punctajul pe bonus in acest caz!

Listă depunctări

Lista nu este exhaustivă. Se pot aplica chiar depunctări mai mari în cazuri excepționale.