Limbaje de programare: Laborator 6

Reprezentare internă. Operatori pe biți

La intrarea în laborator trebuie predată tema 6.

Operații pe biți: prelucrare de imagini

În acest laborator vom aplica operatorii pe biți pentru a efectua prelucrări simple, pixel cu pixel pe imagini în format bitmap.

Reprezentarea imaginii Folosim pentru simplitate imagini în format bitmap (.bmp) care reprezintă independent culoarea fiecărui pixel din imagine. Varietatea paletei de culori e dată de numărul de biți utilizați. Vom lucra cu imagini care folosesc 24 de biți pe pixel. Culorile sunt codificate în format RGB: câte un octet (8 biți) pentru fiecare din cele trei culori de bază, în ordinea: albastru, verde, roșu. Valoarea 0xFF (255) reprezintă intensitate maximă, iar valoarea 0 intensitate zero. Toate trei componentele la maxim dau ca rezultat alb; toate trei valorile zero înseamnă negru. Valoarea 0xFF pentru R și zero pentru celelalte reprezintă roșu aprins; valoarea 0xFF pentru roșu și verde, împreună cu 0 pentru albastru dă galben, etc.

Structura unui fișier imagine Un fișier cu o imagine bitmap conține întâi un antet cu informații despre imagine (dimensiune, metodă de codificare, paletă de culori, etc.). Pentru formatul bitmap cu care lucrăm, antetul are 54 de octeți. După antet urmează imaginea propriu-zisă, reprezentată în acest caz cu câte 3 octeți pe pixel.
Folosiți oricare din fișierele .bmp color din acest set de imagini de test.

Citirea și scrierea imaginilor Pentru simplitate, programele pe care le scriem vor citi și scrie fișierele de la intrarea standard respectiv la ieșirea standard. Aceasta ne va permite să scriem în continuare programele cu funcțiile simple și cunoscute getchar și putchar, care citesc, respectiv scriu câte un octet (un caracter) de la intrarea / la ieșirea standard. Numele fișierelor imagine cu care lucrăm le indicăm din linia de comandă:
./programexecutabil < intrare.bmp > iesire.bmp

Structura programului Întrucât nu vom modifica dimensiunile imaginii, antetul va fi copiat neschimbat în imaginea de ieșire. Programul nostru va avea deci structura:

// copiaza 54 de caractere(octeti) cu getchar/putchar de la intrare la iesire
// cat timp nu s-a terminat intrarea
  // citeste cate un octet (sau cate trei pentru un pixel)
  // modifica octetul conform prelucrarii dorite
  // scrie octetul la iesire
O prelucrare simplă Pentru început, vom vedea ce efect are modificarea componentelor de culoare din imagine. Să presupunem că un pixel are componenta de roșu cu valoarea 173 (cca 2/3 din intensitate între 0 și 255). În binar, 173 e 10101101, sau 0xAD în hexazecimal. Să presupunem acum că punem pe zero cei 4 biți mai puțin semnificativi, și valoarea devine 10100000, adică 0xA0 sau 160, și aplicăm aceeași prelucrare tuturor pixelilor, pentru toate cele 3 culori. Aceasta are două efecte observabile: imaginea devine mai întunecată pe ansamblu (intensitatea fiecărei componente fiind mai mică). În plus, calitatea imaginii scade, apar pete de culoare mai uniformă, deoarece toți pixelii care aveau înainte valori în intervalul [16*n, 16*n+15] (de exemplu [160, 175]) vor avea acum valori egale (160).

De implementat (partea 1) Codificați în program prelucrarea indicată (resetând cei mai puțini semnificativi 4 biți din fiecare componentă de culoare), și observați efectul. Variați apoi numărul de biți afectați (5, 3, 2, ...). Implementați varianta în care setați biții respectivi pe 1. Efectul de pete de culoare va fi același, dar imaginea va deveni mai luminoasă.

De implementat (partea 2) Puteți efectua și alte prelucrări care nu țin de codificare: să inversați intensitatea culorilor din imagine (negativ), să o transformați în nuanțe de gri (folosind uniform media aritmetică a celor trei componente), să modificați luminozitatea, să obțineți diverse efecte de culoare, etc.

Observație Veți observa că dacă nu modificați decât bitul cel mai puțin semnificativ (sau ultimii doi), efectele sunt practic nedetectabile cu ochiul liber. Astfel se pot încorpora în imagine date ascunse fără ca altcineva să suspecteze acest lucru, procedeu numit steganografie.

Alte probleme cu operatori pe biți

  1. Scrieți o funcție care ia ca parametru un întreg fără semn și returnează cea mai semnificativă poziție pe care se afla un bit de 1.
    Rezolvați aceeași problemă pentru poziția cea mai puțin semnificativă.
    Exemplu: 10 = 1010(2). Cel mai semnificativ bit de 1 e pe poziția 3; cel mai puțin semnificativ e pe poziția 1.
  2. Scrieți o funcție care ia ca parametru un întreg fără semn și îl scrie în baza 8, folosind operatori pe biți.
    Indicație: O cifră în baza 8 ocupă 3 biți. Restul la împărțirea cu 8 se obține prin ȘI cu numărul format din 3 biți de 1, adică 7. Câtul la împărțirea cu 8 se obține prin deplasare la dreapta cu 3 biți.
  3. Scrieți o funcție care ia ca parametri doi întregi fără semn și calculează suma lor, făcând adunarea bit cu bit, cu propagarea transportului.
  4. Scrieți o funcție care ia ca parametru un întreg fără semnși returnează numărul cu aceiași biți în ordine inversă.

Marius Minea
Last modified: Tue Oct 30 12:30:00 EET 2012