Sunteți pe pagina 1din 41

Cuprins

1 Introducere 3
1.1 Structura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2 Tipuri de date specifice . . . . . . . . . . . . . . . . . . . . . 5
1.2.1 Matrice . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2.2 Reprezentarea imaginilor . . . . . . . . . . . . . . . . 8
1.3 Manipularea imaginilor . . . . . . . . . . . . . . . . . . . . . 9
1.3.1 Interfaţa grafică . . . . . . . . . . . . . . . . . . . . . 12

2 Prelucrarea imaginilor 15
2.1 Filtare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.1.1 Netezire . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.1.2 Extragerea contururilor . . . . . . . . . . . . . . . . . 17
2.2 Morfologie matematica . . . . . . . . . . . . . . . . . . . . . . 19
2.2.1 Morfologie matematica in OpenCV . . . . . . . . . . . 19
2.3 Transformări geometrice . . . . . . . . . . . . . . . . . . . . . 22
2.4 Histograma . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

3 Analiza imaginilor 33
3.1 Segmentare . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
3.1.1 Segmentarea cu prag . . . . . . . . . . . . . . . . . . . 33
3.1.2 Creşterea regiunilor . . . . . . . . . . . . . . . . . . . 38
3.1.3 Segmentare piramidală . . . . . . . . . . . . . . . . . . 38
3.1.4 Algoritmul Watershed . . . . . . . . . . . . . . . . . . 40

1
2 CUPRINS
Capitolul 1

Introducere

OpenCV “Open Source Computer Vision Library” este o bibliotecă de funcţii


open source, scrisă ı̂n C şi C++. Librăria a fost proiectată astfel ı̂ncât să
ofere eficienţă computaţională pentru aplicaţii de computer vision ı̂n timp
real. Biblioteca OpenCV conţine peste 500 de funcţii care acoperă domenii
precum imagistica medicală, securitatea, calibrarea camerelor fotografice,
vedere stereo sau robotică. Suplimentar OpenCV conţine o un set complet
de funcţii de machine learning (MLL).
Scopul librariei este de a pune la dispozitie potenţialilor utilizatori o
infrastructură de procesare a imaginilor uşor de folosit ce poate fi utilizată
ı̂n dezvoltarea rapidă a unor aplicaţii complexe. Ea este orferită gratuit
utilizatorilor şi este “open source” sub o licenţă BSD.
Lansat oficial ı̂n 1999, proiectul OpenCV a fost la ı̂nceputuri o iniţiativă
a cercetătorilor de la Intel pentru aplicaţii care folosesc intensiv proceso-
rul. Din proiectul iniţial făceau parte aspecte legate de urmărirea razelor de
lumină şi desenarea 3D a pereţilor. Principalii contributori la dezvoltarea
proiectului au fost programatorii de la Intel şi o parte din experţii ı̂n proce-
sare şi analiza imaginilor de la Intel Rusia. În faza de ı̂nceput a proiectului,
obiectivele principale impuse au fost:
• O cercetare amanunţită ı̂n domeniul prelucrării imaginilor oferind nu
numai codul funcţional, dar şi un cod optimizat pentru o platformă
fundamentală ı̂n domeniul prelucrării informaţiei vizuale.
• Standardizarea cunoştinţelor de programare ı̂n domeniul prelucrării
imaginilor ăstfel ı̂ncât să se ofere programatorilor o platformă uşor de
folosit şi transferabilă.
• Suport pentru aplicaţii comerciale avansate ı̂n prelucrarea imaginilor
astfel ı̂ncât să fie portabile şi optimizate
Prima versiune, alpha de OpenCV a fost lansată ı̂n cadrul conferinţei
“IEEE Conference on Computer Vision and Pattern Recognition” din 2000,
iar 5 versiuni beta au fost lansate ı̂ntre 2001 şi 2005. Prima versiune 1.0
a fost lansată ı̂n 2006. La mijlocul anului 2008, OpenCV a obţinut suport
din partea corporaţiei Willow Garage şi este acum din nou sub dezvoltare.
Versiunea 1.1 “pre-release” a fost lansată ı̂n octombrie 2008, iar o carte a
fost scoasă de editura OReilly Media pe piaţa ı̂n aceeaşi lună [3].

3
4 CAPITOLUL 1. INTRODUCERE

Figura 1.1: Structura librăriei OpenCV.

A doua versiune a fost scoasă pe piaţă ı̂n octombrie 2009. OpenCV 2


include schimbări majore ı̂n interfaţa C++, oferind noi funcţii, o implemen-
tare mai bună a funcţilor existente, ı̂n special pentru sisteme multi-core.
Acum OpenCV este disponibil ı̂n mod gratuit la adresa de Internet
http://opencvlibrary.SourceForge.net. OpenCV poate rula pe Linux, Win-
dows şi Mac OS X, având interfeţe pentru Python, Matlab, Ruby şi altele
[1].
În această parte a lucrării de faţă vom inspecta principalele aspecte de
funcţionalitate pe care le oferă biblioteca OpenCV. Această lucrare ı̂si pro-
pune, cel mult să fie un mic ghid introductiv, nicidecum să ofere o privire
detaliată asupra bibliotecii. Pentru cine vrea să ı̂nţeleagă ı̂n profunzime
funcţionalitatea bibliotecii, ı̂i recomandăm să utilizeze atât manualul oficial
[3], lămuririle on-line [1], cât şi nenumăratele tutoriale şi explicaţii disponi-
bile pe Internet, mai ales că din aceste surse a fost inspirat şi materialul de
faţă.
O altă precizare necesară este că aici vom discuta despre varianta de
OpenCv pentru C. Suplimentar există suport pentr C++ (bazat pe clase şi
mult mai apropiat de pachetul de image processing din Matlab) respectiv
pentru Python.

1.1 Structura
OpenCV conţine peste 500 de funcţii pentru numeroase domenii ce folosesc
Computer VisionOpenCV şi este structurată ı̂n 5 componente principale
(cum este parţial prezentat şi ı̂n figura 1.1):

1. CV: conţine algoritmi de bază pentru prelucrarea imaginilor;

2. MLL: reprezintă libraria pentru “machine learning” şi conţine nu-


meroşi clasificatori statistici şi functii pentru clustering;

3. HighGUI: conţine rutinele de I/O precum şi funcţiile pentru ı̂ncărcarea


şi stocarea imaginilor şi filmelor;

4. CXCore: conţine tipurile de date de bază;


1.2. TIPURI DE DATE SPECIFICE 5

5. CVAux: conţine algoritmi experimentali (segmentare fundal/prim-


plan, algoritmi de recunoaştere, algoritmi de tracking, modele Markov
ascunse 1D şi 2D, descriptori de textură).

1.2 Tipuri de date specifice


OpenCV conţine suport pentru câteva tipuri primitive de date, primitive nu
din punctul de vedere al limbajului C, ci pentru că sunt structuri simple şi
pot fi privite ca date atomice. Acestea pot fi examinate ı̂n fişierul cxtypes.h
Cel mai simplu tip este CvPoint. CvPoint-ul este o structură simplă cu
doi membrii ı̂ntregi: x şi y. Tipuri similare sunt CvPoint2D32f care are 2
membrii x, y ı̂n virgulă mobilă, iar CvPoint3D32f ce are 3 membrii x, y,
z de tipul float.
Un alt tip de date, CvSize se aseamănă cu CvPoint, având doi membrii
width şi height. Pentru varianta ı̂n virgulă mobilă există tipul CvSize2D32f.
CvRect se aseamănă cu cele 2 tipuri de mai sus (CvPoint şi CvSize) sı̂
are patru membrii: x, y, width şi height.
CvScalar este un set de patru numere de precizie dublă. Atunci când nu
există limitări de memorie, tipul CvScalar este folosit destul de des pentru
reprezentarea numerelor reale. CvScalar are un singur membru val, care
este un pointer către vectorul ce conţine cele patru numere de dublă-precizie
ı̂n virgulă mobilă.
Toate aceste tipuri au metode constructor cu acelaşi nume ca al tipului.
De exemplu tipul CvSize are constructorul cvSize(). Ţinând cont de faptul
că aceste metode sunt scrise ı̂n limbajul C, ele sunt pur şi simplu funcţii inline
care au o listă de argumente şi returnează structura dorită cu valorile setate
corespunzător.
Constructorii inline pentru aceste tipuri de date cvPoint(), cvSize(),
cvRect() şi cvScalar() sunt foarte utili pentru că fac codul uşor de scris
şi uşor de citit; de exemplu pentru desenarea unui dreptunghi este suficient
apelul de mai jos:
cvRectangle(
out,
cvPoint(145,45),
cvPoint(207,85),
cvScalar(255,255,255)
);

1.2.1 Matrice
Pentru reprezentare matricelor se foloseşte tipul CvMat. Cu toate că OpenCV
este implementat complet ı̂n limbajul C, ı̂ntre structurile CvMat şi IplImage
există o relaţie ce se aseamănă foarte mult cu moştenirea din C++ (IplImage
este “derivată” din CvMat) (a se vedea figura 1.2). Clasa CvArr este o clasă
abstract din care este derivată la rândul ei CvMat.
În OpenCV pentru noţiunea de vector se poate folosi o matrice cu o
singură coloană.
6 CAPITOLUL 1. INTRODUCERE

Figura 1.2: Legătura ı̂ntre tipurile matrice din OpenCV.

