Sunteți pe pagina 1din 8

Laborator 3.

Filtre de convoluție

Scopul exercițiului: cunoașterea filtrelor de convoluție și a ceea ce pot realiza acestea la prelucrarea imaginilor.

1. Filtrul de convoluție generală

Când să o folosiți? Atunci când ne proiectăm propria mască și dorim să o programăm.

De exemplu, luați în considerare următoarea mască 3x3:

Pentru a utiliza această mască pentru filtrarea prin convoluție, sunt necesare trei instrucțiuni:

1. În primul rând, introducem secvențial numerele din mască într-un vector float:

float numere[9] = {0.11, -0.08, 0.19, -0.13, 0.91, 0.31, -0.18, 0.02, -0.12};
2. În al doilea rând, creăm masca sub forma unei matrice OpenCV:

Mat masca = Mat(3, 3, CV_32FC1, numere);

Primele două argumente stabilesc dimensiunea matricei. Al treilea argument specifică tipul de matrice, care
în acest caz este pe 32 de biți, în virgulă mobilă și cu un singur canal.

3. Executăm filtrarea:

filter2D(imIn, imOut, -1, masca);

Să se execute următoarele:

1. Aplicați un filtru care deplasează imaginea cu un pixel într-o direcție. Încărcați o imagine și filtrați-o din nou
cu acest filtru. După fiecare filtrare, afișați imaginea într-o fereastră. Filtrați întotdeauna din nou imaginea
filtrată. Ar trebui să vedeți că imaginea se deplasează treptat în direcția dorită.
2. Construiți un filtru trece-jos cu o mască de 0,2 în mijloc și 8 valori de 0,1 în jurul acesteia. Încărcați o imagine
și filtrați-o din nou cu acest filtru. După fiecare filtrare, afișați imaginea într-o fereastră. Filtrați întotdeauna
din nou imaginea filtrată. Ar trebui să vedeți că imaginea devine ușor mai neclară cu fiecare filtrare.

3. Construiți un filtru de trecere superioară (filtru trece-sus) cu o mască de 1+k în mijloc, 4 -k/4 și 4 zerouri în
jurul ei. Încărcați o imagine și filtrați-o din nou cu acest filtru, folosind valori k crescătoare. După fiecare
filtrare, afișați imaginea într-o fereastră. Filtrați întotdeauna imaginea originală folosind noua mască. Ar
trebui să vedeți că imaginea devine din ce în ce mai clară, dar și cu mai mult zgomot.

1
2. Filtre Blur de tip Gaussian

Aceste filtre sunt utilizate pentru cazuri speciale de măști trece-jos. Ambele au o mască impară x impară cu originea
în mijloc. Masca Blur este distribuită uniform, astfel încât, de exemplu, o mască Blur de 7x5 are valori de 1/35.
Numerele dintr-o mască gaussiană urmează o distribuție în formă de clopot gaussian, astfel încât centrul are cea mai
mare valoare, iar cu cât o valoare este mai departe de origine, cu atât devine mai mică.

Aceste filtre pot fi utilizate print-o comandă:

blur(imIn, imOut, Size(k, k)); // k este impar


GaussianBlur(imIn, imOut, Size(k, k), 1); // k ≥ 3 impar

Primele două argumente sunt imaginea de intrare și de ieșire, al treilea argument stabilește dimensiunea măștii.

Ambele filtre estompează imaginea de intrare. Cu cât masca utilizată este mai mare, cu atât mai puternică este
estomparea. Pentru aceeași dimensiune a măștii, filtrul Blur estompează mai mult decât filtrul Gaussian.

Să se execute următoarele:

Încărcați o imagine și filtrați-o în mod repetat cu un filtru blur sau gaussian, folosind valori k crescătoare. După
fiecare filtrare, afișați imaginea într-o fereastră. Filtrați întotdeauna imaginea originală folosind noua mască. Ar
trebui să vedeți că, cu cât masca este mai mare, cu atât mai puternică este estomparea. Pentru aceeași dimensiune a
măștii, filtrul Blur va estompa mai mult decât filtrul Gaussian.