Un element al matricei CvMat poate reprezenta unul sau mai multe nu-
mere, permiţând reprezentarea culorii pe cele trei canale (RGB). Struc-
tura CvMat este relativ simplă, are o lăţime, o ı̂nălţime, un tip (lungimea
rândului ı̂n bytes) şi un pointer către matricea de date. Elementele se pot
accesa direct printr-un pointer referinţă către CvMat sau prin funcţiile de
acces furnizate. De exemplu, pentru obţinerea dimensiunii unei matrice, se
poate apela cvGetSize(CvMat*), care returnează o structură CvSize, sau
se poate accesa independent lăţimea şi ı̂nălţimea, astfel matrix->height şi
matrix->width.
Matricile pot fii create ı̂n mai multe feluri. O primă variantă este
apelând funcţia cvCreateMat(); alte este apelând cvCreateMatHeader()
(care crează structura fără să-i aloce memorie) ı̂mpreună cu cvCreateData()
(care alocă memorie datelor), fie apelând cvCloneMat(CvMat*), care crează
o nouă matrice dintr-una deja existentă. În cazul ultimei, dealocarea se face
cu cvReleaseMat(CvMat**). Există un constructor cvMat() care crează o
structură CvMat. Dar el nu alocă memorie, ci doar crează header-ul, precum
cvInitMatHeader(). Acesta este folositor ı̂n cazul ı̂n care datele există deja
şi se doreşte ı̂mpachetarea lor ı̂ntr-o strutură.
De exemplu, pentru crearea unei matrici bidimensionale se apelează
cvCreateMat:
cvMat* cvCreateMat(int rows, int cols, int type)
unde type este orice tip predefinit (CV adâncime-bit(S|U|F)Cnumăr de
canale); de exemplu CV 32 FC1 este o matrice care conţine date de tipul 32
bit float.
Pentru interogarea matricilor avem următoarele operaţii:

• cvGetElemType( const CvArr* arr ) - returnează o constantă ı̂ntreagă


reprezentând tipul elementelor stocate ı̂n matrice. Aceasta poate fi de
forma CV 8UC1, CV 64FC4, etc.

• cvGetDims( const CvArr* arr, int* sizes=NULL ) - primeşte o ma-


trice şi un pointer către un ı̂ntreg şi returnează numărul dimensiunii:
2 ı̂n cazul matricelor bidimensionale.

• cvGetDimSize( const CvArr* arr, int index ) - dacă pointerul


ı̂ntreg nu este nul, atunci va stoca ı̂nălţimea şi lungimea matricei.
În cazul matricelor bidimensionale dim(0) = lăţimea, iar dim(1) =
ı̂nălţimea.
1.2. TIPURI DE DATE SPECIFICE 7

Cel mai simplu mod pentru accesarea unui element dintr-o matrice este
cu macro-ul CV MAT ELEM(). Acesta primeşte matricea, tipul elementului
dorit, numărul liniei şi al coloanei. De exemplu:
CvMat* mat = cvCreateMat(4, 4, CV 32FC1);
float element 3 2 = CV MAT ELEM(*mat, float, 3, 2);
Pentru scrierea unui element la o poziţie dată se foloseşte macro-ul
CV MAT ELEM PTR(). De exemplu:
CvMat* mat = cvCreateMat(4, 4, CV 32FC1);
float element 3 2 = 3.3;
*( (float*)CV MAT ELEM PTR(*mat, 3, 2) ) = element 3 2;
Din păcate aceste macro-uri recalculează pointer-ul la fiecare apel, drept
care nu reprezintă cea mai bună metodă de accesare a matricei, fiind utile
doar ı̂n cazul 1D şi 2D). În cazul matricilor N dimensionale, OpenCV-ul fur-
nizează funcţii de tipul cvPtr*D şi cvGet*D. (* este, de fapt, dimensiunea
N). Pentru N ı̂ntre 1D şi 3D, funcţiile au ca argument pointerul CvArr*,
urmat de numerele corespunzătoare indicilor şi un argument opţional care
indică tipul parametrului la ieşire. Funcţiile returnează un pointer al ele-
mentului dorit. În cazul N-dimensional, al doilea argument este un pointer
la matricea care conţine numerele corespunzătoare indicilor.
În cazul unei imagini RGB (cu 3 canale) reprezentată de o matrice bi-
dimensională: datele sunt stocate ı̂ntreţesut: RGBRGBRGB.... De aceea
pentru mutarea pointer-ului la următorul canal se adaugă pur şi simplu 1.
Dacă se doreşte mutarea către următorul pixel se adaugă un ofset egal cu
numărul canalelor, ı̂n cazul nostru 3. Pasul de parcurgere al elementelor
matricei este lungimea ı̂n bytes a unei linii, drept care nu sunt suficienţi
parametrii col şi width pentru deplasarea ı̂ntre liniile matricei. În cazul
unei matrice de ı̂ntregi pasul către următoare linie se face adăugând step/4,
ı̂n cazul tipului double se adaugă step/8 (se ţine cont că C va ı̂nmulţi auto-
mat offsetul pe care-l adăugăm cu dimensiunea tipului ı̂n bytes). Funcţiile
cvSet*D şi cvSetReal*D setează elementul unei matrice sau al unei imagini
dintr-un singur apel.
Prototipurile funcţii set element pentru CvMat (şi, aşa cum vom vedea
IplImage):
void cvSetReal1D( CvArr* arr, int idx0, double val );
void cvSetReal2D(
CvArr* arr,
int idx0,
int idx1,
double val );
void cvSetReal3D( CvArr* arr,
int idx0,
int idx1,
int idx2,
double val);
void cvSetRealND( CvArr* arr, int* idx, double val );
void cvSet2D(CvArr* arr, int idx0, int idx1, CvScalar val);
8 CAPITOLUL 1. INTRODUCERE

void cvSet3D( CvArr* arr,


int idx0,
int idx1,
int idx2,
CvScalar val);
void cvSetND(CvArr* arr, int* idx, CvScalar value);
Pentru matricile cu un singur canal de numere ı̂n virgulă mobilă, se
folosesc funcţiile cvmSet() şi cvmGet().
double cvmGet( const CvMat* mat, int row, int col );
void cvmSet( CvMat* mat, int row, int col, double value );
Pentru accesul direct al unui anumit element din matrice, trebuie să se
ţină cont că datele sunt stocate secvenţial ı̂ntr-o ordine de scanare.

1.2.2 Reprezentarea imaginilor


Fiind dedicată imaginilor, OpenCV oferă utilităţi pentru citirea diverselor
tipuri de imagini. Aceste utilităţi fac parte din toolkit-ul numit HighGUI.
Pentru manipularea imaginilor este definită o structură dedicată, numita
IplImage. Aceasta conţine următoarele câmpuri:

• nSize reprezintă dimensiunea ı̂n bytes a structurii;

• ID versiunea headerului imaginii;

• nChannels reprezintă numărul canalelor folosite (maxim 4)

• alphaChannel este ignorat de openCV

• depth reprezintă numărul de biţi utilizaţi pentru reprezentarea valo-


rilor pixelilor, precum şi tipul valorilor pixelilor.

• colorModel este ignorat de openCV.

• channelSeq este ignorat de openCV.

• dataOrder specifică modul de reprezentare al imaginilor (planar/ı̂ntreţesut).

• origin specifică coordonatale originii imaginii (colt stănga sus/colt


stânga jos).

• align este ignorat de openCV.

• width reprezintă numărul de coloane ale imaginii.

• height reprezintă numărul de linii ale imaginii.

• roi reprezintă un pointer care specifică ce regiune din imagine se do-


reste a fii prelucrată. Dacă pointerul este NULL atunci procesarea se
va aplica ı̂ntregii imagini.

• maskROI trebuie să fie NULL in openCV.

• imageID trebuie să fie NULL in openCV.


1.3. MANIPULAREA IMAGINILOR 9

• tileInfo trebuie să fie NULL in openCV.

• imageSize reprezintă dimensiunea imaginii ı̂n bytes.

• imageData reprezintă pointerul către imaginea utilă (vectorizată).

• widthStep reprezintă dimensiunea ı̂n bytes a unei linii din imagine.

• BorderMode este ignorat de openCV.

• BorderConst este ignorat de openCV.

• imageDataOrigin reprezintă un pointer către originea imaginii. Acest


pointer este utilizat ı̂n procesul de eliberare a spaţiului de memorie
ocupat de imaginea curentă.
Adâncimea imaginii poate fi una din valorile predefinite:

• IPL DEPTH 8U

• IPL DEPTH 8S

• IPL DEPTH 16U

• IPL DEPTH 16S

• IPL DEPTH 32S

• IPL DEPTH 32F

• IPL DEPTH 64F

1.3 Manipularea imaginilor


Citirea unei imagini dintr-un fişier se face cu ajutorul funcţiei cvLoadImage.
Sintaxa este următoarea:
img = cvLoadImage(nume fişier, flag);
Modul de ı̂ncărcare poate fi modificat modificând variabila flag astfel:
dacă are valoarea zero atunci imaginea este forţată să fie o imagine cu nivele
de gri, cu un singur canal; dacă flag > 0 atunci imaginea este cu 3 canale
de culoare; iar dacă flag < 0 atunci imaginea este ı̂ncărcată cu numărul de
canale din fişier.
Pentru a scrie o imagine ı̂ntr-un fişier se foloseşte funcţia cvSaveImage
cu următoarea sintaxă:
int cvSaveImageconst char* filename,const CvArr* image;
Primul argument reprezintă numele fişierului, a cărui extensie va deter-
mina formatul ı̂n care va fi salvată imaginea. Al doilea argument reprezintă
numele imaginii. Funcţia returnează 1 dacă salvarea s-a efectuat cu succes
şi 0 ı̂n caz de eroare.
Pentru afişarea unei imagini se utilizează funcţia: cvShowImage. Pentru
a putea afişa o imagine mai ı̂ntâi trebuie creată o fereastră pentru afişare.
Pentru aceasta se foloseşte funcţia: cvNamedWindow, iar pentru a poziţiona
fereastra pe ecran se foloseşte funcţia cvMoveWindow:
10 CAPITOLUL 1. INTRODUCERE

cvNamedWindow("Image:", CV WINDOW AUTOSIZE);