3. Filtrul median

Filtrul median nu este un filtru de convoluție, dar efectul său este similar cu cel al unui filtru trece-jos. OpenCV poate
fi utilizat după cum urmează:

medianBlur(imIn, imOut, marime);

Primele două argumente sunt imaginea de intrare și cea de ieșire, iar ultimul argument stabilește dimensiunea
vecinătății cu care va lucra filtrul. Vecinătatea este întotdeauna pătrată, iar dimensiunea este specificată ca un
număr impar. Cu cât dimensiunea este mai mare, cu atât mai puternic va fi efectul filtrului.

Să se execute următoarele:

4. Încărcați o imagine și trasați pe ea linii negre de diferite grosimi. Filtrați în mod repetat imaginea mâzgălită
cu un filtru median, folosind dimensiuni din ce în ce mai mari ale vecinătăților. După fiecare filtrare, afișați
imaginea într-o fereastră. Filtrați întotdeauna imaginea originală folosind noua dimensiune a vecinătății. Ar
trebui să vedeți că, cu cât vecinătatea este mai mare, cu atât zgomotul este mai gros, dar și mai neclar.
5. Desenați o imagine bicoloră: de exemplu, o amibă albă pe un fundal negru. Filtrați această imagine cu un
filtru median mare (de exemplu, 21x21) de sute de ori. După fiecare filtrare, afișați imaginea într-o fereastră.

2
Filtrați întotdeauna din nou imaginea filtrată. Ar trebui să vedeți că amoeba devine din ce în ce mai
regulată, iar când devine complet convexă, începe să se micșoreze rapid până când dispare.

------------------------------------------------------------------------------------------------------------------------------------------------

– Aceste exemple vor suferi modificari, sunt scrise în versiunea veche!!!

Rezolvări:
1. Problema 1 are trei rezolvări. Prima o folosește o funcție auxiliară pentru copierea unei imagini RGB,
considerând că fiecare pixel o ocupă 24 biți (3 octeți). Versiunea a doua o execută doi pași într-un ciclu, dar
nu o folosește copierea imaginii, deci poate fi folosită pentru orice fel de imagine (soluție mai generală).
Versiunea a treia este cea preferabilă, deoarece copierea imaginii se execută prin utilizarea unei metode
standard.

void copyImg(Mat imSrc, Mat imDest)


{
unsigned char* pData = imSrc.data;

int width = imSrc.rows;


int height = imSrc.cols;

//data copy using memcpy function


memcpy(imDest.data, pData, 3 * sizeof(unsigned char) * width * height);
}

void lab03_1()
{
Mat imIn = imread("Imaginea_aleasa.jpg", 1);

if (imIn.empty())
{
printf(" Error opening image\n");
return;
}

Mat imOut;

const char* window_name = "Translatie";


cv::namedWindow(window_name);
imshow(window_name, imIn);

waitKey(0);

float numere[9] = { 0,0,1,0,0,0,0,0,0 };


Mat masca = Mat(3, 3, CV_32FC1, numere);

for (int q = 0; q < 100; ++q)


3
{
filter2D(imIn, imOut, -1, masca);
imshow(window_name, imOut);
copyImg(imOut, imIn);
waitKey(50);
}

waitKey(0);
}

void lab03_1a()
{
Mat imIn = imread("Imaginea_aleasa.jpg", 1);

if (imIn.empty())
{
printf(" Error opening image\n");
return;
}

Mat imOut;

const char* window_name = "Translatie";


cv::namedWindow(window_name);
imshow(window_name, imIn);

waitKey(0);

float numere[9] = { 0,0,1,0,0,0,0,0,0 };


Mat masca = Mat(3, 3, CV_32FC1, numere);

for (int q = 0; q < 50; ++q)


{
filter2D(imIn, imOut, -1, masca);
imshow(window_name, imOut);
waitKey(50);

filter2D(imOut, imIn, -1, masca);


imshow(window_name, imIn);
waitKey(50);
}

waitKey(0);
}