cvMoveWindows("Image:", 100, 100);
cvShowImage("image:", img);
Exemplu complet de citire şi afişare de imagine este:
#include "stdafx.h"
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
int tmain(int argc, TCHAR* argv[])
{
IplImage *img = cvLoadImage("lena.jpg"); // ^
ıncărcare
cvNamedWindow("Image:",1); // fereastra de afişare
cvShowImage("Image:",img); // se afişează imaginea
cvWaitKey(); // se asteaptă o tastă pentru terminare
cvDestroyWindow("Image:");// se distruge fereastra
cvReleaseImage(&img);
return 0;
}
În exemplul anterior imaginea a fost citită de pe disc; alternativ o ima-
gine se poate crea (de exemplu o mască). Pentru a crea o imagine ı̂ntâi
trebuie să se aloce memorie. Acest lucru se face cu funcţia:
IplImage* cvCreateImage(
CvSize size,
int depth,
int channels);
unde dimensiune, size se poate formata cu cvSize(width,height);.
Exemple
• Allocarea unei imagini cu 1 octet pe canal:
IplImage* img1=
cvCreateImage(cvSize(640,480),IPL DEPTH 8U,1);

• Allocarea unei imagini cu 3 canale de tip float:


IplImage* img2=
cvCreateImage(cvSize(640,480),IPL DEPTH 32F,3);
După utilizare o memoria utilizată de o imagine trebuie eliberată:
cvReleaseImage(&img);
O altă modalitate de creare a unei imagini este prin clonarea uneia exis-
tentă:
IplImage* img1=
cvCreateImage(cvSize(640,480),IPL DEPTH 8U,1);
IplImage* img2;
img2=cvCloneImage(img1);
1.3. MANIPULAREA IMAGINILOR 11

OpenCv-ul conţine rutine puternice pentru prelucrarea imaginilor pe


zone de interes. Setarea unei regiuni de interes se face cu:
void cvSetImageROI(IplImage* image, CvRect rect);
void cvResetImageROI(IplImage* image);
vRect cvGetImageROI(const IplImage* image);
Accesarea datelor ı̂ntr-o imagine trebuie făcută ı̂n cel mai direct şi ra-
pid mod, evitând accesul indirect prin utilizarea funcţiile de tipul cvSetND.
Considerând cazul unei imagini cu trei canale HSV, ı̂n care se doreşte mo-
dificarea saturaţiei şi a intensităţii[value] cu valoarea 255 (valoarea maximă
pentru o imagine 8 bit), accesarea datelor din canalul S şi V, se realizează
manipulând pointerii, astfel:
void saturateSV( IplImage* img ){
for( int y=0; y<img->height; y++ ) {
uchar* ptr = (uchar*) (
img->imageData + y * img->widthStep);
for( int x=0; x<img->width; x++ ) {
ptr[3*x+1] = 255;
ptr[3*x+2] = 255;
}
}
}
Pointerul ptr se calculează direct ca ı̂nceputul rândului relevant y. Apoi
locaţia canalului c pe coloana x se calculează astfel: 3*x+c. În cazul imagi-
nilor offset-ul se foloseşte aşa cum este, nu se scalează ca ı̂n cazul matricelor,
pentru că pointerul datelor este ı̂ntotdeauna de tipul byte.
O modalitate şi mai rapidă de parcurge imaginea este utilizând direct
pointeri. Acest mod nu este specific OpenCv-ul ci ţine de programare fun-
damentală ı̂n C. Funcţia anterioară se poate scrie astfel:
void saturateSV( IplImage* img ){
uchar* pImg = (uchar*) (
img->imageData + y * img->widthStep );
for( int y=0; y<img->height; y++, ptr+=img->widthStep ) {
uChar* pLine = pImg;
for( int x=0; x<img->width; x++, pLine+=3 ) {
pLine[1] = 255;
pLine[2] = 255;
}
}
}
Aici folosim doi pointeri pImg care se poziţionează la ı̂nceputul fiecărei
linii de interes fiind deci este incerementat cu distanţa ı̂ntre doi elemenţi
consecutivi pe aceeaşi coloană şi pLine care parcurge fiecare linie. El este
12 CAPITOLUL 1. INTRODUCERE

incrementat cu numărul de octeţi dintre doi pixeli consecutivi. Această


variantă este mai rapidă decât anterioara pentru că economiseşte operaţii la
calculul deplasamentului faţă de valoarea pointată. O variantă mai rapidă
se poate obţine ı̂nlocuind for-urile cu while.

1.3.1 Interfaţa grafică


Deşi recomandarea oficială este ca interfeţele grafice să fie create cu aju-
torul altor biblioteci, OpenCv-ul oferă o funcţionalitate minimală pentru a
putea ilustra concepte legate de prcesarea imaginilor. Acest lucru se face
tot cu funcţii din cadrul modulului HighGUI. În mare se disting următoarele
categorii:

• Controlul ferestrelor:
cvNamedWindow("win1", CV WINDOW AUTOSIZE); creează o fereastră
cu numele win1 şi cu proprietatea de automodificare a dimensiunii ı̂n
acord cu imaginea afişată;
cvMoveWindow("win1", 100, 100); - mută fereastra cu 1oo de pi-
xeli ı̂n jos şi la dreapta faţă de colţul din stânga sus al imaginii;
cvDestroyWindow("win1"); - distruge ferestra win1;

void cvDestroyAllWindows( void ); - distruge toate ferestele des-


chise;
cvResizeWindow("win1",100,100); redimensionează fereastra;

• Afişarea unei imaginii are loc ı̂ntr-o fereastră:


cvShowImage("win1",img); - afişează imaginea img ı̂n fereastra
win1;

• Suport si pentru tratarea evenimentelor de mouse şi tastatură. Funcţia


callback pentru mouse este:
void CvMouseCallback(
int event,
int x,
int y,
int flags,
void* param);
Pentru a asocia callback-ul unei ferestre se utilizează:
void cvSetMouseCallback(
const char* windowName,
CvMouseCallback onMouse,
void* param = NULL );
Din categoria funcţiilor asociate controlului prin tastatură vom menţiona
doar cvWaitKey(int msec) care aşteaptă numărul de milisecunde dat
drept parametru şi intoarce codul ASCI al tastei apăsate.
1.3. MANIPULAREA IMAGINILOR 13

• Controale grafice. Un trackbar este creat cu funcţia


int cvCreateTrackbar(
const char* trackbarName,
const char* windowName,
int* value,
int count,
CvTrackbarCallback onChange
);
Pentru a citi sau seta valoarea trackbar-ului se folosesc funcţiile:
int cvGetTrackbarPos(
const char* trackbarName,
const char* windowName
);
void cvSetTrackbarPos(
const char* trackbarName,
const char* windowName,
int pos);
În OpenCv nu exită suport pentru butoane. Se obişnuieşte ı̂n schimb
să se utilizeze trackbar-uri cu 2 poziţii.
14 CAPITOLUL 1. INTRODUCERE
Capitolul 2

Prelucrarea imaginilor

Deşi obiectivul final este să ofere suport pentru meotde de computer vision,
OpenCV-ul oferă suport pentru o multitudine de operaţii primare ce ţin de
domeniul prelucrării imaginilor şi, ı̂n mod tradiţional, sunt folosite fie pentru
preprocesare imaginilor fie drept bază pentru extragerea de trăsături. În
acest capitol vom inventaria câteva dintre cele mai relevante dintre acestea.

2.1 Filtare
Tradiţional, ı̂n capitolul de “filtrare” se discută despre filtrare liniară res-
pectiv neliniară, şi despre extragerea contururilor respectiv mediere (sau
netezire).
Operaţia de filtrare (convoluţie liniară cu un nucleu) poate fi implemen-
tată cu ajutorul funcţiei:
void cvFilter2D(
const CvArr* src,
CvArr* dst,
const CvMat* kernel,
CvPoint anchor=cvPoint(-1, -1))
Parametrii funcţiei au semnificaţia

• src: imaginea sursă.

• dst: imaginea destinaţie

• kernel: Nucleul de convoluţie este o matrice de tip float cu un singur


canal care se aplică pe toate cele trei plane de culoare.

• anchor: Ancora nucleului va indica poziţia relativă a punctului ce


corespunde punctului curent faţă de colţul stânga sus al nucleului.
Valoare implicită este (−1, −1) ce presupune ca nucleul se centrează
pe punctul curent.

Acestă funcţie aplică un filtru liniar unei imagini. Marginile imaginii se


completează cu cel mai apropiat vecin disponibil (prin replicare).

15
16 CAPITOLUL 2. PRELUCRAREA IMAGINILOR

2.1.1 Netezire
Pentru netezire OpenCV-ul oferă funcţia cvSmooth. Prototipul acestei funcţii
este:
void cvSmooth(
const CvArr* src,
CvArr* dst,
int smoothType,
int param1,
int param2,
double param3,
double param4);
Parametrii funcţiei au semnificaţia următoare:

• src: imaginea sursă.

• dst: imaginea destinaţie.

• smoothtype: determină tipul de netezire. Valorile predefinite sunt:

– CV BLUR NO SCALE: implementează convoluţie liniară cu un nu-


cleu dreptunghiular de dimensiuni param1×param2, ı̂n care toate
valorile sunt 1. Energia imaginii nu se pătrează (creşte) ı̂n urma
acestei operaţii
– CV BLUR - convoluţie liniară cu nucleu dreptunghiular de dimen-
siuni param1×param2, ı̂n care toate valorile sunt 1, urmată de
sclarea valorilor pentru conservarea energiei.
– CV GAUSSIAN - convoluţie liniară cu un nucleu gaussian de dimen-
siuni param1×param2.
– CV MEDIAN - filtru median (filtru neliniar de ordine) pe o ve-
cinătate de diametru param1×param1.
– CV BILATERAL filtru bilateral aplicat pe o vecinătate de dimen-
siuni param1×param1, iar variantă color este dată de param3 şi
variantă spaţială de param4. Mai multe informaţii despre filtrarea
bilaterală se pot afla ı̂n [8].

• param1 - Primul parametru al operaţiei de netezire şi reprezintă di-


ametrul orizontal al nucleului de filtrare. Trebuie să fie un număr
pozitiv impar (1, 3, 5, etc.)

• param2 - Al doilea parametru al operaţiei de netezire şi reprezintă


diametrul vertical al nucleului de filtrare. Este ignorat ı̂n cazul filtrării
mediane şi bliaterale. Trebuie să fie un număr pozitiv impar.

• param3 - În cazul netezirii gaussiene are semnificaţia de deviaţie stan-


dard.
2.1. FILTARE 17

2.1.2 Extragerea contururilor


Pentru detecţia contururilor, bibliotecile OpenCV pun la dispozitie 3 me-
tode: operatorii primari Laplace şi Sobel şi operatorul evoluat Canny.
Detecţia de contururi folosind operatorul Sobel presupune convoluţia
imaginii cu două nuclee: unul care să facă mediere pe orizontală şi să măsoare
amplitudinea nucleelor pe verticală şi unul care să netezească pe verticală
şi să caute muchii pe orizontală. Cele două imagini rezultante se compun
(radical din suma patratelor).
Pentru a folosi operatorul Sobel se apelează la funcţia cvSobel. Sintaxa
acesteia este:
void cvSobel(
const CvArr* src,
CvArr* dst,
int xorder,
int yorder,
int apertureSize);
Parametrii necesari sunt:

• src: imaginea originală (sursă).

• dst: imaginea finală (destinaţie). Reprezintă contururile imaginii


iniţiale.

• xorder: ordinul derivatei pe direcţia x.

• yorder: ordinul derivatei pe direcţia y

• aperture size: dimensiunea kernelului aplicat. Poate fi 1, 3, 5 sau 7


 
−1 0 1
Nucleul Sobel pentru direcţia x este: −2 0 2
−1 0 1
 
−1 −2 −1
Nucleul Sobel pentru direcţia y este:  0 0 0
1 2 1
Operatorul Sobel poate fi aplicat pe directia x folosind următoarea sin-
taxă:
cvSobel(img, out2, 1, 0, 3);
Trebuie menţionat că de cele mai multe ori imaginea finală (destinaţie)
conţine valori mult mai mari decât imaginea sursă (ı̂n valoare absolută), şi,
pentru a evita depăşirea de scală este nevoie ca imaginea destinaţie sa fie
reprezentată pe 16b, dacă imaginea sursă este reprezentată pe 8b.
Detecţia de contururi folosind operatorul Laplace are la bază derivata
a doua:
d2 src d2 src
dst(x, y) = + (2.1)
dx2 dy 2
ı̂n timp ce Sobel presupune calculul derivatei ı̂ntâi.
Pentru a folosi operatorul Laplace putem apela la functia de OpenCv
cvLaplace. Sintaxa acesteia este descrisa in continuare.
18 CAPITOLUL 2. PRELUCRAREA IMAGINILOR

void cvLaplace(
const CvArr* src,
CvArr* dst,
int apertureSize=3)
Parametrii:

• src - imaginea originală (sursă);

• dst - imaginea finala (destinaţie). Reprezintă contururile imaginii


iniţiale;

• apertureSize - dimensiunea nucleului aplicat. Poate fi 1, 3, 5 sau 7.


 
0 1 0
Nucleul Laplace aplicat, pentru o apertură de 1 este: 1 −4 1
0 1 0
Şi ı̂n acest caz, imaginea finală (destinaţie) poate conţine valori mult mai
mari decât imaginea sursă (ı̂n valoare absolută), şi, pentru a evita depaşirea
de scală este nevoie ca imaginea desţinatie să fie reprezentată pe 16b, dacă
imaginea sursă este reprezentată pe 8b.
Detecţia de contururi folosind operatorul Canny implementează un al-
goritm complex bazat pe extragere de contururi ce include netezire gaussiană
pentru reducerea zgomotului, detecţie de contururi cu operatorul Sobel, eli-
minarea valorilor non-maximale şi binarizarea adaptivă contururilor conti-
nue [4]. Pentru a folosi operatorul Canny putem apela la funcţia de OpenCv
cvCanny. Sintaxa acesteia este:
void cvCanny(
const CvArr* image,
CvArr* edges,
double threshold1,
double threshold2,
int aperture size );
Semnificaţia parametrilor este:

• image - imaginea originală (sursă);

• edges - imaginea finala (destinaţie). Reprezintă contururile imaginii


iniţiale;

• threshold1 - valoarea primului prag;

• threshold2 - valoarea celui de-al doilea prag;

• aperture size - dimensiunea nucleului aplicat. Poate fi 1, 3, 5 sau 7.

Valoarea cea mai mică dintre threshold1 şi threshold2 este folosită
pentru a uni contururile, iar valoarea cea mai mare este folosită pentru a
determina segmentele de contururi puternice.
2.2. MORFOLOGIE MATEMATICA 19

2.2 Morfologie matematica


Morfologia matematică a fost introdusă ı̂n prelucrarea imaginilor de către
Serra [7]. O operaţie morfologică presupune convoluţia unei imagini, sau
a unei regiunii dintr-o imagine, A cu un nucleu B care poartă numele de
element structurant. Un pixel este descris de coordonatele spaţiale x şi de
nivelul de gri, A(x). Elementul structurant poate avea orice formă şi mărime
şi are un sistem de coordonate propriu ce de obicei ı̂şi conţine originea, deşi se
poate să nu o facă. Iarăşi, deşi uzuale sunt elementele structurante simetrice,
există şi aplicaţii ı̂n care se folosesc elemente ne-simetrice.
Operaţiile morfologice de bază sunt dilatarea şi erodarea, acestea putând
fi folosite ı̂n numeroase contexte precum eliminarea zgomotului, izolarea
unor obiecte sau unirea unor elemente disjuncte din imagine. Reamintim
că dilatarea, ⊕ este definită ca o operaţie de maximizare locală pe supor-
tul elementului structurant. Operaţia are ca rezultat creşterea regiunilor
luminoase şi reducerea celor ı̂ntunecate.

A⊕B = max {A(x − y) + B(y)} (2.2)


y∈Supp(B)

Erodarea, ⊖ reprezintă operaţia duală1 şi este definită ca o operatie de


minimizare locală pe suportul elementului structurant.

A⊖B = min {A(x − y) − B(y)} (2.3)


y∈Supp(B)

Operaţia de erodare are ca rezultat creşterea regiunilor ı̂ntunecate şi


reducerea celor luminoase.
Morfologia matematică este deseori folosită pe imagini binare, obţinute
ı̂n urma prăguirii imaginii sau a imaginii de contururi. Dacă obiectele sunt
reprezentate printr-o valoare nenulă şi fundalul prin 0, dilatarea are ca rezul-
tat mărirea obiectelor, iar eroadarea micşorarea lor. Direcţia de modificare
a obiectelor depinde de orientarea şi forma elementului structurant.

2.2.1 Morfologie matematica in OpenCV


In OpenCv operaţiile descrise anterior sunt implementate ı̂n funcţiile cvDilate
şi cvErode:
void cvDilate(
IplImage* src,
IplImage* dst,
IplConvKernel* B = NULL,
int iterations = 1
);
void cvErode(
IplImage* src,
IplImage* dst,
1
Operaţiile duale au acelaşi efect dacă se interschimbă obiectul cu complementul lui -
fundalul.
20 CAPITOLUL 2. PRELUCRAREA IMAGINILOR

IplConvKernel* B = NULL,
int iterations = 1
);
unde parametrii sunt:
• scr: imaginea sursă;
• dst: imaginea destinatie (poate fi tot src);
• B: nucleul, elementul structurant (implicit dat ca valoare NULL este
echivalent cu un nucleu 3*3 cu originea in mijloc)
• iterations: numărul de câte ori se repetă operaţia (implicit 1).
Rezultatul funcţiilor este că valoarea fiecărui pixel din imaginea sursă
este ı̂nlocuită ı̂n imaginea destinaţie cu maximul, respectiv minimul, dintre
valorile tuturor pixelilor acoperiţi de elementul structurant, ce are originea
suprapusă peste pixelul curent.
Un element structurant plat nu are nevoie de valori numerice şi doar
indică poziţii ı̂n spaţiu care sunt considerate la calculul maximului sau mini-
mului local. Originea elementului structurant arată cum este aliniat nucleul
peste fiecare pixel al imaginii sursă.
Pentru realizarea altor tipuri de elemente structurante se foloseste func-
tia:
IplConvKernel* cvCreateStructuringElementEx(
int cols,
int rows,
int anchor x,
int anchor y,
int shape,
int* values=NULL
);
unde parametrii folosiţi sunt :
• cols, rows - dimensiunea dreptunghiului care conţine elementul struc-
turant;
• anchor x, anchor y - coordonatele originii ı̂n dreptunghiul determinat
anterior;
• shapes identifică forma elementului structurant si poate avea valorile
predefinite:
– CV SHAPE RECT - element structurant dreptunghiular
– CV SHAPE CROSS - element structurant ı̂n formă de cruce
– CV SHAPE ELLIPSE - element structurant elliptic
– CV SHAPE CUSTOM - element structurant definit de utilizator
• values: utilizat când shape= CV SHAPE CUSTOM; conţine rows × cols
elemente; o valoare diferită de zero indică prezenţa punctului ı̂n ele-
mentul structurant.
2.2. MORFOLOGIE MATEMATICA 21

Ştergerea unui element structurant se realizează cu:


void cvReleaseStructuringElement(
IplConvKernel** element );
Pentru realizarea unor operaţii adiţionale se poate folosi funcţia:
void cvMorphologyEx(
const CvArr* src,
CvArr* dst,
CvArr* temp,
IplConvKernel* element,
int operation,
int iterations = 1
);
Aceasta functie foloseşte 2 noi parametri:
• temp: un vector temporal necesar unor operaţii, ce trebuie să aibă
aceleaşi dimensiuni ca şi imaginea originala;

• operation: selectează operaţia morfologică ce trebuie efectuată:

– CV MOP OPEN - realizează deschidere morfologică;

A ◦ B = (A ⊕ B) ⊖ B (2.4)

– CV MOP CLOSE - realizează ı̂nchidere morfologică;