void lab03_1b()
{
Mat imIn = imread("Imaginea_aleasa.jpg", 1);

if (imIn.empty())
{

4
printf(" Error opening image\n");
return;
}

Mat imOut;

const char* window_name = "Translatie";


cv::namedWindow(window_name);
imshow(window_name, imIn);

waitKey(0);

float numere[9] = { 0,0,1,0,0,0,0,0,0 };


Mat masca = Mat(3, 3, CV_32FC1, numere);

for (int q = 0; q < 100; ++q)


{
filter2D(imIn, imOut, -1, masca);
imshow(window_name, imOut);

imIn = imOut.clone();

waitKey(50);
}

waitKey(0);
}

Original După 10 iterații După 100 iterații

-----------------------------------------------------------------------------
-- programele următoare nu funcționează, vor fi modificate pentru OpenCV 4.7

void lab03_2()
{
IplImage* imIn = cvLoadImage("Imaginea_aleasa.jpg", 1);
cvNamedWindow("Trece jos", CV_WINDOW_AUTOSIZE);
cvShowImage("Trece jos", imIn);
cvWaitKey(0);

float numere[9] = { 0.1,0.1,0.1,0.1,0.2,0.1,0.1,0.1,0.1 };


CvMat masca = cvMat(3, 3, CV_32FC1, &numere);

5
for (int q = 0; q < 20; ++q)
{
cvFilter2D(imIn, imIn, &masca);
cvShowImage("Trece jos", imIn);
cvWaitKey(50);
}
}

Filtru trece jos aplicat o dată 2x 3x

6x 10x 20x

void lab02_3()
{
IplImage* imIn = cvLoadImage("Imaginea_aleasa.jpg", 1);
IplImage* imOut = cvCloneImage(imIn);

for (float k = 0.0f; k <= 3.0f; k+=0.1f)


{
float numere[9] = { 0, -k/4.0f, 0, -k / 4.0f, 1.0f+k, -k / 4.0f, 0, -k / 4.0f, 0 };
CvMat masca = cvMat(3, 3, CV_32FC1, &numere);
cvFilter2D(imIn, imOut, &masca);
cvShowImage("Trece sus", imOut);
cvWaitKey(0);
}
}

k=0.5 k=1.5 k=3.0

Observație: la anumite imagini k=2 poate să amplifice zgomotul la un nivel deranjant


6
void lab02_4()
{
IplImage* imIn = cvLoadImage("Imaginea_aleasa.jpg", 1);
IplImage* imOut = cvCloneImage(imIn);

// Pe imaginea de intrare să desenăm niște linii pentru testare


for (int ori = 0; ori < 20; ++ori)
cvLine(imIn, cvPoint(rand()%imIn->width, rand()%imIn->height),
cvPoint(rand()%imIn->width, rand()%imIn->height), cvScalar(0,0,0,0), 1+ori% 1);

for (int k = 1; k <= 15; k += 2)


{
cvSmooth(imIn, imOut, CV_MEDIAN, k);
cvShowImage("Median", imOut);
cvSaveImage("median.png", imOut);
cvWaitKey(0);
}
}

Imaginea mâzgâlită filtrare 3x3 median 5x5

7x7 9x9 11x11

void lab02_5()
{
IplImage* imIn = cvLoadImage("amoba.png", 1);
cvNamedWindow("Amoba", CV_WINDOW_AUTOSIZE);
cvShowImage("Amoba", imIn);
cvWaitKey(0);

for (int q = 0; q < 1000; ++q)


{
cvSmooth(imIn, imIn, CV_MEDIAN, 21);
cvShowImage("Amoba", imIn);
cvWaitKey(50);
}
cvWaitKey(0);
}

7
Amoba originală După 10 filtrări de tip median După 30 filtrări de tip median

După 50 filtrări de tip median După 100 filtrări de tip median După 666 filtrări de tip median

S-ar putea să vă placă și