A • B = (A ⊖ B) ⊕ B (2.5)
– CV MOP GRADIENT - realizează gradientul morfologic (are nevoie
de temp);
– CV MOP TOPHAT - implemntează transformata Top Hat (are nevoie
de temp doar dacă src = dst);
– CV MOP BLACKHAT - implemntează transformata Black Hat (are
nevoie de temp doar dacă src = dst).

Închiderea morfologică a imaginii cu un element structurant se defineşte


ca dilatarea imaginii cu elementul structurant respectiv, urmată de eroda-
rea cu elementul structurant simetrizat. Operaţia are drept efect netezirea
formei. Prin ı̂nchiderea cu un element structurant de tip disc centrat ı̂n
origine, găurile incluse ı̂n obiecte, mai mici decât elementul structurant fo-
losit, sunt umplute, ca de altfel şi concavităţile puternice ale contururilor;
totodată obiectele foarte apropiate sunt unite.
Deschiderea morfologică a imaginii cu un element structurant se defineşte
ca erodarea imaginii cu elementul structurant respectiv, urmată de dilatarea
cu elementul structurant simetrizat. Operaţia are drept efect de netezirea
fundalului. Prin deschiderea cu un element structurant de tip disc centrat
ı̂n origine, componentele imaginii mai mici decât elementul structurant sunt
ı̂ndepărtate şi convexităţile foarte accentuate ale contururilor sunt teşite.
Repetarea operaţiilor de ı̂nchidere, respectiv deschidere, cu acelasi ele-
ment structurant nu mai aduce modificări. Din acest motiv pentru valoarea
22 CAPITOLUL 2. PRELUCRAREA IMAGINILOR

2 (sau mai mare) a argumentului iterations operaţiile se repetă ı̂n ordinea


dilatare-dilatare-erodare-erodare, respective invers.

Gradientul morfologic O aplicaţie practică a morfologiei matematice


este extragerea gradientului. Acesta se defineşte:

gradient(src) = (A ⊕ B) − (A ⊖ B) (2.6)

Efectul acestei operaţii pe o imagine binară este identificarea perime-


trului obiectelor. Într-o imagine cu nivele de gri operatorul arată variaţia
intensităţii luminoase.

Transformatele Top Hat şi Black Hat Aceşti operatori sunt utilizaţi
pentru a izola regiuni care sunt mai luminoase, respectiv mai ı̂ntunecate
decât zonele imediat invecinate:
T opHat(src) = A − (A ◦ B)
(2.7)
BlackHat(src) = (A • B) − A

2.3 Transformări geometrice


Transformările geometrice reprezintă operaţii utilizate pentru modificarea
structurii spaţiale a imaginilor, permiţând deplasarea pixelilor din imagine,
astfel ı̂ncât orice pixel al imaginii iniţiale să poată fi transformat ı̂n orice pixel
al imaginii finale. Datorită necesităţii de păstrare a conţinutului vizual se vor
impune o serie de constrângeri asupra posibilităţilor de mişcare ale pixelilor.
Transformările geometrice sunt definite de legea de mişcare a punctelor din
imaginea iniţială către cea finală.
Transformările ce pot fi aplicate imaginii sursă sunt:
1. Translaţia reprezintă deplasarea ı̂n plan a conţinutului imaginii (schim-
barea sistemului de coordonate de reprezentare);

2. Scalarea poate fi ı̂n fapt ı̂ntindere sau comprimare a imaginii pe una


sau ambele axe, fără păstrarea distanţelor ı̂ntre perechi de pixeli din
imaginea iniţială şi cea transformată;

3. Înclinarea imaginii reprezintă deplasarea pixelilor după o singură co-


ordonată, cealaltă rămânând nemodificată;

4. Rotaţia pixelii sunt deplasaţi circular ı̂n jurul centrului de rotaţie.


Funcţiile din cadrul acestei secţiuni a librăriei OpenCV sunt utilizate
pentru transformări bidimensionale ale imaginilor, neschimbând conţinutul
acestora, ci deformând grid-ul ce va fi ulterior suprapus imaginii destinaţie.
Pentru evitarea operaţiei de eşantionare, maparea se face ı̂n ordine inversă,
de la imaginea, de la destinaţie spre sursă (pixel filling). Pentru fiecare pixel
caracterizat de coordonatele (x, y) din imaginea destinaţie se vor calcula co-
ordonatele pixelului corespondent din imaginea sursă şi se va copia valoarea
acestora:
dst(x, y) = src (f (x, y), f (x, y)) (2.8)
2.3. TRANSFORMĂRI GEOMETRICE 23

Implementările transformărilor geometrice se confruntă cu două pro-


bleme:
1. Extrapolarea pixelilor inexistenţi: unii pixeli se pot regăsi ı̂n exteriorul
imaginii destinaţie, fiind nevoie de o operaţie suplimentară de extra-
polare, ce se alege din opţiunile puse la dispoziţie de librăria OpenCV.
Opţiunea BORDER TRANSPARENT poate fi utilizată pentru a nu mai mo-
difica pixelii corespunzători din imaginea destinaţie;
2. Interpolarea valorilor pixelilor: ı̂n cazul transformărilor afine, de per-
spectivă sau corecţie a distorsiunilor introduse de lentile radiale, tre-
buie recuperaţi pixelii situaţi la coordonate fracţionare. O decizie
simplă o reprezintă rotunjirea coordonatelor la cea mai apropiată coor-
donată număr ı̂ntreg, rezultate mai bune fiind obţinute prin utilizarea
funcţiilor de interpolare predefinite.
Funcţiile oferite de biblioteca OpenCV pentru transformări geometrice
şi interpolări, ı̂n condţiile ı̂n care mereu src se referă imaginea sursă, iar
dst la cea destinaţie sunt:
• cvGetRotationMatrix2D: calculează matricea afină a unei rotaţii bi-
dimensionale. Prototipul este:
CvMat* cv2DrotationMatrix(
cvPoint2D32f center,
double ange,
double, scale,
CvMat* mapMarix);
Parametrii suplimentari ai funcţiei sunt:
– center: centrul rotaţiei ı̂n imaginea sursă;
– angle: unghiul de rotaţie ı̂n grade;
– scale: factorul de scalare;
– mapMatrix: pointer la matricea destinaţie, de dimensiune 2 × 3.
Funcţia calculează matricea.
• cvGetAffineTransform: calculează transformarea afină utilizând trei
puncte;
CvMAt* cvGetAffinetransform(
const cvPoint2D32f* src,
const CvPoint2D32f* dst,
CvMat* mapMatrix);
Parametrul suplimentar al transfomării este mapMatrix ce reprezintă
pointer la matricea 2 × 3 destinaţie.
• cvGetPerspectiveTransform: calculează transformarea de perspec-
tivă utilizând 4 puncte;
CvMAt* cvGetPerspectivTransform(
const cvPoin2D32f src,
24 CAPITOLUL 2. PRELUCRAREA IMAGINILOR

const CvPoint2D32f* dst,


CvMat* mapMatrix);
Parametrul suplimentar este mapMatrix - pointer la maricea destinaţie.

• cvGetQadrangelSubPix: extrage coordonatele pixelului din imagine


cu acurateţe de subpixel. Valorile coordonatelor ce nu sunt numere
ı̂ntregi sunt extrase prin interpolare biliniară. În cazul imaginilor
multi-canal, fiecare canal este prelucrat independent;
void cvGetQaudrangleSubPix(
const CvArr* src,
CvArr* dst,
const CvMat* mapMatrix);
Parametrul suplimentar al funcţiei este mapMatrix şi reprezintă ma-
tricea de transformare 2 × 3. Funcţia extrage pixeli cu acurateţe de
subpixel din imaginea sursă şi ı̂i stochează ı̂n imaginea destinaţie

• cvGetRectSubPix: extrage vecinătatea dreptunghiulară a unui pixel


cu acurateţe de subpixel. Centrul dreptunghiului trebuie să se situeze
ı̂n interiorul imaginii, deşi părţi din acesta pot fi ı̂n exterior;
void cvGetRectSubPix(
const CvArr* src,
CvArr* dst,
CvPoint2d32f center);
Parametrii funcţiei sunt:

– src: imaginea sursă;


– dst: dreptunghiul extras;
– center: coordonatele centrului dreptunghiului extras (float) din
cadrul imaginii sursă. Valorile pixelilor la coordonate ce nu re-
prezintă numere ı̂ntregi vor fi calculate utilizând interpolarea bi-
liniară.

• cvLogPolar: mapează o imagine utilizând spaţiul log-polar. Această


funcţie emulează vederea umană şi poate fi utilizatâ ı̂n cadrul aplicaţiilor
de reperare a modeleor invariante la rotaţie sau urmărire de obiecte;
void cvLogPolar(
const CvArr* src,
CvArr* dst,
CvPoint2D32f center,
double M,
int flags);
Parametrii suplimentari ai funcţiei sunt:

– center: centrul transformării, locul de precizie maximă;


2.3. TRANSFORMĂRI GEOMETRICE 25

– M: parametru de scalare a amplitudinii;


– flags: o combinaţie ı̂ntre metodele de interpolare şi flag-uri
opţionale:
∗ CV WARP FILL OUTLINERS: umple toţi pixelii din imaginea destinaţie;
∗ CV WARP INVERSE MAP

• cvRemap: aplică o transformare geometrică imaginii;


void cvRemap(
const CvArr* src,
CvArr* dst,
const CvArr* mapx,
const CvArr* mapy,
int flags,
CvScalar fillval = cvScalarAll(0));
Parametrii suplimentari ai funcţiei sunt:

– mapx: harta coordonatelor pe axa x;


– mapy: harta coordonatelor pe axa y;
– flags: o combinaţie ı̂ntre metoda de interpolare şi o serie de
flag-uri opţionale;
– fillval: valoarea utilizată pentru umplerea contururilor.

• cvResize: rescalează imaginea sursă pentru a se potrivi constrângerilor


impuse imaginii destinaţie;
void CvResize(
const CvArr* src,
CvArr* dst,
int interpolation = CV INTER LINEAR);
Parametrul suplimentar al funcţiei este interpolation şi preprezintă
metoda de interpolare utilizată. Aceasta poate fi:

– CV INTER NN: interpolare de tipul cel mai apropiat vecin;


– CV INTER LINEAR: interpolarea biliniara (default);
– CV INTER AREA: re-eşantionare prin utilizarea relaţiei de arie a
pixelului;
– CV INTER CUBIC: interpolare bicubică.

• cvWarpAffine: aplică o transformare afină imaginii;


void cvWarpAffine(
const CvArr* src,
CvArr* dst,
const CvMat* mapMatrix,
26 CAPITOLUL 2. PRELUCRAREA IMAGINILOR

int flags,
CvScalar fillval = cvScalarAll(0));
Parametrii suplimentari ai funcţiei sunt:

– mapMatrix: matricea 2 × 3 de transformare;


– flags: o combinaţie de metode de interpolare şi următoarele
flag-uri opţionale:
∗ CV WARP FILL OUTLINERS: umple pixelii imaginii destinaţie;
∗ CV WARP INVERSE MAP: indică faptul că matrix este tranfor-
mată invers de la imaginea destinaţie la sursă, putând fi
direct utilizată pentru interpolarea pixelilor. În caz con-
trar, funcţia trebuie să găsească transformarea inversă pentru
mapMatrix;
– fillval: valoarea utilizată pentru umplerea contururilor. Această
funcţie necesită ca imaginile sursă şi rezultat să aibă acelaşi tip
de date, nu este recomandată imaginilor mici şi poate lăsa o parte
din imaginea destinaţie neschimbată.

• cvWarpPerspective: aplică o transformare de perspectivă imaginii.


void cvWarpPerspective(
const CvArr* src,
CvArr* dst,
const CvMat* mapMAtrix,
int flags = CV INTER LINEAR+CV WARP FILL OUTLIERS,
CvScalar fillval = cvScalarAll(0));
Parametrii suplimentari ai funcţiei sunt:

– mapMatrix: matricea 3 × 3 de transformare;


– flags: o combinaţie de metode de interpolare şi următoarele
flag-uri opţionale
∗ CV WARP FILL OUTLINERS: umple pixelii imaginii destinaţie;
∗ CV WARP INVERSE MAP: indică faptul că matrix este tranfor-
mată invers de la imaginea destinaţie la sursă, putând fi
direct utilizată pentru interpolarea pixelilor. În caz con-
trar, funcţia trebuie să găsească transformarea inversă pentru
mapMatrix;
– fillval: valoarea utilizată pentru umplerea contururilor.

2.4 Histograma
Histograma reprezintă o aproximare practică a densităţii de probabilitate,
a cărei realizare particulară este imaginea dată . Cel mai des, histograma
conţine valorile de luminozitate ale pixelilor, ı̂n intervalul 0 (negru) - 255
(alb). Aplicaţiile practice ale histogramelor includ:
2.4. HISTOGRAMA 27

• histogramele 1-D se folosesc la :

– evdindenţierea obiectelor ı̂n imagini cu nivele de gri


– identificarea obiectelor ı̂n cadrul procesului de segmentare

• histogramele 2-D se folosesc la:

– analiza şi segmentarea imaginilor color


– analiza şi segmentarea câmpurilor de mişcare
– analiza formelor şi texturilor

O histogramă poate fi stocată fie sub o formă densă (suprafaţă multi-


dimensională), fie sub o formă distribuită (arbore echilibrat). Astfel, histo-
gramele 1-D şi 2-D sunt memorate sub o formă densă, ı̂n timp ce histogra-
mele n-D (n ¿ 3) sunt memorate sub o formă distribuită. Într-o histogramă
de tip suprafaţă multi-dimensională fiecare dimensiune corespunde unei ca-
racteristici a obiectului. Un element din suprafaţă este numit “bin” (nivel)
al histogramei, şi este caracterizat de coordonatele [i1 , i2 , . . . , in ] şi conţine
un număr de măsurători pentru respectivul obiect cu valoarea cuantizată i1
pentru prima coordonată, i2 pentru a doua coordonată, ş.a.m.d.
În OpnCV tipul de date CvHistogram se foloseşte pentru stocarea tutu-
ror tipurilor de histogramă. Declaraţia acestui tip este:
typedef struct CvHistogram {
int header size;
CvHistType type;
int flags;
int c dims;
int dims[CV HIST MAX DIM];
float* thresh[CV HIST MAX DIM];
float* array;
struct CvNode* root;
CvSet* set;
int* chdims[CV HIST MAX DIM];
CvHistogram;
unde semnificaţia câmpurilor este:

• header size reprezintă dimensiunea header-ului;

• type - tipul histogramei;

• flags - flag-urile histogramei;

• c dims - numărul dimensiunilor histogramei;

• dims[CV HIST MAX DIM] - mărimea fiecărei dimensiuni;

• thresh[CV HIST MAX DIM] - prag pentru fiecare dimensiune;

• array - datele histogramei desfăşurate pe un singur rând;


28 CAPITOLUL 2. PRELUCRAREA IMAGINILOR

• root - datele histogramei-arbore;


• set - pointer către locaţia din memorie (pentru datele din arbore);
• chdims[CV HIST MAX DIM] - date stocate pentru calcul rapid;

Funcţiile asociate lucrului cu histograma sunt:


• CreateHist creează o histogramă de dimensiuni specificate şi ı̂ntoarce
un pointer către histograma creată. Dacă parametrul ranges este 0
atunci trebuie menţionate domeniile binilor ı̂n funcţia SetHistBinRanges:
CvHistogram* cvCreateHist (
int cDims,
int* dims,
CvHistType type,
float** ranges=0,
int uniform=1); unde:
– cDims reprezintă numărul dimensiunilor histogramei
– dims - suprafaţa mărimilor dimensiunilor histogramei
– type - formatul reprezentării histogramei cu următoarele valori
predefinite: CV HIST ARRAY ı̂nseamnă că datele histogramei sunt
reprezentate ca o suprafaţă, iar CV HIST TREE ı̂nseamnă că datele
sunt reprezentate ca un arbore echilibrat;
– ranges - domeniului fiecărui nivel al histogramei; depinde de va-
loarea parametrului uniform;
– uniform - flag de uniformitate, ia valoarea 1 pentru histograma
are cu nivele distribuite uniform;
• ReleaseHist eliberează o histogramă (header şi date) setând toate
valorile la 0 ı̂n cazul unei histograme dense, sau ştergând toate valorile
ı̂n cazul unei histograme distribuite.
void cvReleaseHist (CvHistogram* hist);
unde: hist este pointer către histograma ţintă.
• MakeHistHeaderForArray iniţializează header-ul histogramei şi se-
tează pointer-ul de date la valoarea specificată data. Histograma tre-
buie să fie de tipul CV HIST ARRAY.
void cvMakeHistHeaderForArray (
int cDims,
int* dims,
CvHistogram* hist,
float* data,
float** ranges=0,
int uniform=1);
unde cel mai important parametru este data ce reprezintă un pointer
către histograma sursă de date
2.4. HISTOGRAMA 29

• QueryHistValue 1D interoghează o anumită valoare a unei histograme


1-D specificată prin hist şi ı̂ntoarce valoarea binului specificat. Dacă
formatul histogramei este distribuit, iar binul specificat nu există atunci
funcţia ı̂ntoarce 0.
float cvQueryHistValue 1D (CvHistogram* hist, int idx0);
unde idx0 este indexul valorii căutate.

• QueryHistValue 2D interoghează o valoarea dintr-o histograme 2-D la


locaţia idx0, idx1:
float cvQueryHistValue 2D (
CvHistogram* hist,
int idx0,
int idx1);

• QueryHistValue 3D interoghează valoarea binului unei histograme 3-


D

• QueryHistValue nD interoghează valoarea binului unei histograme n-


D unde locaţia nD este dată prin pointerul la lista de indecşi idx.
float cvQueryHistValue nD (CvHistogram* hist, int* idx);
Similar cu setul de funtii QueryHistValue nD este setul de funcţii
GetHistValue nD cu diferenţa că ı̂ntoarce un pointer (şi nu valoarea
propiru-zisă) către o locaţie a histogramei, deci permite modificarea
acesteia.

• Funcţia GetMinMaxHistValue caută valorile minime şi maxime din


histogramă. În cazul ı̂n care există mai multe minime şi maxime sunt
returnate valorile cele mai din stânga.
void cvGetMinMaxHistValue (
CvHistogram* hist,
float* minVal,
float* maxVal,
int* minIdx=0,
int* maxIdx=0);
unde parametrii sunt:

– minVal - pointer către valoarea minimă a histogramei; poate fi


NULL;
– maxVal - pointer către valoarea maximă a histogramei; poate fi
NULL;
– minIdx - pointer către suprafaţa coordonatelor minimului ; dacă
nu este NULL trebuie să aibă hist->c dims elemente;
– maxIdx - pointer către suprafaţa coordonatelor maximului; dacă
nu este NULL trebuie să aibă hist->c dims elemente.
30 CAPITOLUL 2. PRELUCRAREA IMAGINILOR

• Funcţia NormalizeHist normalizează histograma astfel ı̂ncât suma


valorilor să fie egală cu factorul de normalizare.
void cvNormalizeHist (CvHistogram* hist, float factor);
unde factor reprezintă factorul de normalizare.

• ThreshHist - setează pragul, specificat prin thresh pentru segmentare


histogramă, astfle ı̂ncât toate valorile sub nivelul specificat sunt făcute
0.
void cvThreshHist (CvHistogram* hist, float thresh);

• CompareHist - compară două histograme:


double cvCompareHist (
CvHistogram* hist1,
CvHistogram* hist2,
CvCompareMethod method);
unde parametrii au semnificaţia:

– hist1 reprezintă prima histogramă;


– hist2 - a doua histogramă;
– method indică metoda de comparaţie şi poate lua una din valorile:
∗ CV COMP CORREL - metoda folosită este corelaţia ı̂ntre cele
două histgrame. Valoarea ı̂ntoarsă este:
i i
P
I H1 (I) · H2 (I)
d(H1 , H2 ) = qP (2.9)
i (I) 2 · i (I) 2
 P 
I H 1 I H 2

unde Hki (I) = Hk (I) − N1 J Hk (J), iar N este numărul de


P
valori ı̂n care a fost calculată histograma.
∗ CV COMP CHISQR - himplementează metoda χ2 :
X H1 (I) − H2 (I)
d(H1 , H2 ) = (2.10)
H1 (I) + H2 (I)
I

∗ CV COMP INTERSECT implementează:


X
d(H1 , H2 ) = max(H1 (I), H2 (I)) (2.11)
I

∗ CV COMP BHATTACHARYYA implementează distanţă Bhattacha-


ryya (ce necesită histograme normalizate) conform formulei:
s Xp
d(H1 , H2 ) = 1 − H1 (I)H2 (I) (2.12)
I

• CopyHist - realizează o copie a histogramei. Dacă al doilea pointer


al histogramei *dst este NULL atunci se creează o nouă histogramă
de aceeaşi dimensiune cu src. Altfel, ambele histograme trebuie să
2.4. HISTOGRAMA 31

aibă tipuri şi dimensiuni identice. Funcţia copiază valoarea binului


histogramei sursă ı̂n histograma destinaţie şi setează domeniul binului
la fel ca ı̂n src.
void cvCopyHist (CvHistogram* src, CvHistogram** dst);

• SetHistBinRanges setează limitele intervalelor ı̂n care se calculează


valorile histogramei. Acetse intervale trebuie să fie stabilite ı̂nainte de
a calcula histograma sau proiecţia de fond.
void cvSetHistBinRanges (
CvHistogram* hist,
float** ranges,
int uniform=1);

• Funcţia CalcHist este poate cea mai importantă intrucât ea calcu-


lează histograma unei imagini cu un singur canal. Dacă parametrul
doNotClear este 0 atunci histograma este ştearsă ı̂nainte de calcul;
altfel, histograma este reactualizată.
void cvCalcHist (
IplImage** img,
CvHistogram* hist,
int doNotClear=0,
IplImage* mask=0);
unde parametrii funcţiei au semnificaţia:

– img indică imaginea pe care se va calcula histograma;


– hist - pointer către histogramă;
– doNotClear - flagul de clear cu funcţionalitatea meanţionată
– mask este masca ce determină ce pixeli ai imaginilor sursă sunt
luaţi in considerare ı̂n calculul histogramei

• Funcţia CalcBackProject calculează proiecţia de fond pentru o his-


togramă. Mai precis fiind dată o histogramă specificată prin hist
şi imaginea (pe care să se facă proiecţia), src va returna o imagine
de acceaşi dimensiune cu imaginea originală, dar ı̂n care intensităţile
pixelilor sunt ı̂nlocuite cu probabilitatea de apariţie a nivelului.
void cvCalcBackProject (
IplImage** img,
IplImage* dstImg,
CvHistogram* hist);

• CalcContrastHist determină histograma de contrast pentru o ima-


gine cu un singur canal. Dacă parametrul dontClear este 0 atunci
histograma este ştearsă ı̂nainte de calcul ; altfel, histograma este reac-
tualizată. Dacă pointerul către mască este NULL histograma se calcu-
lează pentru toţi pixelii din imagine ; altfel, se iau ı̂n considerare doar
pixelii cu valoare nenulă din mască.
32 CAPITOLUL 2. PRELUCRAREA IMAGINILOR

void cvCalcContrastHist (
IplImage **src,
CvHistogram* hist,
int dontClear,
IplImage* mask);
unde parametrii au semnificaţia :

– src - pointer către imaginile sursă


– hist - histograma destinaţie
– dontClear - flag clear
– mask - imagine mască

• Funcţia EqualizeHist modifică contrastul unei imagini conforma al-


goritmului clasic de egalizare de histogramă.
void cvEqualizeHist( const CvArr* src, CvArr* dst );
unde src este pointer către imaginea sursă, iar dst către imaginea
destinaţie.
Capitolul 3

Analiza imaginilor

Deşi cuprinde rutine pentru mai multe operaţii din categoria analizei ima-
ginilor, cum ar fi descrierea formelor sau a contururilor, aici vom prezenta,
pe scurt, doar câteva din soluţiile existente ı̂n OpenCV ı̂n ceea ce priveşte
segmentarea.

3.1 Segmentare
Segmentarea ese operaţia ı̂n care o imagine este partiţionată ı̂n segmentele
constituente, segmente ce se doreşte să corespundă obiectelor vizibile ı̂n
imagine.

3.1.1 Segmentarea cu prag


Segmentarea cu prag este probabil cea mai simplă metodă de partiţionare
a imaginii ı̂n obiecte constituente şi utilă ı̂n special datorită simplităţii sale.
Functia OpenCV cvThreshold() este folosită pentru segmentarea cu prag
fix. Ideea de bază e că fiind dat un vector, un prag, fiecare element al
vectorului este modificat depinzând de faptul că este mai mic sau mai mare
decât pragul.
double cvThreshold(
CvArr* src,
CvArr* dst,
double threshold,
double max value,
int threshold type);
După cum este aratat ı̂n tabelul 3.1, fiecărui tip de prag ı̂i corespunde
o operaţie de comparaţie ı̂ntre pixelul i din sursa src[i] şi pragul notat
ı̂n tabel cu T. În funcţie de relaţia dintre pixelul sursă şi prag, pixelul din
vectorul destinatie dst[i] poate fi setat la 0, src[i] sau max value (notată
ı̂n tabel cu M).
În exemplul de mai jos sunt adunate cele trei planuri de culoare şi apoi
rezultatul este trunchiat la 100.
#include <stdio.h>
#include <cv.h>

33
34 CAPITOLUL 3. ANALIZA IMAGINILOR

Tabela 3.1: Diferitele variante de prăguire selectabile prin parametrul


threshold type ale funcţiei cvThreshold()

Tipul de prag - threshold type Operaţia


CV THRESH BINARY dst[i] =(src[i] > T )> M:0
CV THRESH BINARY INV dst[i] =(src[i] > T )> 0:M
CV THRESH TRUNC dst[i] =(src[i] > T )> M:src[i]
CV THRESH TOZERO INV dst[i] =(src[i] > T )> 0:src[i]
CV THRESH TOZERO dst[i] =(src[i] > T )> src[i]:0

Figura 3.1: Rezultatele varierii threshold type ı̂n funcţia cvThreshold().


Linia orizontală din fiecare grafic reprezintă un nivel particular al pragului
aplicat graficului de sus şi efectul sau pentru fiecare dintre cele cinci tipuri
operaţii de segmentare mai jos.
3.1. SEGMENTARE 35

#include <highgui.h>
void sum rgb( IplImage* src, IplImage* dst ) {
// aloca planurile individuale de culoare.
IplImage* r = cvCreateImage( cvGetSize(src), IPL DEPTH 8U, 1 );
IplImage* g = cvCreateImage( cvGetSize(src), IPL DEPTH 8U, 1 );
IplImage* b = cvCreateImage( cvGetSize(src), IPL DEPTH 8U, 1 );
// imparte imaginea in planurile de culoare
cvSplit( src, r, g, b, NULL );
// in s este stocata imaginea temporar
IplImage* s = cvCreateImage( cvGetSize(src), IPL DEPTH 8U, 1 );
// Aduna ponderi egale pentru valorile rgb
cvAddWeighted( r, 1./3., g, 1./3., 0.0, s );
cvAddWeighted( s, 2./3., b, 1./3., 0.0, s );
// truncheaza valorile mai mari de 100
cvThreshold( s, dst, 100, 100, CV THRESH TRUNC );
cvReleaseImage( &r );
cvReleaseImage( &g );
cvReleaseImage( &b );
cvReleaseImage( &s );
}

int main()
{
char *name=NULL;
name="fruits.jpg";
// creeaza o fereastra numita ca fisierul imagine
cvNamedWindow( name, 1 );
// incarca imaginea cu numele dat
IplImage* src = cvLoadImage(name );
IplImage* dst = cvCreateImage( cvGetSize(src), src->depth, 1);
sum rgb( src, dst);
// afiseaza imaginea in fereastra creeata mai sus
cvShowImage( name, dst );
// asteapta sa fie apasata tasta ‘‘ESC’’
while( 1 ) { if( (cvWaitKey( 10 )&0x7f) == 27 ) break; }
// dezaloca spatiul folosit
cvDestroyWindow( name);
cvReleaseImage( &src );
cvReleaseImage( &dst );
36 CAPITOLUL 3. ANALIZA IMAGINILOR

}
În exemplul de mai sus se poate observa că valorile pentru r, g şi b nu
sunt adunate ı̂ntr-un vector pe 8 biţi deoarece este posibil ca suma să iasa
din domeniul de definiţie. De aceea, am folosit adunarea cu ponderi egale
a celor trei canale de culoare prin intermediul funcţiei cvAddWeighted().
Apoi, rezultatele sunt trunchiate la valoarea 100. Functia cvThreshold()
se poate aplica numai imaginilor sursă pe 8 biţi sau ı̂n virgula mobilă dar cu
niveluri de gri. Imaginea destinaţie trebuie să fie de acelaşi tip cu imaginea
sursă sau o imagine pe 8 biţi. De fapt, cvThreshold() permite ca imaginea
sursă şi cea destinaţie să fie identice.
Pentru segmentarea cu prag adaptiv, ı̂n OpenCv exista funcţia numită
cvAdaptiveThreshold() ı̂n care pragul este variabil:
void cvAdaptiveThreshold(
CvArr* src,
CvArr* dst,
double max val,
int adaptive method = CV ADAPTIVE THRESH MEAN C
int threshold type = CV THRESH BINARY,
int block size = 3,
double param1 = 5 );
Funcţia cvAdaptiveThreshold permite două tipuri diferite de segmen-
tare adaptivă care depind de setarea adaptive method. În ambele cazuri,
pragul adaptiv T (x, y) este ales calculând o medie ponderată a pixelilor
dintr-o vecinatate b × b din jurul pixelului central minus o constantă, unde b
este dat de către parametrul block size, iar constanta este dată de param1.
Dacă metoda aleasă este CV ADAPTIVE THRESH MEAN C atunci toţi pixelii din
vecinătate au ponderi egale. Dacă metoda este CV ADAPTIVE THRESH GAUSSIAN C
atunci pixelii din vecinătate au ponderi gaussiene. Parametrul threshold type
poate avea aceleaşi valori ca pentru cvThreshold() din tabelul 3.1.
Metoda segmentării cu prag adaptiv este utilă atunci când există gradienţi
puternici datorită iluminării sau unor reflexii extreme care trebuie să nu
influenţeze rezultatul segmentării. Această funcţie se poate aplica numai
imaginilor cu un singur canal pe 8 biţi sau ı̂n virgulă mobilă şi trebuie să
aibă imaginea sursă diferită de cea destinaţie.
Un exemplu pentru evidenţierea diferenţelor dintre cvAdaptiveThreshold()
şi cvThreshold() este aratat ı̂n exemplul de mai jos:
#include <cv.h>
#include <highgui.h>
#include <math.h>
IplImage *Igray=0,*It = 0, *Iat;
int main()
{
//setarile pragurilor
double threshold = (double)15;
int threshold type = 1 ?
3.1. SEGMENTARE 37

CV THRESH BINARY : CV THRESH BINARY INV;


int adaptive method = 1 ?
CV ADAPTIVE THRESH MEAN C : CV ADAPTIVE THRESH GAUSSIAN C;
int block size = 71;
double offset = 15;
//imaginea se citeste grayscale
if(( Igray = cvLoadImage( "right14.jpg",
CV LOAD IMAGE GRAYSCALE)) == 0){
return -1;
// se creeaza imaginile de iesire to grayscale
It = cvCreateImage(cvSize(Igray->width,Igray->height),
IPL DEPTH 8U, 1);
Iat = cvCreateImage(cvSize(Igray->width,Igray->height),
IPL DEPTH 8U, 1);
//segmentarea
cvThreshold(Igray,It,threshold,255,threshold type);
cvAdaptiveThreshold(Igray, Iat, 255, adaptive method,
threshold type, block size, offset);
//se creeaza trei ferestre
cvNamedWindow("Raw",1);
cvNamedWindow("Threshold",1);
cvNamedWindow("Adaptive Threshold",1);
//afisarea rezultatelor
cvShowImage("Raw",Igray);
cvShowImage("Threshold",It);
cvShowImage("Adaptive Threshold",Iat);
cvWaitKey(0);
//stergerea memoriei alocate
cvReleaseImage(&Igray);
cvReleaseImage(&It);
cvReleaseImage(&Iat);
cvDestroyWindow("Raw");
cvDestroyWindow("Threshold");
cvDestroyWindow("Adaptive Threshold");
return(0);
}
38 CAPITOLUL 3. ANALIZA IMAGINILOR

3.1.2 Creşterea regiunilor


Un algoritm des utilizat pentru segmentare este cel de creştere a regiunilor.
În OpenCv este implementată o variantă de creştere a regiunilor denumită
FloodFill, ce a fost introdusă ı̂n [5]. Algoritmul FloodFill porneşte de la un
punct de interes denumit sămânţă sau germene şi inspectează toţi vecini.
Dacă un vecin respectă condiţia de similaritate, atunci este el inclus ı̂n re-
giune; mai precis un pixel v este inclus ı̂n regiune, dacă ı̂n vecinătatea lui
există un pixel v0 care să fie deja ı̂n regiune şi să se respecte condiţia:

v0 − dlw ≤ v ≤ v0 − dup (3.1)

Prototipul funcţiei este:


void cvFloodFill (
IplImage* img,
CvPoint seedPoint,
double newVal,
double loDiff,
double upDiff,
CvConnectedComp* comp,
int connectivity=4);
unde semnificaţia parametrilor este:

• img - imaginea de intrare ce va fi desenată după aplicarea funcţiei;

• seedPoint - coordonatele sămănţei ı̂n interiorul regiunii de interes;

• newVal - valoarea utilizată pentru re-umplerea imaginii de ieşire;

• loDiff - diferenţa maximală, de jos, permisă, ı̂ntre valorile pixelului


ce aparţine zonei re-desenate şi a unui pixel adiacent (dlw din ecuătia
(3.1) );

• upDiff - diferenţa maximală, de sus, permisă, ı̂ntre valorile pixelului


ce aparţine zonei re-desenată şi a unui pixel adiacent ce este interogat,
(dup din ecuătia (3.1) ) ;

• comp - pointer la structura ce va conţine informaţii despre operaţia de


umplere;

• connectivity - tipul de connectivitate utilizat ı̂n funcţie. Dacă este


4 (valoare implicită) atunci funcţia testează patru vecini ai pixelului
curent, altfel testeaza toţi cei 8 vecini;

3.1.3 Segmentare piramidală


În analiza imaginilor, de obicei pentru accelerarea algoritmilor, se folosesc
piramide de imaginii, ı̂n care vârful are o rezoluţie minimală şi pe măsură ce
se coboară creşte rezoluţia. În practică se folosesc două tipuri de piramide
Gaussiană (pentru a scădea rezoluţia) şi Laplaciană pentru a o creşte.
3.1. SEGMENTARE 39

Un nivel dintr-o piramidă Gaussiană presupune convoluţia imaginii sursă


cu un nucleu Gaussian şi renunţarea apoi la liniile şi coloanele pare, ceea
ce produce o imagine cu rezoluţia la un sfert din cea a imaginii originală.
Funcţia pentru a genera cu o versiune de rezoluţie mai redusă dintr-o imagine
(adică implementând un nivel dintr-o piramidă Gaussiană) este:
void cvPyrDown(
IplImage* src,
IplImage* dst,
IplFilter filter = IPL GAUSSIAN 5x5);
unde src este pointer la imaginea sursă, dst la cea destinaţie, iar filter
este filtrul utilizat pentru convoluţie; momentan doar IPL GAUSSIAN 5x5
este suportat.
Operaţia ı̂n sens invers (dar care nu este opusă ı̂n sens matematic) se
realizează cu funcţia:
void cvPyrUp (
IplImage* src,
IplImage* dst,
IplFilter filter=IPL GAUSSIAN 5x5);
Operaţia de up-sampling se realizează injectând zerouri ı̂ntre liniile şi
coloanele existente şi apoi aplicănd un nucleu Gaussian care amplifică şi
energia de patru ori.
Utilizând descompunerea unei imagini ı̂n nivele piramidale se poate re-
aliza segmentarea ei conform metodei descrise ı̂n [2]. Acest lucru este rea-
lizat ı̂n OpenCv de către funcţia cvPyrSegmentation() . În cadrul acestei
funcţii se construieşte piramida până la nivelul specificat de level. Legătura
ı̂ntre orice pixel a pe nivelul i şi părintele său candidat b pe nivelul adiacent
este stabilită dacă:

ρ(c(a), c(b)) < threshold1 (3.2)


După ce componentele conectate sunt stabilite, ele sunt atribuite unor
clustere (grupuri). Orice două segmente A şi B sunt ı̂n acelaşi cluster dacă:

ρ(c(A), c(B)) < threshold2 (3.3)

Dacă imaginea de intrare este cu niveluri de gri, atunci funcţia ρ este:

ρ(c1 , c2 ) = |c1 − c2 | (3.4)


Dacă imaginea are trei canale atunci:

ρ(c1 , c2 ) = 0.3|cr1 − cr2 | + 0.59|cg1 − cg2 | + 0.11|cb1 − cb2 | (3.5)

Funcţia care implementează această segmetare este:


void cvPyrSegmentation (
IplImage* srcImage,
IplImage* dstImage,
CvMemStorage* storage,
40 CAPITOLUL 3. ANALIZA IMAGINILOR

CvSeq** comp,
int level,
double threshold1,
double threshold2);
unde storage stochează rezultatele secvenţei de componente conectate,
la care pointează comp.

3.1.4 Algoritmul Watershed


Algoritmul Watershed introdus ı̂n [6] utilizează escrierea topografică a ima-
ginilor transformând contururile ı̂n zone muntoase, de demarcaţie şi zonele
uniforme ı̂n arii inundabile, arii care se vor identifica. Algoritmul de Water-
shed permite unui utilizator sau unui alt algoritm să specifice părţi ale unui
obiect sau ale fundalului. Algoritmul de Watershed va grupa aceste puncte
ı̂mpreună, pentru ca ulterior să segmenteze imaginea, tinând cond de zonele
pre-marcate.
Prototipul funcţiei este :
void cvWatershed(
const CvArr* image,
CvArr* markers );
unde image este o imagine color pe 8 biţi color (trei canale) iar markers
este o imagine de ı̂ntregi unidimensional de tip IPL DEPTH 32S cu aceleaşi
coodonate (x, y) ca şi imaginea originală; valoarea acestor markeri este 0
peste tot, mai puţin acolo unde utilizatorul (sau un alt algoritm) a indicat
zone de interes atribuind valori pozitive.
Bibliografie

[1] Opencv 2.0 c reference. on-line (2009)

[2] Antonisse, H.J.: Image segmentation in pyramids. Computer Graphics


and Image Processing 19, 367–383 (1982)

[3] Bradski, G., Kaehler, A.: Learning OpenCV. OReilly Media, Inc (2008)

[4] Canny, J.: A computational approach to edge detection. IEEE Transac-


tions on Pattern Analysis and Machine Intelligence 8, 679–714 (1986)

[5] Heckbert, P.: A Seed Fill Algorithm. (Graphics Gems I), New York:
Academic Press (1990)

[6] Meyer, F.: Color image segmentation. In: 303-306 (ed.) Proceedings of
the International Conference on Image Processing and Its Applications
(1992)

[7] Serra, J.: Image Analysis and Mathematical Morphology. Academic


(1982)

[8] Tomasi, C., Manduchi, R.: Bilateral filtering for gray and color images.
on-line (2009)

41

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