Sunteți pe pagina 1din 82

Sisteme de Vedere Artificială

Îndrumar de Laborator
http://rovis.unitbv.ro

Sorin M. Grigorescu, Gigel Măces, anu


Tiberiu T. Cocias,

Analiza ‫܈‬i Prelucrarea Informa‫܊‬iilor Vizuale

Control
robotic

Imagine
Segmentarea
A Estimarea Estimarea Estimare
Achizi‫܊‬ie ‫܈‬i
Geometriei Mi‫܈‬cării Volumetrică
Imagini Imagine Clasificarea
Scenei Camerei 3D
Obiectelor
B

Informa‫܊‬ie de reac‫܊‬ie

Editura Universităt, ii Transilvania


Bras, ov, 2013
EDITURA UNIVERSITĂŢII TRANSILVANIA DIN BRAŞOV
Adresa: 500091 Braşov,
B-dul Iuliu Maniu 41A
Tel:0268 – 476050
Fax: 0268 476051
E-mail : editura@unitbv.ro

Copyright  Autorii, 2013

Editură acreditată de CNCSIS


Adresa nr.1615 din 29 mai 2002

Referenţi ştiinţifici: Prof. univ. dr. ing. Florin MOLDOVEANU


Prof. univ. dr. ing. Claudiu POZNA

Descrierea CIP a Bibliotecii Naţionale a României


GRIGORESCU, SORIN MIHAI
Sisteme de vedere artificială : îndrumar de laborator / Sorin Mihai
Grigorescu, Gigel Măceşanu, Tiberiu Teodor Cociaş. - Braşov : Editura
Universităţii "Transilvania", 2013
Bibliogr.
ISBN 978-606-19-0240-8
I. Măceşanu, Gigel
II. Cociaş, Tiberiu Teodor
621.397.42
Prefat, ă

Această carte tratează problematica sistemelor de vedere artificială utilizate, cu precădere,


ı̂n scopul prelucrării s, i analizei informaţiilor vizuale achizit, ionate cu ajutorul camerelor
video sau prin senzori de lumină structurată. O cerinţă strict necesară ı̂n acest domeniu
este recunoaşterea precisă a obiectelor din imaginile achiziţionate, extragerea proprietăţiilor
obiectelor şi, având la bază datele extrase, reconstrucţia 3D, cât s, i urmărirea formelor geo-
metrice.
Îndrumarul de fat, ă se adresează ı̂n special student, ilor sect, iilor de Automatică s, i Infor-
matică Tehnică s, i Robotică, care urmează cursul Sisteme de Vedere Artificială, dar s, i acelora
care doresc să se familiarizeze cu metodele şi abordările de proiectare a unor asemenea sis-
teme. În prima parte a cărt, ii sunt tratate not, iunile fundamentale de programare a aplicat, iilor
de vedere artificială, utilizându-se mediul de dezvoltare MS Visual C++. Primele labora-
toare sunt destinate introducerii ı̂n domeniul analizei formelor s, i prelucării imaginilor 2D,
prin metode precum conversia s, i filtrarea imaginilor, segmentarea obiectelor prin partit, ionare
sau detectarea cantelor.
Analiza imaginilor achizit, ionate cu ajutorul camerelor stereo este tratată din perspectiva
determinării corespondent, elor din imagini, operat, ie urmată de reconstruct, ia 3D a punctelor
corespondente. De asemenea, manipularea datelor 3D, ı̂n general achizit, ionate prin senzori
de lumină structurată, este prezentată pe parcursul a trei laboratoare ı̂n care se expun
algoritmii de potrivire s, i segmentare a norilor de puncte 3D.
Partea finală a lucrării de fat, ă este dedicată algoritmilor de clasificare a datelor s, i de
urmărire a obiectelor de interes ı̂n secvent, e video. Astfel, clasificarea informat, iilor vizuale
este exemplificată printr-un sistem de recunoas, tere a fet, elor ı̂n imagini, urmat de un laborator
de urmărire a formelor utilizându-se estimatoare de stare.
Autorii aduc pe această cale mult, umiri domnilor profesori Florin Moldoveanu s, i Claudiu
Pozna, referent, ii s, tiint, ifici ai prezentei lucrări, care, prin citirea atentă a manuscrisului s, i
prin observat, iile s, i sugestiile făcute, au contribuit la aducerea ı̂ndrumarului la forma pe care
autorii o prezintă cititorilor.
De asemenea, mult, umim membrilor s, i student, ilor grupului de cercetare Robust Vision
and Control Laboratory (ROVIS) http://rovis.unitbv.ro, din care fac parte s, i autorii
manualului, pentru sprijinul acordat de-a lungul ultimilor ani.

Bras, ov, Martie 2013 Sorin M. Grigorescu


Gigel Măces, anu
Tiberiu T. Cocias,
Cuprins

1 Proiectarea unei aplicaţii de vedere artificială 3


1.1 Instalarea librăriei OpenCV . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2 Mediul de programare MS Visual C++ . . . . . . . . . . . . . . . . . . . . . 5
1.3 Configurarea unui proiect ı̂n MS Visual C++ . . . . . . . . . . . . . . . . . 5
1.4 Cerinţe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.5 Codul sursă pentru ı̂ncărcarea şi afişarea unei imagini . . . . . . . . . . . . . 13
1.6 Descrierea funcţiilor principale . . . . . . . . . . . . . . . . . . . . . . . . . . 14

2 Manipularea imaginilor 15
2.1 Baze teoretice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.1.1 Reprezentarea imaginilor . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.1.2 Filtrarea imaginilor . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.2 Cerinţe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.3 Codul sursă al aplicaţiei . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.4 Descrierea funcţiilor principale . . . . . . . . . . . . . . . . . . . . . . . . . . 19

3 Segmentarea prin partiţionare 21


3.1 Baze teoretice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.1.1 Histograma unei imagini . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.1.2 Segmentarea prin partiţionare . . . . . . . . . . . . . . . . . . . . . . 21
3.1.3 Extragerea de contururi . . . . . . . . . . . . . . . . . . . . . . . . . 22
3.2 Cerinţe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.3 Codul sursă al aplicaţiei . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.4 Descrierea funcţiilor principale . . . . . . . . . . . . . . . . . . . . . . . . . . 26

4 Detectarea cantelor 29
4.1 Baze teoretice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
4.1.1 Calculul gradientului ı̂ntr-o imagine . . . . . . . . . . . . . . . . . . . 29
4.1.2 Detectorul de cante Canny . . . . . . . . . . . . . . . . . . . . . . . . 30
4.1.3 Transformata Hough . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
4.2 Cerint, e . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
4.3 Codul sursă al aplicat, iei . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
4.4 Descrierea funct, iilor principale . . . . . . . . . . . . . . . . . . . . . . . . . . 34

5 Corespondenţe stereo şi reconstrucţia 3D a unei scenei 37


5.1 Baze teoretice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
5.1.1 Detectorul de colt, uri Harris . . . . . . . . . . . . . . . . . . . . . . . 37
5.1.2 Reconstruct, ia 3D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
5.2 Cerint, e . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
5.3 Codul sursă al aplicat, iei . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
5.4 Descrierea funct, iilor principale . . . . . . . . . . . . . . . . . . . . . . . . . . 42
CUPRINS 1

6 Procesarea datelor RGB-D 43


6.1 Baze teoretice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
6.2 Cerinţe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
6.3 Codul sursă al aplicat, iei . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
6.4 Descrierea funcţiilor principale . . . . . . . . . . . . . . . . . . . . . . . . . . 47

7 Alinierea robustă a densităţilor de puncte 3D 49


7.1 Baze teoretice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
7.1.1 Măsurarea distanţei dintre diferite date geometrice . . . . . . . . . . 50
7.1.2 Estimarea rotaţiei şi a translaţiei optime ı̂ntre nori de puncte . . . . . 50
7.1.3 Prezentarea generală a algoritmului ICP . . . . . . . . . . . . . . . . 51
7.1.4 Alinierea parţială şi globală a formelor utilizându-se ICP . . . . . . . 51
7.2 Cerinţe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
7.3 Codul sursă al aplicaţiei . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
7.4 Descrierea funcţiilor principale . . . . . . . . . . . . . . . . . . . . . . . . . . 55

8 Segmentarea prin partiţionare a norilor de puncte 57


8.1 Baze teoretice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
8.1.1 Identificarea suprafeţelor plane din scena de lucru . . . . . . . . . . . 57
8.1.2 Segmentarea prin partiţionare a datelor RGB-D . . . . . . . . . . . . 58
8.2 Cerinţe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
8.3 Codul sursă al aplicaţiei . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
8.4 Descriere codului sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62

9 Detectarea feţelor ı̂n imagini 65


9.1 Baze teoretice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
9.2 Cerinţe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
9.3 Codul sursă al aplicat, iei . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
9.4 Descriere codului sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67

10 Urmărirea formelor 69
10.1 Baze teoretice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
10.1.1 Estimatori de stare şi urmărirea formelor . . . . . . . . . . . . . . . . 69
10.1.2 Filtrul Kalman . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
10.2 Cerinţe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
10.3 Codul sursă al aplicat, iei . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
10.4 Descrierea funct, iilor principale . . . . . . . . . . . . . . . . . . . . . . . . . . 75

Bibliografie 77
2 CUPRINS
1. Proiectarea unei aplicaţii de vedere
artificială

Librăria de vedere artificială Open Computer Vision (OpenCV)


Configurarea unui proiect bazat pe OpenCV
Citirea şi afişarea imaginilor

Scopul acestui laborator este acela de a se introduce principalele elementele ale librăriei
OpenCV, dintre acestea amintind: citirea, afişarea sau salvarea imaginilor. Primii paşi ı̂n
dezvoltarea unei aplicaţii care are la bază librăria amintită sunt aceia de instalare a librăriei
şi de configurare a unui proiect ı̂ntr-un mediu de dezvoltare software (IDE) (de ex. MS
Visual Studio, Eclipse). Pe parcursul laboratoarelor prezentate ı̂n acest ı̂ndrumar se va
folosi sistemul Microsoft Visual C++ 2010.

1.1 Instalarea librăriei OpenCV


OpenCV este o librărie open source destinată dezvoltării aplicaţiilor de vedere artificială.
Datorită licenţei BSD, librăria poate fi utilizată atât pentru aplicaţii academice, cât şi pentru
sisteme comerciale. Ultimele versiuni ale librăriei se găsesc la adresa www.opencv.org.
Pagina de Download a site-ului librăriei pune la dispoziţia utilizatorilor diferite versiuni
de OpenCV, specifice diferitelor platforme de operare, precum Linux, Unix, Mac, iOS, sau
Windows. Arhiva descărcată conţine, de obicei, un folder denumit ı̂n funcţie de versiunea
librăriei, spre exemplu OpenCV 2.43, ı̂n interiorul căruia se găsesc o serie de directoare,
prezentate ı̂n Fig. 1.1. Dintre acestea, amintim directorul include, ı̂n care se află fişierele
care vor fi incluse ı̂n proiecte; directorul modules care conţine fişierele sursă ale librăriei;
directorul doc ı̂n care se regăseşte documentaţia specifică librăriei; directorul samples ı̂n
care se găsesc exemple de programe pentru lucrul cu librăria.
În situaţia ı̂n care este utilizat sistemul de operare Windows, ı̂mpreună cu mediul de
programare Visual Studio C++, există posibilitatea de a se descărca un program executabil
de instalare automată a librăriei OpenCV.
Începând cu versiunea 2.2, librăria OpenCV este divizată ı̂n mai multe module, compilate
ca librării separate, ı̂n directorul lib. Aceste module sunt:
ˆ opencv core, care conţine funcţionalităţile de bază ale librăriei, mai exact structurile
de date şi funcţiile aritmetice;
ˆ opencv imgproc, ı̂n care sunt stocate principalele funcţii de procesare a imaginilor;
ˆ opencv highgui, utilizat pentru citirea şi salvarea imaginilor, cât şi a fişierelor video,
ı̂mpreună cu o serie de funcţii destinate creării de interfeţe cu utilizatorul;
ˆ opencv features2d, conţine detectoarele şi descriptoarele de puncte cheie, precum şi
metodele de potrivire 1 dintre aceste puncte;
1
Eng. Matching
4 PROIECTAREA UNEI APLICAŢII DE VEDERE ARTIFICIALĂ

Fig. 1.1 Structura de directoare a librăriei OpenCV.

opencv calib3d, dezvoltat pentru calibrarea camerelor şi estimarea geometriei scenelor,
prin utilizarea de camere stereo;
opencv video, utilizat pentru estimarea mişcării şi urmărirea formelor;
opencv objdetect, care conţine funcţii pentru detectarea obiectelor, precum şi re-
cunoaşterea persoanelor, respectiv a feţelor;
opencv ml, ı̂n acest modul se găsesc algoritmii de inteligenţă artificială;
opencv flann, este utilizat pentru implementarea metodelor de calcul geometric (ex.
determinarea celui mai apropiat vecin ı̂n spaţiul 3D);
opencv gpu, necesar stocării funcţiilor implementate pe structuri de calcul paralel 2 ;
opencv legacy, utilizat pentru a se realiza o compatibilizare a noilor versiuni cu vechile
variante ale librăriei OpenCV.
Fiecare dintre modulele menţionate anterior au câte un fişier header asociat, localizat
ı̂n directorul include. În mod tipic, un program ı̂n OpenCV va ı̂ncepe prin includerea
modulelor necesare aplicaţiei, spre exemplu:
1 #include <opencv2 / core / core . hpp>
2 #include <opencv2 / imgproc / imgproc . hpp>
3 #include <opencv2 / highgui / highgui . hpp>
Un program OpenCV ce ı̂ncepe cu header-ul:
1 #include "cv.h"
reprezintă o aplicaţie dezvoltată cu o versiune veche a librăriei.
Versiunea cea mai recentă a codului librăriei OpenCV poate fi descărcată, utilizându-
se sistemul de management al codului sursă GIT, de la adresa git://code.opencv.org/
opencv.git
2
Eng. Graphical Processing Unit
Mediul de programare MS Visual C++ 5

1.2 Mediul de programare MS Visual C++


În sistemul de operare Windows se pot crea uşor aplicaţii care folosesc librăria OpenCV,
prin utilizarea mediului de programare MS Visual C++. Se pot crea atât aplicaţii simple,
de consolă, cât şi aplicaţii care utilizează interfeţe cu utilizatorul (GUI). De-a lungul acestui
ı̂ndrumar vor fi create doar aplicaţii tip consolă, ı̂n mediul Visual Studio 2010. Cu toate
acestea, aceleaşi principii se pot aplica oricărei versiuni a mediului MS Visual Studio.
La prima lansare a programului Visual Studio, se poate seta mediul de programare default
ca fiind C++. Astfel, Visual Studio va porni de fiecare dată ı̂n modul C++. Vom considera
ca aţi instalat librăria OpenCV ı̂n directorul C:\OpenCV2.4, aşa cum s-a explicat ı̂n secţiunea
anterioară.
În Visual Studio este important să se ı̂nţeleagă diferenţa dintre o soluţie şi un proiect.
O soluţie este compusă din mai multe proiecte. Spre exemplu, un proiect este un modul
software distinct (program sau librărie). Într-o soluţie, diferite proiecte pot ı̂mpărţii fişiere
şi librării. De obicei se crează un director principal pentru soluţie, care conţine directoarele
fiecărui proiect.
De asemenea, un proiect Visual C++ se poate compila şi executa ı̂n două configuraţii:
Debug şi Release. Modul Debug este utilizat pentru analiza erorilor din codul sursă sau
determinarea scăpărilor de memorie. Cu toate astea, modul Debug generează programe care
se execută ı̂ntr-un interval de timp mai mare. Astfel, după ce aplicaţia a fost testată, ea
poate fi compilată ı̂n versiunea Release, versiune ce va fi distribuită ulterior utilizatorilor.
Modurile Debug şi Release nu sunt specifice doar mediului MS Visual C++, ci majorităţii
sistemelor de dezvoltare a aplicaţiilor software.

1.3 Configurarea unui proiect ı̂n MS Visual C++


Un proiect nou ı̂n MS Visual C++ se crează utilizând opţiunea File|New Project din
meniul utilizator. Se va selecta opţiunea Win32 Console Application, aşa cum este ilustrat
ı̂n Fig. 1.2.
În acest moment se specifică locaţia unde se va salva proiectul, cât şi numele său. Există
şi opţiunea de a se crea un director pentru proiect ı̂n soluţie. Apăsând OK, se vor afişa
setările, cum poate fi văzut ı̂n Fig. 1.3. Se va selecta un proiect gol (empty project).
Opţiunea specifică MS Visual Studio Precompiled header trebuie să fie deselectată.
Această opţiune face procesul de compilare mai rapid. Deoarece se doreşte utilizarea stan-
dardului ANSI C++, nu vom utiliza headere precompilate. Proiectul va fi creat apăsând
butonul Finish, urmând să adăugăm codul sursă ı̂ntr-un fişier main.cpp.
Pentru a se putea compila şi rula aplicaţii utilizând librăria OpenCV, este necesară
setarea căii mediului Visual C++ către locaţia unde se găsesc librăriile OpenCV şi fişierele
de tip include. Deoarece se vor crea o serie de proiecte care au la bază OpenCV, cea
mai bună opţiune de configurare este aceea de a se crea o foaie de proprietăţi 3 care va
putea fi reutilizată ı̂n fiecare proiect. Acest lucru este posibil prin utilizarea managerului
de proprietăţi (Property Manager), prezentat ı̂n Fig. 1.4. Dacă nu este vizibil, el poate fi
accesat cu ajutorul meniului View.
În Visual Studio C++ 2010, o foaie de proprietăţi este un fişier de tip XML care descrie
setările unui proiect. După cum se poate vedea ı̂n Fig. 1.5, acest fişier se poate crea apăsând
click-dreapta pe nodul Debug|Win32 din proiect şi selectându-se opţiunea Add New Project
Property Sheet.
Noua foaie de proprietăţi este adăugată odată ce este apăsat butonul Add, urmând ca
ea să fie editată ulterior. Următorul pas este acela de a se realiza un dublu-click pe numele
3
Eng. Property Sheet
6 PROIECTAREA UNEI APLICAŢII DE VEDERE ARTIFICIALĂ

Fig. 1.2 Crearea unui proiect nou ı̂n MS Visual Studio C++ 2010.

Fig. 1.3 Setările unui nou proiect MS Visual C++ 2010.


Configurarea unui proiect ı̂n MS Visual C++ 7

Fig. 1.4 Managerul de proprietăţi din MS Visual Studio C++ 2010.

foii de proprietăţi şi a se selecta opţiunea VC++ Directories, după cum este exemplificat
ı̂n Fig. 1.6.
Se editează câmpul Include Directories, accesibil din nodul VC++ Directories (v.
Fig. 1.7), prin adăugarea căilor către fişierele include din librăria OpenCV (v. Fig. 1.8).
Este necesară efectuarea aceleiaşi operaţii şi pentru câmpul Library Directories, prin
adăugarea căilor către fişierele de tip librărie din OpenCV (v. Fig. 1.9).
Este important de remarcat faptul că ı̂n foaia de proprietăţi setarea locaţiilor fişierelor
OpenCV a fost realizată prin căi explicite. În general, este cel mai indicat să se utilizeze vari-
abile de sistem 4 pentru a se desemna locaţia librăriei OpenCV. În acest fel, ı̂n cazul ı̂n care
se doreşte schimbarea versiunii librăriei (spre exemplu de la OpenCV 2.4 la OpenCV 2.5), nu
trebuie decât să setaţi variabilele care pointează către locaţia dorită. De asemenea, ı̂n cazul
dezvoltării de software ı̂n echipă, diferiţi utilizatori ı̂şi pot instala OpenCV ı̂n locaţii diferite.
Utilizându-se o variabilă de sistem, este evitată editarea foii de proprietăţi de către fiecare
utilizator ı̂n parte. În consecinţă, dacă este definită o variabila de sistem OPENCV DIR care
pointează către locaţia C:\OpenCV 2.4, atunci cele două directoare care trebuiesc specificate
ı̂n foaia de proprietăţi vor fi (OPENCV DIR)\include şi (OPENCV DIR)\lib.
Următorul pas este de a se specifica care fişiere ale librăriei OpenCV vor fi necesare
link-editării, ı̂mpreună cu codul sursă, pentru a se putea crea aplicaţia executabilă. Astfel,
vor fi necesare diferite module din OpenCV, ı̂n funcţie de aplicaţia de vedere artificială care
urmează a fi creată. Deoarece se doreşte utilizarea aceleiaşi foi de proprietăţi pentru toate

4
Eng. Environment Variables
8 PROIECTAREA UNEI APLICAŢII DE VEDERE ARTIFICIALĂ

Fig. 1.5 Selectarea opţiunii de adăugare a unei noi foi de proprietăţi.

proiectele, se vor adăuga acele librarii care vor fi utilizate de-a lungul lucrărilor din acest
ı̂ndrumar. După cum se poate vedea ı̂n Fig. 1.10, acest lucru este posibil din opţiunea Input
a nodului Linker.
Este necesară editarea câmpului Additional Dependencies (v. Fig. 1.11), prin adăugarea
modulelor opencv core, opencv imgproc, opencv highgui, opencv features2d şi opencv c
alib3d.
Se poate observa că la finalul numelor librăriilor este adăugată litera ”d”. Acestea
reprezintă librăriile pentru modul Debug. În situaţia ı̂n care este utilizat modul Release,
este necesară crearea unei noi foi de proprietăţi, aproape identică cu aceea de Debug (este uti-
lizată aceeaşi procedură), dar adăugată la nodul Release|Win32. În modul Release numele
librăriilor nu se mai termină cu litera ”d”.
În acest moment au fost introduse toate noţiunile necesare pentru a se crea, compila şi rula
prima aplicaţie de vedere artificială. Adăugarea unui nou fişier sursă poate fi realizată prin
utilizarea modulului Solution Explorer şi efectuarea unui click-dreapta pe nodul Source
Files. Este selectată opţiunea Add New Item, unde se specifică noul fişier sursă C++, cu
numele main.cpp, aşa cum este ilustrat ı̂n Fig. 1.12. Un nou fişier poate fi, de asemenea,
adăugat prin alegerea opţiunii File|New|File.
În Fig. 1.13 este prezentat codul sursă al unei aplicaţii care ı̂ncarcă şi afişează o imagine
de pe disc. Rezultatul execuţiei programului este afişat ı̂n Fig. 1.14.
Configurarea unui proiect ı̂n MS Visual C++ 9

Fig. 1.6 Adăugarea unei noi foi de proprietăţi.

Fig. 1.7 Nodul VC++ Directories.


10 PROIECTAREA UNEI APLICAŢII DE VEDERE ARTIFICIALĂ

Fig. 1.8 Adăugarea căilor către fişierele include din libraria OpenCV.

Fig. 1.9 Adăugarea căilor către fişierele librărie din OpenCV.


Configurarea unui proiect ı̂n MS Visual C++ 11

Fig.
g 1.10 Selectarea opţiunii
p¸ p al nodului Linker.
Input

Fig. 1.11 Adăugarea modulelor OpenCV necesare lucrărilor din prezentul ı̂ndrumar.
12 PROIECTAREA UNEI APLICAŢII DE VEDERE ARTIFICIALĂ

Fig. 1.12 Adăugarea fişierului sursă main.cpp.

Fig. 1.13 Editarea fişierului main.cpp prin adăugarea codului sursă.

1.4 Cerinţe
Să se realizeze citirea şi afişarea unei imagini de pe HDD.
Codul sursă pentru ı̂ncărcarea şi afişarea unei imagini 13

Fig. 1.14 Rezultatul executării aplicaţiei având codul sursă listat ı̂n Fig 1.13.

1.5 Codul sursă pentru ı̂ncărcarea şi afişarea unei imagini

1 # include <i o s t r e a m >


2 # include <opencv2 / c o r e / c o r e . hpp>
3 # include <opencv2 / h i g h g u i / h i g h g u i . hpp>
4
5 using namespace cv ;
6 using namespace std ;
7
8 int main ( int argc , char ** argv )
9 {
10 cout << "SVA Laborator 01: Incarcarea imaginilor in mediul OpenCV " ←
<< endl ;
11
12 // O b i e c t u l i m a g i n e
13 Mat imagine_in = cv : : imread ( "pcrai .jpg" ) ;
14
15 // V e r i f i c a r e a i n c a r c a r i i c o r e c t e a i m a g i n i i
16 if ( ! imagine_in . data )
17 {
18 cout << " Imaginea nu a putut fi incarcata " << endl ;
19 return −1;
20 }
21
22 // Creaza o f e r e a s t r a cu numele ” Imagine i n t r a r e ”
23 namedWindow ( " Imagine intrare " ) ;
24 // A f i s e a z a i m a g i n e a c i t i t a
25 imshow ( " Imagine intrare " , imagine_in ) ;
26 // Asteapta 10000 ms
27 waitKey ( 1 0 0 0 0 ) ;
28
14 PROIECTAREA UNEI APLICAŢII DE VEDERE ARTIFICIALĂ

29 return 0 ;
30 }
1.6 Descrierea funcţiilor principale

2 # include <opencv2 / c o r e / c o r e . hpp>


3 # include <opencv2 / h i g h g u i / h i g h g u i . hpp>
Declararea fişierelor de tip include OpenCV.
12 Mat imread ( const string& filename , int flags=1)

Încarcă o imagine de pe disc.


ˆ filename: numele fişierului imagine;
ˆ flags: indicator de ı̂ncărcare a tipului de imagine:
– CV LOAD IMAGE ANYDEPTH: ı̂ncarcă o imagine pe 16-biţi \32-biţi atunci când ima-
ginea corespunde acestor rezoluţii, altfel converteşte imaginea la 8-biţi;
– CV LOAD IMAGE COLOR: ı̂ntotdeauna ı̂ncarcă imaginea color;
– CV LOAD IMAGE GRAYSCALE: converteşte imaginea ı̂n niveluri de gri;
– < 0: ı̂ncarcă imaginea aşa cum este.
22 void namedWindow ( const string& winname , int flags=WINDOW_AUTOSIZE )
Crează o fereastră.
ˆ winname: numele ferestrei;
ˆ flags: indicator a tipului de fereastră:
– CV WINDOW AUTOSIZE: dimensiunea ferestrei este setată ı̂n funcţie de dimensiunea
imaginii.
24 void imshow ( const string& winname , InputArray mat )
Afişează o imagine ı̂ntr-o fereastră dată:
ˆ winname: numele ferestrei;
ˆ mat: imaginea de intrare.
26 int waitKey ( int delay=0)
Aşteaptă ca o tastă să fie apăsată:
ˆ delay: ı̂ntârzierea ı̂n milisecunde (0 reprezintă aşteptare infinită).
2. Manipularea imaginilor

Reprezentarea imaginilor
Accesarea pixelilor unei imagini
Conversia imaginilor şi spatii de culoare (Gri, RGB, HSV)
Filtrarea spatială a imaginilor (filtrul median, filtrul Gaussian)

În această aplicaţie se vor prezenta diferite forme de reprezentare a imaginilor, modalităţi
de reprezentare a culorilor, cât şi două metode de filtrare spat, ială a imaginilor, mai exact
filtrul median şi filtrul Gaussian.

2.1 Baze teoretice


2.1.1 Reprezentarea imaginilor
O imagine digitală poate fi reprezentată printr-o funcţie f (x, y), unde parametrii funcţiei
reprezintă coordonatele imaginii pe cele două direcţii ale lui 2 , aşa cum se poate vedea şi
ı̂n Fig. 2.1. O formă compactă de scriere a unei imagini digitale monocrome este dată sub
forma unei matrici ale cărei elemente sunt denumit, i pixeli [6]:
⎡ ⎤
f (0, 0) f (0, 1) ··· f (0, N − 1)
⎢ ⎥
⎢ f (1, 0) f (1, 1) ··· f (1, N − 1) ⎥

f (x, y) = ⎢ ⎥, (2.1)
... ... ... ... ⎥
⎣ ⎦
f (M − 1, 0) f (M − 1, 1) · · · f (M − 1, N − 1)
unde valorile pe care le poate lua f (x, y) aparţin unui domeniu finit:

0 ≤ f (x, y) ≤ L − 1. (2.2)
Valoarea lui L este, ı̂n general, 256 pentru imagini gri. Acest proces de reprezentare a
imaginilor, denumit eşantionare, este exemplificat ı̂n Fig. 2.2 pentru cazul unei imagini de
nivel gri definită pe 8 biţi.
În cazul imaginilor color, f (x, y) va conţine cele trei culori fundamentale (Roşu, Albastru
şi Verde), ea putând fi reprezentată matematic ı̂n două forme:
– prin intercalarea pixelilor, unde fiecare linie este o matrice 2D, cu fiecare element
reprezentând o listă cu trei valori;
– prin intercalarea culorilor, unde pe fiecare linie datele sunt separate ı̂n matrici 2D, câte
una pentru fiecare canal de culoare:

fRGB (x, y) = fr (x, y), fg (x, y), fb (x, y) . (2.3)

Pentru a se putea realiza o standardizare a culorilor a fost introdusă noţiunea de model al


culorilor [6]. Un astfel de model poate fi orientat spre hardware (monitoare sau imprimate)
sau spre aplicaţii software, unde scopul final este acela de manipulare a culorilor. Cel mai
16 MANIPULAREA IMAGINILOR

Originea imaginii
0 1 2 3 N-1
0 Y

{
1
2
3

Pixelii
imaginii

M-1
f (x,y)
X

Fig. 2.1 Coordonatele unei imagini digitale f (x, y).

Fig. 2.2 Reprezentarea unei imagini de nivel gri prin eşantionare.

utilizat model al culorilor, din categoria orientată spre hardware, este modelul RGB (Red,
Green, Blue). Acest model este utilizat ı̂n special la monitoarele color dar şi la o clasă largă
de camere video. Reprezentarea imaginilor se poate realiza şi prin alte modele de culori,
dintre care se pot aminti: HSV (Hue, Saturation, Value), CMY (Cyan, Magenta, Yellow ),
sau Lab. Dintre acestea, modelul HSV este un model de reprezentare ce se aseamănă cu
modul de vedere uman [6], iar modelul CMY este utilizat manipularea datelor ı̂n imprimante
color.

2.1.2 Filtrarea imaginilor


Filtrarea imaginilor este folosită pentru a se reduce zgomotul din imaginile de intrare,
fiind definită ı̂n domeniul spaţial ca o operaţie de convoluţie:

g(x, y) = f (x, y) ∗ w(x, y), (2.4)


unde f (x, y) este imaginea de intrare, g(x, y) imaginea de ieşire, iar w o funcţie fereastră,
sau mască, aplicată tuturor pixelilor din imaginea de intrare.
Cerinţe 17

Fig. 2.3 Reprezentarea operat, iei de filtrare spat, ială a unei imagini.

Filtrul median este reprezentat de acea mască ı̂n care toţi coeficienţii sunt egali:
⎡ ⎤
1/9 1/9 1/9
⎢1/9 1/9 1/9⎥
w(x, y) = ⎣ ⎦. (2.5)
1/9 1/9 1/9

2.2 Cerinţe
1. Să se ı̂ncarce şi să se afişeze o imagine color;
2. Să se convertească imaginea color ı̂ntr-o imagine gri;
3. Să se convertească imaginea color ı̂n spaţiul de culoare HSV;

Fig. 2.4 Filtrarea unei imagini utilizând o mască de dimensiune 5x5.


18 MANIPULAREA IMAGINILOR

4. Să se acceseze un pixel, respectiv o regiune, din imagine;


5. Să se aplice un filtru median asupra imaginii.

2.3 Codul sursă al aplicaţiei

1 # include <i o s t r e a m >


2 # include <opencv2 / c o r e / c o r e . hpp>
3 # include <opencv2 / h i g h g u i / h i g h g u i . hpp>
4 # include <opencv2 / imgproc / imgproc . hpp>
5
6 using namespace cv ;
7 using namespace std ;
8
9 int main ( int argc , char ** argv )
10 {
11 cout << "SVA Laborator 02: Manipularea imaginilor " << endl ;
12
13 Mat img_in , img_out ;
14 string strImgPath ;
15
16 // I n c a r c a r e a i m a g i n i i de pe d i s k
17 if ( argc == 2 )
18 strImgPath = argv [ 1 ] ;
19 else
20 strImgPath = "../ pcrai .jpg" ;
21
22 img_in = imread ( strImgPath . c_str ( ) , CV_LOAD_IMAGE_UNCHANGED ) ;
23
24 // V e r i f i c a r e a i n c a r c a r i i c o r e c t e a i m a g i n i i
25 if ( ! img_in . data )
26 {
27 cout << " Imaginea " << strImgPath << " nu a putut fi incarcata " ←
<< endl ;
28 return −1;
29 }
30
31 // C o n v e r s i a d i n i m a g i n e i n c u l o r i i n i m a g i n e g r i
32 cvtColor ( img_in , img_out , CV_RGB2GRAY ) ;
33 imshow ( " Culoare -> Gri" , img_out ) ;
34 waitKey ( ) ;
35 destroyAllWindows ( ) ;
36
37 // C o n v e r s i a d i n s p a t i u l de c u l o a r e RGB i n s p a t i u l HSV
38 cvtColor ( img_in , img_out , CV_RGB2HSV ) ;
39 imshow ( "RGB -> HSV" , img_out ) ;
40 waitKey ( ) ;
41 destroyAllWindows ( ) ;
42
43 // A c c e s a r e a p i x e l u l u i avand c o o r d o n a t e l e ( 1 0 , 1 0 )
44 Vec3b pxValue = img_in . at<Vec3b >(10 ,10) ;
45 cout << "(10 ,10): R = " <<
46 ( int ) pxValue [ 0 ] << " G = " <<
Descrierea funcţiilor principale 19

47 ( int ) pxValue [ 1 ] << " B = " <<


48 ( int ) pxValue [ 2 ] << endl ;
49
50 // A c c e s a r e a u n e i r e g i u n i de i n t e r e s d i n i m a g i n e
51 for ( int i = 1 0 0 ; i < 2 0 0 ; i++)
52 {
53 for ( int j = 5 0 ; j < 2 0 0 ; j++)
54 {
55 img_in . at<Vec3b >(j , i ) [ 0 ] = 2 5 5 ;
56 img_in . at<Vec3b >(j , i ) [ 1 ] = 2 5 5 ;
57 img_in . at<Vec3b >(j , i ) [ 2 ] = 2 5 5 ;
58 }
59 }
60
61 imshow ( " Regiune de interes " , img_in ) ;
62 waitKey ( ) ;
63 destroyAllWindows ( ) ;
64
65 // A p l i c a r e a unui f i l t r u median
66 medianBlur ( img_in , img_out , 5 ) ;
67 imshow ( " Imagine originala " , img_in ) ;
68 imshow ( " Imagine filtrata " , img_out ) ;
69 waitKey ( ) ;
70 destroyAllWindows ( ) ;
71
72 return 0 ;
73 }
2.4 Descrierea funcţiilor principale

32 void cvtColor ( InputArray src , OutputArray dst , int code )


Converteşte o imagine dintr-un spaţiu de culoare ı̂n altul.
ˆ src: imaginea de intrare;
ˆ dst: imaginea de ieşire;
ˆ code: codul conversiei de culoare:
– CV BGR2HSV, CV RGB2HSV, CV HSV2BGR, CV HSV2RGB;
– CV BGR2HLS, CV RGB2HLS, CV HLS2BGR, CV HLS2RGB;
– CV BGR2Lab, CV RGB2Lab, CV Lab2BGR, CV Lab2RGB.
66 void medianBlur ( InputArray src , OutputArray dst , int ksize )
Filtrarea unui imagini utilizându-se un filtru median.
ˆ src: imaginea de intrare;
ˆ dst: imaginea de ieşire;
ˆ ksize: dimensiunea ferestrei mască (trebuie sa fie un număr impar mai mare ca 1: 3,
5, 7, etc.).
20 MANIPULAREA IMAGINILOR
3. Segmentarea prin partiţionare

Histograma unei imagini gri


Segmentarea regiunilor de interes prin partiţionare histogramei
Extragerea contururilor dintr-o imagine binară

În acest laborator va fi prezentată o metodă de analiză a unei imagini gri, prin partiţionarea
histogramei. După ce operaţia de segmentare a fost aplicată, obiectele din imaginea binară
vor fi extrase folosindu-se analiza contururilor.

3.1 Baze teoretice


3.1.1 Histograma unei imagini
Considerându-se o imagine gri, unde L reprezintă numărul de niveluri de intensitate
(pentru o imagine cu 8 biţi, L are valoarea 255), histograma nivelelor de intensitate se
defineşte ca o funcţie h(g) ce are ca valoare numărul de pixeli din imagine (sau dintr-o
regiune) cu o intensitate g ∈ [0, 1, . . . , L]. Un exemplu de histograma a unei imagini este
prezentată ı̂n Fig. 3.1.

3.1.2 Segmentarea prin partiţionare


Tehnicile care au la bază segmentarea regiunilor din imagini au ca obiectiv principal
gruparea pixelilor ı̂n funcţie de proprietăţi comune ale imaginii, cum este cazul valorilor de
intensitate, textură, sau profile spectrale.
Cea mai populară metodă de segmentare a unei regiuni dintr-o imagine este partiţionarea 1
histogramei. Dacă valorile pixelilor dintr-o histogramă pot fi separate printr-o valoare globală
TG , atunci pixelii de fundal din imaginea binară de ieşire sunt reprezentaţi de acei pixeli din
imaginea de intrare care au o valoare mai mică decât TG . Pixelii obiect vor fi reprezentaţi de
aceia care au o valoare mai mare sau egală cu TG . În aceast ı̂ndrumar, valoarea de separaţie
a histogramei va fi denumită threshold, termen consacrat din limba engleză. Matematic,
operaţia de separaţie poate fi descrisă astfel:

1, if f (x, y) ≥ TG ,
tG (x, y) = (3.1)
0, if f (x, y) < TG ,

unde tG (x, y) reprezintă imaginea binară de ieşire. În Fig. 3.1 sunt exemplificaţi paşii
operaţiei de partiţionare prin regiuni a unei imagini gri.
O cerinţă ı̂n segmentarea imaginilor folosind doar un singur threshold este ca imaginea
de intrare să conţină un singur obiect vizualizat, pe fondul unui fundal uniform. Această

1
Eng. Thresholding
22 SEGMENTAREA PRIN PARTIŢIONARE

(a) (b) (c)

Fig. 3.1 Segmentarea unei imagini gri. (a) Imaginea de intrare. (b) Histograma imaginii de intrare.
(c) Rezultatul partiţionării imaginii de intrare prin valoarea de threshold TG = 42.

Fig. 3.2 Partiţionarea unei histograme printr-un interval de segmentare T = [Tlow , Thigh ].

problemă poate fi soluţionată prin definirea unui interval de partiţionare T = [Tlow , Thigh ]:

1, if f (x, y) ∈ T ,
t(x, y) = (3.2)
0, if f (x, y) ∈
/ T,
unde f (x, y) reprezintă valoarea unui pixel la coordonatele (x, y) din imagine. Tlow şi Thigh
sunt valorile minime şi maxime ale intervalului de partiţionare aplicat histogramei imaginii
f (x, y). Un exemplu de partiţionare a unei histograme printr-un interval de partiţionare este
ilustrat ı̂n Fig. 3.2.
O metodă automată de partiţionare a histogramei este aşa numitul threshold adaptiv,
care partiţionează imaginea având ı̂n vedere o ferestră glisantă, sau mască [6]. Valoarea
optimală de threshold Topt este calculată ı̂n funcţie de media aritmetica a valorilor pixelilor
din mască.

3.1.3 Extragerea de contururi


În funcţie de tipul segmentării, de regiune (partit, ionare) sau de detectare a cantelor,
obiectele dintr-o imagine binară pot fi reprezentate de mulţimi grupate 2 de pixeli obiect, ı̂n
cazul segmentării regiunilor, sau de pixeli de cante conectaţi, ı̂n cazul segmentării cantelor.
Principiul de bază al extragerii de contururi este ordonarea pixelilor de pe marginea obiec-
tului segmentat şi numerotarea lor ı̂n sens orar, sau anti-orar. Procedura mai este ı̂ntâlnită
şi sub denumirea de urmărirea marginilor 3 [6].
2
Eng. Blobs
3
Eng. Boundary (Border ) Following
Cerinţe 23

O metoda des ı̂ntâlnită ı̂n procesele de extragere a contururilor este aşa numita metodă
de codare a lanţurilor 4 . Prin codarea lanţurilor marginea unui obiect este descrisă de o
secvenţă conectată de segmente de linii drepte care au o direcţie şi o lungime specifică. De
obicei, metoda are la bază conectivitatea segmentelor dintre pixelii cu 4 sau 8 vecini. În
această reprezentare, denumita şi codare a lanţurilor tip Freeman 5 , direcţia fiecărui segment
este codată sub forma unei secvenţe de numere direcţionale, de la un pixel la următorul [6].
Un exemplu de codare a direcţiei bazată pe 8 vecini a obiectului sintetic din Fig. 3.3 este:

000060667764566444444242222202202

0 0 0 0
0 2 6 0
2 6
0 2 6
7
2
7
2
2 6
2 5 4
2 6
4 2 6
4 4 4 4 4 4

Fig. 3.3 Codarea directiei bazata pe 8 vecini a marginii unui obiect segmentat.
O asemenea margine digitală poate fi ulterior aproximată printr-un poligon. Obiectivul
aproximării poligonale este acela de a se transforma marginea codată extrasă ı̂ntr-o formă
care să descrie esenţa marginii obiectului cu cel mai mic număr de segmente posibil. O
metodă utilizată cu precădere ı̂n aproximarea poligonală presupune descrierea marginilor
unui obiect prin poligonul de perimetru minim 6 [6]. Din poligonul obţinut, un număr de
atribute pot fi extrase, ca de exemplu aria, perimetrul, diametrul, axa majoră şi axa minoră
ı̂mpreună cu excentricitatea (raportul dintre axele majoră şi minoră), curbura, etc.

3.2 Cerinţe
1. Să se ı̂ncarce şi să se convertească o imagine color ı̂ntr-una gri;
2. Să se calculeze histograma imaginii;
3. Să se segmenteze imaginea utilizându-se datele din histogramă;
4. Să se extragă contururile din imaginea segmentată;
5. Să se calculeze aria şi perimetrul contururilor detectate.

3.3 Codul sursă al aplicaţiei

1 # include <i o s t r e a m >


2 # include <opencv2 \ c o r e \ c o r e . hpp>
3 # include <opencv2 \ h i g h g u i \ h i g h g u i . hpp>
4 # include <opencv2 \ imgproc \ imgproc . hpp>
5
6 using namespace cv ;
4
Eng. Chain Code
5
Eng. Freeman Chain Code
6
Eng. Minimum-perimeter Polygon
24 SEGMENTAREA PRIN PARTIŢIONARE

7 using namespace std ;


8
9 int main ( int argc , char ** argv )
10 {
11 cout << "SVA Laborator 03: Utilizarea histogramelor si extragerea ←
de contururi " << endl ;
12
13 Mat matImg_in , matImg_out , matImgGray ;
14 string strImgPath ;
15
16 RNG rng ( 1 2 3 4 5 ) ;
17 vector< vector<Point> > contours ;
18 vector<Vec4i> hierarchy ;
19
20 // I n c a r c a r e a i m a g i n i i de pe d i s k
21 if ( argc >= 2 )
22 strImgPath = argv [ 1 ] ;
23 else
24 strImgPath = "Th.png" ;
25
26 matImg_in = imread ( strImgPath . c_str ( ) , CV_LOAD_IMAGE_UNCHANGED ) ;
27
28 // V e r i f i c a r e a i n c a r c a r i i c o r e c t e a i m a g i n i i
29 if ( matImg_in . empty ( ) )
30 {
31 cout << " Imaginea " << strImgPath << " nu a putut fi incarcata " ←
<< endl ;
32 return −1;
33 }
34
35 // C o n v e r s i a i m a g i n i i c o l o r i n t r −una g r i
36 cvtColor ( matImg_in , matImgGray , CV_RGB2GRAY ) ;
37 imshow ( " GrayImage " , matImgGray ) ;
38 waitKey ( ) ;
39
40 // Vector p e n t r u c o n t o r i z a r e a p i x e l i l o r
41 vector <int> vPixelsVector ;
42
43 // I n i t i a l i z a r e v e c t o r
44 for ( int i = 0 ; i < 2 5 6 ; i++)
45 vPixelsVector . push_back ( 0 ) ;
46
47 // Determinarea numarului de p i x e l i avand d i f e r i t e n i v e l e de g r i
48 for ( int i = 0 ; i < matImgGray . rows ; i++)
49 {
50 for ( int j = 0 ; j < matImgGray . cols ; j++)
51 {
52 unsigned char ucPixelValue = matImgGray . at<unsigned char >(i , j ) ;
53 vPixelsVector . at ( ( int ) ucPixelValue )++;
54 }
55 }
56
Codul sursă al aplicaţiei 25

57 // Imaginea de a f i s a r e a h i s t o g r a m e i i m a g i n i i
58 Mat matHistImg = Mat : : zeros ( 2 0 0 , 2 5 5 , CV_8UC1 ) ;
59
60 // Desenarea comp on en t e l or h i s t o g r a m e i
61 for ( int i = 0 ; i < vPixelsVector . size ( ) ; i++)
62 line ( matHistImg ,
63 Point ( i , matHistImg . rows ) ,
64 Point ( i , 200 − ( int ) ( vPixelsVector . at ( i ) ) / 1 0 0 ) ,
65 Scalar ( 2 5 5 , 1 0 0 , 1 0 ) ) ;
66
67 // A f i s a r e a h i s t o g r a m e i
68 imshow ( " HistImg " , matHistImg ) ;
69 waitKey ( ) ;
70
71 // A p l i c a r e t h r e s h o l d
72 Mat matThreshold = Mat : : zeros ( matImg_in . size ( ) , CV_8UC1 ) ;
73 threshold ( matImgGray , matThreshold , 4 2 , 2 5 5 , CV_THRESH_BINARY_INV ) ;
74
75 // A f i s a r e a i m a g i n i i s e g m e n t a t e
76 imshow ( " ThImage " , matThreshold ) ;
77 waitKey ( 0 ) ;
78
79 /*
80 * Cautare c o n t u r u r i .
81 * F i e c a r e c o n t u r va f i s a l v a t i n t r −un vecor , numit c o n t o u r s .
82 * F i e c a r e c o n t u r r e p e z i n t a , de f a p t , un v e c t o r de puncte .
83 */
84 findContours ( matThreshold , contours , hierarchy , CV_RETR_TREE , ←
CV_CHAIN_APPROX_SIMPLE , Point ( 0 , 0 ) ) ;
85
86 // Desenarea f i e c a r u i contur , f o l o s i n d o c u l o a r e g e n e r a t a a l e a t o r
87 for ( int i = 0 ; i< contours . size ( ) ; i++ )
88 {
89 Scalar color = Scalar ( 1 0 0 , 1 0 , 255 ) ;
90 drawContours ( matImg_in , contours , i , color , 2 , 8 , hierarchy ) ;
91 imshow ( " Contur " , matImg_in ) ;
92 waitKey ( ) ;
93 }
94
95 // C a l c u l u l a r i e i f i e c a r u i c o n t u r
96 for ( int i = 0 ; i< contours . size ( ) ; i++ )
97 {
98 double area = contourArea ( contours . at ( i ) ) ;
99 cout << "Aria conturului " << i << " = " << area << endl ;
100 }
101
102 // C a l c u l u l p e r i m e t r u l f i e c a r u i c o n t u r
103 for ( int i = 0 ; i< contours . size ( ) ; i++ )
104 {
105 double perimeter = arcLength ( contours . at ( i ) , true ) ;
106 cout << " Perimetrul conturului " << i << " = " << perimeter << ←
endl ;
26 SEGMENTAREA PRIN PARTIŢIONARE

107 }
108
109 imshow ( " Imagine Contur " , matImg_in ) ;
110 waitKey ( 0 ) ;
111 }
3.4 Descrierea funcţiilor principale

62 void line ( Mat& img , Point pt1 , Point pt2 , const Scalar& color , int ←
thickness =1)
Desenează o linie care conectează două puncte.
ˆ img: imaginea pe care va fi desenată linia;
ˆ pt1: punctul de start;
ˆ pt2: punctul de oprire;
ˆ color: culoarea liniei;
ˆ thickness: grosimea liniei.
73 double threshold ( InputArray src , OutputArray dst , double thresh , ←
double maxval , int type )
Aplică un threshold cu valoare fixă asupra tuturor pixelilor din imagine
ˆ src: imaginea de intrare;
ˆ dst: imaginea rezultată;
ˆ thresh: valoarea de threshold;
ˆ maxval: valoarea maximă care urmează a fi utilizată cu parametrul type de tipul
THRESH BINARY sau THRESH BINARY INV;
ˆ type: poate fi utilizat unul dintre următoarele tipuri de threshold:
– THRESH BINARY pentru:

maxval, daca src(x, y) > thresh,


t(x, y) = (3.3)
0, altfel,

– THRESH BINARY INV pentru:


0, daca src(x, y) > thresh,


t(x, y) = (3.4)
maxval, altfel,

– THRESH TRUNC pentru:


threshold, daca src(x, y) > thresh,


t(x, y) = (3.5)
src(x, y), altfel,

– THRESH TOZERO pentru:


src(x, y), daca src(x, y) > thresh,


t(x, y) = (3.6)
0, altfel,

– THRESH TOZERO INV pentru:


0, daca src(x, y) > thresh,


t(x, y) = (3.7)
src(x, y), altfel,
Descrierea funcţiilor principale 27

84 void findContours ( InputOutputArray image , OutputArrayOfArrays ←


contours , OutputArray hierarchy , int mode , int method , Point ←
offset=Point ( ) )
Caută contururile ı̂ntr-o imagine binară.
ˆ image: imaginea de intrare, ı̂n format de 8 biţi cu 1 canal;
ˆ contours: vectorul care conţine contururile detectate. Fiecare contur este stocat sub
forma unui vector de puncte;
ˆ hierarchy: este un parametru opţional care conţine informaţii despre topologia ima-
ginii;
ˆ mode: modalitatea sub care se va face extragerea contururilor. Următoarele variante
sunt posibile:
– CV RETR EXTERNAL: extrage doar contururile exterioare;
– CV RETR LIST: extrage toate contururile fără a se stabili relaţii ierarhice ı̂ntre
acestea;
– CV RETR CCOMP: extrage toate contururile şi le organizează sub forma unei ierarhii
cu două niveluri;
– CV RETR TREE: extrage toate contururile şi reconstruieşte o ierarhie completă a
contururilor sub formă de cascadă.
ˆ method: reprezintă modalitatea de reprezentare a contururilor. Poate fi aleasă una
dintre următoarele combinaţii:
– CV CHAIN APPROX NONE: salvează toate punctele conturului considerat;
– CV CHAIN APPROX SIMPLE: realizează compresia segmentelor pe orizontală, verti-
cală şi pe diagonală, lăsând nemodificate dor punctele lor terminale;
– CV CHAIN APPROX TC89 L1, CV CHAIN APPROX TC89 KCOS aplică una dintre metodele
algoritmului de aproximare Teh-Chin.
ˆ offset: parametru opţional prin care fiecare punct din contur poate fi deplasat.
90 void drawContours ( InputOutputArray image , InputArrayOfArrays contours ←
, int contourIdx , const Scalar& color , int thickness =1, int ←
lineType =8, InputArray hierarchy=noArray ( ) , int maxLevel=INT_MAX , ←
Point offset=Point ( ) )
Desenează contururile detectate ı̂ntr-o imagine.
ˆ image: imaginea unde vor fi desenate contururile detectate;
ˆ contours: vectorul care conţine contururile detectate. Fiecare contur este salvat sub
forma unui vector de puncte;
ˆ contourIdx: parametru care specifică indexul conturului ce urmează a fi desenat.
O valoare negativă a acestui parametru conduce la desenarea tuturor contururilor
detectate;
ˆ color: culoarea cu care urmează a fi desenat conturul specificat;
ˆ thickness: grosimea liniei care defineşte conturul considerat;
ˆ lineType: tipul liniei cu care este desenat conturul;
ˆ hierarchy: parametru opţional, necesar doar atunci când se doreşte desenarea anu-
mitor contururi;
98 double contourArea ( InputArray contour , bool oriented=false )
Calculează aria unui contur.
ˆ contour: vectorul de puncte care defineşte conturul;
ˆ oriented: indicator care permite determinarea orientării unui contur.
105 double arcLength ( InputArray curve , bool closed )
28 SEGMENTAREA PRIN PARTIŢIONARE

Calculează perimetrul unui contur.


ˆ curve: vectorul de puncte care defineşte conturul;
ˆ closed: indică dacă un contur este ı̂nchis sau nu.
4. Detectarea cantelor

Calculul gradientului ı̂ntr-o imagine


Detectorul de cante Canny
Transformata Hough

În această lucrare vor fi studiate metode de detectare a cantelor prin evaluarea gradi-
entului intensităt, ii pixelilor dintr-o imagine s, i segmentarea muchiilor obiectelor. Liniile din
imagine vor fi determinate utilizându-se evaluarea proprietăt, ii de coliniaritate a pixelilor
obiect folosind transformata Hough.

4.1 Baze teoretice


4.1.1 Calculul gradientului ı̂ntr-o imagine
Gradientul unei imagini reprezintă o schimbare direct, ională a intensităt, ii pixelilor unei
imagini. Acesta este utilizat cu precădere la segmentarea cantelor prin extragerea marginilor
obiectelor vizualizate. Operat, ia de determinare a gradientului este ı̂n mod normal efectuată
prin detectarea tranzit, iilor locale brus, te ale intensităt, ilor pixelilor imaginii. Uzual, operat, ia
mai este cunoscută s, i sub numele de extragerea cantelor. Aceasta are ca principal rezultat
o imagine binara având ca pixeli de fundal marginile obiectelor din imagine, sau locul unde
intensitatea ı̂s, i schimbă valoarea brusc.
Principiul extragerii cantelor este bazat pe calculul local al gradientului imaginii prin
derivate part, iale de ordinul unu sau doi. Ilustrarea grafică s, i numerică a gradientului imaginii
de-a lungul unei direct, ii (x) poate fi observată ı̂n Fig. 4.1.

Fig. 4.1 Detectarea tranzit, iilor brus, te ı̂ntr-o imagine gri (sursa [6]).
30 DETECTAREA CANTELOR

Matematic, gradientul unei imagini f (x, y), poate fi definit astfel:



Gx ∂f /∂x
∇f = = . (4.1)
Gy ∂f /∂y
unde (x, y) sunt coordonatele pixelilor din imagine.
Calculul gradientului imaginii este efectuat folosind o fereastră glisantă translatată pe
imaginea de intrare. Imaginea gradient obt, inută este partit, ionată folosind relat, ia 3.1, prezen-
tată ı̂n lucrarea de laborator numărul 3. O problemă majoră ı̂n folosirea acestui detector
de cante este dificultatea alegerii unei valori optimale de partit, ionareEng: threshold . Dacă
valoarea de partit, ionare este prea mică, atunci imaginea binara de ies, ire va cont, ine cante
false cunoscute s, i sub numele de pozitive false. Pe de alta parte, dacă valoarea de prag este
prea mare, cantele reale vor fi suprimate, ı̂n cazul acesta denumite s, i negative false.

4.1.2 Detectorul de cante Canny


Detectorul de cante Canny are la bază partit, ionarea globală a imaginii gradient [3].
Acesta este foarte des folosit ı̂n procesarea de imagini datorită timpului de execut, ie scăzut s, i
a calităt, ii foarte bune a cantelor obt, inute. Detectarea optimală a cantelor implică atingerea
a trei obiective:
ˆ detectarea de cante optimală: toate marginile din imagine trebuiesc detectate cat mai
aprope de marginile reale;
ˆ localizarea optimală de puncte a cantelor : pozit, ia marginilor obt, inute trebuie să fie cât
mai aproape posibil de marginile reale;
ˆ răspuns optimal al punctelor marginilor : cantele calculate trebuie să fie cât mai subt, iri
posibil, adică detectorul nu trebuie să identifice două cante acolo unde există doar una
singură.
Detectorul de cante Canny este bazat pe trei pas, i secvent, iali. La ı̂nceput, este folosită o
operat, ie de convolut, ie ı̂ntre imaginea de intrare f (x, y) s, i un filtru Gaussian de netezire:
x2 +y 2
G(x, y) = e− 2σ 2 , (4.2)
unde G(x, y) este o funct, ie Gaussiană cu deviat, ia standard σ. Acest tip de filtraj suprimă
zgomotele din imaginea de intrare, din moment ce prima derivată a unei Gaussiene folosită
ı̂n calculul gradientului imaginii este susceptibila la zgomot prezent ı̂n imaginea neprocesată.
Al doilea pas al algoritmului Canny este calculul magnitudinii imaginii gradient M (x, y)
s, i al direct, iei (unghiului) α(x, y):

M (x, y) = gx2 + gy2 , (4.3)


α(x, y) = tan−1 gx /gy , (4.4)
unde gx s, i gy sunt direct, iile orizontale s, i verticale ale imaginii gradient.
Cantele obt, inute sunt subt, iate folosind supresia non-maxima, adică patru ferestre filtru
sunt utilizate ı̂n specificarea unui număr de orientări discrete ale normalei cantei: orizontală,
verticală, +45◦ s, i −45◦ .
În final, imaginea gri obt, inută este binarizată folosind as, a numita tehnică de partit, ionare
prin histerezis, ce utilizează doua valori de partit, ionare: nivel jos TL s, i nivel sus TH . Pixelii cu
o valoare peste TH sunt considerat, i pixeli apart, inând cantelor ”puternici ”, iar cei cu o valoare
sub TL sunt considerat, i cante false. Acei pixeli ce apart, in intervalului [TL , TH ], denumit, i s, i
Baze teoretice 31

Fig. 4.2 Schema-bloc a operat, iei de segmentare a cantelor prin metoda Canny.

pixeli ”slabi ”, sunt considerat, i margini dacă sunt conectat, i deja la pixeli ”puternici”.
Potrivit [18], valoarea joasă de prag poate fi exprimată ca o funct, ie a valorii superioare:

TL = 0.4 · TH , (4.5)
Schema-bloc a metodei de segmentare a cantelor Canny este reprezentată ı̂n Fig. 4.2.

4.1.3 Transformata Hough


O problemă des ı̂ntâlnita ı̂n segmentarea cantelor este aceea că de foarte multe ori can-
tele obt, inute nu sunt continue, adică ı̂ntre pixelii marginilor exista mici ı̂ntreruperi. Acest
fenomen se datorează zgomotului prezent ı̂n imaginea de intrare, iluminării neuniforme, cât
s, i datorită unor efecte ce introduc discontinuităt, i ı̂n imaginea de intensitate.
Transformata Hough [13], folosită la conectarea pixelilor cantelor, este o metodă bazată
pe forma obiectului. Cu toate că orice formă de obiect poate fi reprezentată prin as, a nu-
mita transformata Hough generalizată, ı̂n practică, datorita limitării resurselor de calcul,
reprezentarea formelor se realizează prin linii, cercuri sau elipse. Transformata Hough poate
fi folosită ı̂n combinat, ie cu detectoarele de cante pentru localizarea cu precizie a marginilor
obiectelor.
Principiul transformatei Hough pentru detect, ia de linii, reprezentat ı̂n Fig. 4.3, este bazat
pe ecuat, ia generalizată a unei linii drepte:

yi = axi + b, (4.6)
unde (xi , yi ) este un punct al liniei.

y b’ b

(xi, yi) b xia yi


a’

(xj, yj) b xja yj

x a
(a) (b)
Fig. 4.3 Principiul transformatei Hough. (a) Planul xy al imaginii. (b) Spat, iul parametric ab.
Prin punctul (xi , yi ) trece un număr infinit de linii, toate satisfăcând ecuat, ia 4.6 cu
diferite valori ale coeficient, ilor a s, i b. Dacă ı̂n locul planului imaginii xy ecuat, ia liniei este
reprezentată ı̂n funct, ie de planul ab din Fig. 4.3(b), plan numit s, i spat, iu parametric, atunci
ecuat, ia unei singure linii pentru o pereche fixă (xi , yi ) poate fi descrisă după cum urmează:

b = −xi a + yi . (4.7)
32 DETECTAREA CANTELOR

Fig. 4.4 Schema-bloc a unui sistem de extragere a liniilor dintr-o imagine utilizând detectorul Canny
s, i transformata Hough.

După cum poate fi văzut ı̂n Fig. 4.3, dacă un al doilea punct (xj , yj ) este colinear cu
punctul (xi , yi ), atunci, ı̂n spat, iul parametric, cele doua linii corespunzătoare se intersectează
ı̂ntr-un anumit punct (a , b ).
Schema bloc completă a unui sistem de detectare a liniilor, bazat pe detectorul de cante
Canny s, i transformata Hough, poate fi văzută ı̂n Fig. 4.4.

4.2 Cerint, e
1. Să se ı̂ncarce şi să se convertească o imagine către o reprezentare cu niveluri de gri;
2. Să se calculeze gradientului imaginii utilizând filtrul SOBEL;
3. Să se detecteze cantele din imagine utilizând filtrul Laplace
4. Să se detecteze cantele din imagine utilizand filtrul Canny.

4.3 Codul sursă al aplicat, iei

1 # include <i o s t r e a m >


2 # include <s t d i o . h>
3 # include <opencv2 / c o r e / c o r e . hpp>
4 # include <opencv2 / h i g h g u i / h i g h g u i . hpp>
5 # include <opencv2 / imgproc / imgproc . hpp>
6
7 using namespace cv ;
8 using namespace std ;
9
10 int main ( int argc , char ** argv )
11 {
12 cout << "SVA Laborator 04: Calculul Gradientului " << endl ;
13
14 int rezolutie_imagine = CV_16S ;
15 int ordin_derivata = 0 ;
16 int marime_filtru = 0 ;
17 int raport = 3 ;
18 int threshold_canny_high = 1 0 0 ;
19 int threshold_hough = 1 5 5 ;
20 vector<Vec4i> linii_hough ;
21 Mat img_in , img_out ;
22 Mat img_filtrare_Sobel ;
Codul sursă al aplicat, iei 33

23 Mat img_filtrare_Laplace ;
24 Mat img_segmentare_Canny ;
25 string strCaleImagine ;
26
27 // I n c a r c a r e a i m a g i n i i de pe d i s k
28 if ( argc != 4 )
29 {
30 cout<<" Apelare : aplicatie <cale -imagine > <ordin -derivata > <←
dimensiune -fereastra -glisanta >"<<endl ;
31 exit ( 0 ) ;
32 }
33 else
34 {
35 strCaleImagine = argv [ 1 ] ;
36 }
37
38 img_in = imread ( strCaleImagine . c_str ( ) , CV_LOAD_IMAGE_UNCHANGED ) ;
39
40 // V e r i f i c a r e a i n c a r c a r i i c o r e c t e a i m a g i n i i
41 if ( ! img_in . data )
42 {
43 cout << " Imaginea " << strCaleImagine << " nu a putut fi ←
incarcata " << endl ;
44 return −1;
45 }
46
47 // C o n v e r s i a i m a g i n i i de i n t r a r e c o l o r i n i m a g i n e g r i
48 cvtColor ( img_in , img_out , CV_RGB2GRAY ) ;
49 imshow ( " Imagine Gri" , img_out ) ;
50 waitKey ( ) ;
51 destroyAllWindows ( ) ;
52
53 // S e l e c t i a o r d i n u l u i d e r i v a t e i
54 sscanf ( argv [ 2 ] , "%d" , &ordin_derivata ) ;
55
56 // S e l e c t i a m a r i m i i f i l t r u l u i
57 sscanf ( argv [ 3 ] , "%d" , &marime_filtru ) ;
58
59 // C a l c u l u l g r a d i e n t u l u i i m a g i n i i u t i l i z a n d f i l t r u l SOBEL
60 Sobel ( img_out , img_filtrare_Sobel , rezolutie_imagine , ←
ordin_derivata , ordin_derivata , marime_filtru ) ;
61
62 // C o n v e r s i e s c a l a
63 convertScaleAbs ( img_filtrare_Sobel , img_filtrare_Sobel ) ;
64 namedWindow ( " SOBEL " , CV_WINDOW_AUTOSIZE ) ;
65 imshow ( " SOBEL" , img_filtrare_Sobel ) ;
66 waitKey ( ) ;
67 destroyAllWindows ( ) ;
68
69 // D e t e c t a r e a c a n t e l o r u t i l i z a n d f i l t r u l L a p l a c e
70 Laplacian ( img_out , img_filtrare_Laplace , rezolutie_imagine , ←
marime_filtru , 1 , 0 , BORDER_DEFAULT ) ;
34 DETECTAREA CANTELOR

71
72 // C o n v e r s i e s c a l a
73 convertScaleAbs ( img_filtrare_Laplace , img_filtrare_Laplace ) ;
74 namedWindow ( " LAPLACE " , CV_WINDOW_AUTOSIZE ) ;
75 imshow ( " LAPLACE " , img_filtrare_Laplace ) ;
76 waitKey ( ) ;
77 destroyAllWindows ( ) ;
78
79 // D e t e c t a r e a c a n t e l o r u t i l i z a n d f i l t r u l Canny
80 Canny ( img_out , img_segmentare_Canny , threshold_canny_high * 0 . 7 , ←
threshold_canny_high , marime_filtru ) ;
81 namedWindow ( " Filtru Canny " , CV_WINDOW_AUTOSIZE ) ;
82 imshow ( " Filtru Canny" , img_segmentare_Canny ) ;
83 waitKey ( ) ;
84 destroyAllWindows ( ) ;
85
86 // C a l c u l u l l i n i i l o r p r i n t r a n s f o r m a t a Hough
87 HoughLinesP ( img_segmentare_Canny , linii_hough , 1 , CV_PI / 1 8 0 , ←
threshold_hough , 1 0 0 , 2 0 ) ;
88
89 // Desenarea l i n i i l o r Hough pe i m agi n e a de i n t r a r e
90 for ( size_t i = 0 ; i < linii_hough . size ( ) ; i++ )
91 {
92 Vec4i l = linii_hough [ i ] ;
93 line ( img_in , Point ( l [ 0 ] , l [ 1 ] ) , Point ( l [ 2 ] , l [ 3 ] ) , Scalar←
( 0 , 0 , 2 5 5 ) , 3 , CV_AA ) ;
94 }
95
96 // A f i s a r e a l i n i i l o r Hough
97 imshow ( "Linii Hough " , img_in ) ;
98 waitKey ( ) ;
99
100 return 0 ;
101 }
4.4 Descrierea funct, iilor principale

60 void Sobel ( InputArray src , OutputArray dst , int ddepth , int dx , int ←
dy , int ksize =3, double scale=1)
Calculează prima, a doua sau a treia derivată a unei imagini, utilizând operatorul Sobel.
ˆ src: imaginea de intrare;
ˆ dst: imaginea de ies, ire;
ˆ ddepth: adâncimea imaginii de ies, ire (CV 8U, CV 16U, CV 16S, CV 32F, CV 64F);
ˆ xorder: ordinul derivatei pe axa x;
ˆ yorder: ordinul derivatei pe axa y;
ˆ ksize: mărimea ferestrei Sobel (trebuie să fie un număr impar: 1, 3, 5 sau 7);
ˆ scale: factor de scalare opt, ional.
63 void convertScaleAbs ( InputArray src , OutputArray dst , double alpha=1)
Scalează, calculează valori absolute s, i convertes, te rezultatul pe o rezolut, ie de 8-bit, i.
ˆ src: imaginea de intrare;
ˆ dst: imaginea de ies, ire;
Descrierea funct, iilor principale 35

ˆ alpha: factor de scalare opt, ional.


70 void Laplacian ( InputArray src , OutputArray dst , int ddepth , int ksize←
=1, double scale=1)
Calculează Laplacianul unei imagini. Aceias, i parametrii ca s, i la filtrul Sobel.
80 void Canny ( InputArray image , OutputArray edges , double threshold1 , ←
double threshold2 , int apertureSize =3)
Detector de cante Canny.
ˆ image: imagine gri pe 8-bit, i;
ˆ edges: imagine cont, inând cante;
ˆ threshold1: primul prag al metodei de partit, ionare prin histerezis;
ˆ threshold2: al doilea prag al metodei de partit, ionare prin histerezis;
ˆ apertureSize: mărimea ferestrei mască Sobel.
87 void HoughLinesP ( InputArray image , OutputArray lines , double rho , ←
double theta , int threshold , double minLineLength =0, double ←
maxLineGap=0 )
Calculează segmente de linii ı̂ntr-o imagine binară utilizând transformata Hough proba-
bilistică.
ˆ image: imagine gri (binară) pe 8-bit, i;
ˆ lines: liniile Hough detectate. Fiecare linie este reprezentată de un vector cu 4
elemente (x1 , y1 , x2 , y2 ), unde (x1 , y1 ) s, i (x2 , y2 ) sunt coordonatele capetelor liniilor;
ˆ rho: rezolut, ia, exprimată ı̂n pixeli, a matricei acumulator;
ˆ theta: rezolut, ia, exprimată ı̂n radiani, a unghiului dintre punctele din matricea acu-
mulator;
ˆ threshold: valoarea de threshold aplicată matricei acumulator;
ˆ minLineLength: lungimea minimă a liniilor;
ˆ maxLineGap: distant, a maximă admisă dintre 2 pixeli ai aceleias, i linii.
36 DETECTAREA CANTELOR
5. Corespondenţe stereo şi
reconstrucţia 3D a unei scenei

Detectorul de colt, uri Harris


Reconstruct, ia 3D prin triangulat, ie

În acest laborator va fi prezentată o metodă de detect, ie a corespondent, elor ı̂n imagini
stereo precum s, i modul prin care aceasta poate fi utilizată pentru a reconstrui pozit, ia 3D a
punctelor vizualizate printr-o cameră stereo.

5.1 Baze teoretice


5.1.1 Detectorul de colt, uri Harris
Cea mai comună definit, ie a unui colt, ı̂ntr-o imagine a fost dată de Harris [9] ı̂n 1988
şi se bazează pe matricea derivatelor de ordinul doi (∂ 2 x, ∂ 2 y, ∂x∂y) a intensităt, ii imaginii
I. Derivatele de ordinul doi ale unei imagini, la fiecare pozit, ie (x, y), pot fi considerate ca
formând o nouă ”imagine de derivate de ordinul doi ”, sau o nouă imagine Hessian H(x, y).
Terminologia prezentată este dată de matricea Hessian ı̂n jurul unui punct care, pentru cazul
bidimensional, poate fi definită după cum urmează:
∂ 2 I(x,y) ∂ 2 I(x,y)
∂x2 ∂x∂y
H(x, y) = ∂ 2 I(x,y) ∂ 2 I(x,y) (5.1)
∂y∂x ∂y 2
.
Colt, urile astfel detectate pot reprezenta principalele caracteristici care permit deter-
minarea corespondent, elor ı̂ntre două imagini stereo. Un exemplu de astfel de corespondent, e
poate fi observat ı̂n Fig. 5.1. Colt, urile identificate cu detectorul Harris sunt considerate
drept caracteristici solide ce pot reprezenta corespondent, e ı̂n imagini stereo.

Fig. 5.1 Puncte corespondente ı̂ntre două imagini.


38 CORESPONDENŢE STEREO ŞI RECONSTRUCŢIA 3D A UNEI SCENEI

Detectorul Harris se bazează pe analiza funct, iei de autocorelaţie, ce estimează schimbarea


locală a intensităt, ii pentru o pozit, ie (x, y), sau derivata intensităt, ii imaginii la poziţia (x, y):

E(Δx, Δy) = w(x, y) · [I(x + Δx, y + Δy) − I(x, y)]2 , (5.2)
x,y

unde w reprezintă o mască de netezire de formă circulară. De obicei, w este o mască Gaus-
siană de forma:
1 x2 +y 2
w(x, y) = exp− 2σ2 (5.3)
2πσ
unde σ reprezintă deviat, ia standard sau scara de netezire.
În implementarea detectorului Harris se pot distinge două etape:
ˆ prima, ı̂n care sunt calculate valorile funct, iilor de autocorelaţie pentru fiecare pixel din
imagine;
ˆ a doua, unde este determinat un maxim local al funct, iei de autocorelaţie ı̂ntr-o vecinătate
definită de utilizator. Pixelii asociat, i acestor valori de maxim local sunt considerat, i ca
fiind colt, uri.
Variaţia intensităţii pixelilor din imagine poate fi calculată utilizând o mască ale cărei
dimensiuni sunt alese de către utilizator. Variaţia intensităţii pixelilor survine ı̂n urma
deplasării acestei măşti pe distanţe mici de-a lungul diferitelor direcţii. Considerând o astfel
de abordare, pot exista trei cazuri distincte:
ˆ dacă masca conţine pixeli al căror nivel este apropiat de nivelul intensităt, ii imaginii,
ı̂n urma deplasării măştii ı̂n orice direcţie va rezulta o variaţie mică a acesteia;
ˆ dacă masca conţine porţiuni dintr-o imagine, o deplasare a măştii de-a lungul marginii
va conduce la variaţii mici ale intensităţii. În schimb, o deplasare perpendiculară pe
margine va conduce la obţinerea unei variaţii mari a intensităţii pixelilor;
ˆ dacă ı̂n interiorul măştii se află un colţ atunci deplasarea măştii ı̂n orice direcţie va
conduce la obţinerea unei variaţii semnificative a intensităţii. În acest caz, un colţ
poate fi determinat găsind valoarea minimă a variaţiei intensităţii.
Variat, ia intensităt, ii pixelilor (gradient, ii imaginii) pot fi reprezentat, i astfel:
 ∂I(x, y)
Ix = I −1 0 1 = , (5.4)
∂x
 T ∂I(x, y)
Iy = I −1 0 1 = . (5.5)
∂y
Pentru variaţii mici, rezultă:

 Ix2 Ix Iy Δx
E(Δx, Δy) = Δx Δy . (5.6)
Iy Ix Iy2 Δy

5.1.2 Reconstruct, ia 3D
Principiile de bază ale reconstruct, iei stereo sunt ilustrate grafic ı̂n Fig. 5.2. Punctele
pL şi pR reprezintă proiecţia punctului 3D (P ) ı̂n planurile imaginilor celor două camere
(stângă s, i dreaptă), fiecare senzor având propriul punct de vizualizare. Reconstruct, ia stereo
a punctului tridimensional X este dată de proiecţia razelor, ilustrate prin linie punctată ı̂n
Fig. 5.2, ce pleacă din centrele optice cL şi cR ale camerelor şi trec prin punctele xL şi xR .
Matricea de proiecţie descrie configurat, ia unei camere ı̂n lumea reală. Aceasta este rezul-
Baze teoretice 39

pL=QL·P pR=QR·P

cR
cL
Camera Camera
stângă dreaptă

Fig. 5.2 Reconstrucţia unui punct 3D (P ) din punctele vizualizate 2D pL şi pR , achizit, ionate de la
o cameră stereo cu matricele de proiecţie QL şi QR cunoscute.

tatul unui proces de calibrare a camerei. În cazul unei camere stereo sunt folosite două
matrice de proiecţie, una pentru senzorul stâng QL şi una pentru cel drept QR . În funct, ie
de semnificat, ia lor, parametrii matricei de proiect, ie pot fi clasificat, i după cum urmează:
ˆ parametri intrinseci (Cint ), ce descriu caracteristicile interne ale camerei, precum distant, a
focală, intersect, ia axei optice cu planul imaginii şi aspectul pixelilor, etc.;
ˆ parametri extrinseci (Cext ), ce reprezintă o transformare omogenă ı̂ntre poziţia şi ori-
entarea camerei ı̂n raport cu un sistem de coordonate de referinţă.
Atunci când ambii parametri, intrinseci şi extrinseci, sunt cunoscuţi, matricea de proiecţie
a unei camere poate fi determinată cu următoarea relaţie:

Q = Cint · Cext . (5.7)


Acurateţea cu care se poate realiza reconstrucţia unei scene 3D depinde de cantitatea de
informaţie a priori cunoscută a parametrilor sistemului video. Astfel, dacă sunt cunoscuţi
atât parametrii intrinseci cât şi cei extrinseci ai sistemului de camere stereo, este posibilă
reconstrucţia scenei fără ambiguităţi prin utilizarea metodei triangulaţiei [4, 10, 21].
În aplicaţia curentă, principiul triangulaţiei este aplicat imaginilor achiziţionate de la
sistemul stereo. Acest proces presupune utilizarea a două camere video, poziţionate rigid la
distanţa b una faţă de cealaltă, ce achiziţionează imagini care vizualizează aceeas, i caracter-
istică (acelaşi punct P ) ı̂n interiorul lor.
Punctul 3D P din scenă este observat ca un punct 2D pL , ı̂n planul stâng al imaginii,
respectiv pR , ı̂n planul drept al imaginii (v. Fig. 5.2), formând un sistem, ı̂n coordonate
omogene, de forma [7, 8, 17]:

⎨pL = (xL , yL , 1),
(5.8)
⎩p = (x , y , 1).
R R R

De asemenea, axa principală intersectează planul imaginii ı̂n punctul de coordonate


cL (xcL , ycL ), corespunzător imaginii achiziţionate de la camera stângă, respectiv ı̂n punc-
tul cR (xcR , ycR ) pentru centrul imaginii achiziţionate de la camera dreaptă. Se presupune că
originea planului de coordonate coincide cu centrul lentilei camerei stângi.
Având la dispoziţie informaţia legată de cele două puncte proiectate ı̂n planurile imagini-
lor, cât şi distanţa dintre centrele optice ale celor două camere, se pune problema determinării
40 CORESPONDENŢE STEREO ŞI RECONSTRUCŢIA 3D A UNEI SCENEI

coordonatelor 3D ale punctului P . Pentru aceasta se pot utiliza următoarele expresii:

b
X = xL · , (5.9)
d
b
Y = yL · , (5.10)
d
b
Z=f· , (5.11)
d
unde X, Y , Z sunt coordonatele 3D ale punctului P reprezentat ı̂n coordonate omogene, iar
d reprezintă disparitatea. În cazul de fat, ă, disparitatea reprezinta diferent, a dintre proiect, ia
punctului P ı̂n imaginea dreapta s, i proiact, ia sa ı̂n imaginea stângă, de-a lungul axei x. Cu
cât d este mai mare, cu atât punctul este mai aproape de cameră. Disparitatea poate fi
determină după cum urmează [7]:

d = xL − xR . (5.12)
Cu ajutorul relaţiilor (5.9) ÷ (5.11) se poate trage concluzia că distanţa Z este invers
proporţională cu disparitatea, iar coordonatele X şi Y ale sistemului de referinţă depind
doar de valoarea variabilei d şi de distanţa dintre cele două camere.

5.2 Cerint, e
1. Să se citească de pe HDD o pereche de imagini stereo;
2. Să se detecteze colt, urile din imaginea stângă;
3. Să se determine corespondent, ele dintre imaginea stânga s, i cea dreaptă;
4. Să se determine coordonatele 3D ale corespondent, elor determinate la punctul 3.

5.3 Codul sursă al aplicat, iei

1 # include < s t d l i b . h>


2 # include <i o s t r e a m >
3 # include " opencv2 / opencv .hpp"
4 # include " opencv2 / highgui / highgui .hpp"
5 # include " opencv2 / imgproc / imgproc .hpp"
6
7 using namespace cv ;
8
9 int main ( int argc , char ** argv )
10 {
11 // P a r a m e t r i i c a m e r e i s t e r e o
12 float fLiniaDeBaza ( 0 . 0 1 2 ) ;
13 float fDistantaFocala ( 5 2 4 . 0 ) ;
14
15 // Coordonate 3D de r e c o n s t r u i t
16 float X ( 0 . 0 ) , Y ( 0 . 0 ) , Z ( 0 . 0 ) ;
17
18 std : : string strCaleImagineStanga , strCaleImagineDreapta ;
19 std : : string strCaleImagineStanga , strCaleImagineDreapta ;
20
21 // I n c a r c a r e a i m a g i n i i de pe d i s k
Codul sursă al aplicat, iei 41

22 if ( argc != 3 )
23 {
24 std : : cout<<" Usage : aplicatie <cale - imagineStanga > <cale -←
imaginereapta >"<<std : : endl ;
25 exit ( 0 ) ;
26 }
27 else
28 {
29 strCaleImagineStanga = argv [ 1 ] ;
30 strCaleImagineDreapta = argv [ 2 ] ;
31 }
32 // I m a g i n i de i n t r a r e
33 Mat ImagineStanga = imread ( strCaleImagineStanga . c_str ( ) , ←
CV_LOAD_IMAGE_GRAYSCALE ) ;
34 Mat ImagineDreapta = imread ( strCaleImagineDreapta . c_str ( ) , ←
CV_LOAD_IMAGE_GRAYSCALE ) ;
35
36 // Corespondente s t e r e o
37 std : : vector<Point2f> CorespondenteStanga ;
38 std : : vector<Point2f> CorespondenteDreapta ;
39 std : : vector<uchar> nStatus ;
40
41 int nNoMaximCorespondente ( 1 ) ;
42 std : : vector<float> fFeatureErrors ;
43
44 // D e t e c t a r e a c o l t u r i l o r d i n i m a g i n e a s t a n g a
45 goodFeaturesToTrack ( ImagineStanga ,
46 CorespondenteStanga ,
47 nNoMaximCorespondente ,
48 0.01 ,
49 5.0) ;
50
51 // Determinarea c o r e s p o n d e n t e l o r d i n t r e i m a g i n e a s t a n g a s i c e a ←
dreapta
52 calcOpticalFlowPyrLK ( ImagineStanga ,
53 ImagineDreapta ,
54 CorespondenteStanga ,
55 CorespondenteDreapta ,
56 nStatus ,
57 fFeatureErrors ) ;
58
59 std : : cout << "No corespondente = " << CorespondenteStanga . size ( ) ←
<< std : : endl << std : : endl ;
60
61 // R e c o n s t r u c t i a 3D
62 for ( int i = 0 ; i < CorespondenteStanga . size ( ) ; i++)
63 {
64 float fDisparitate = CorespondenteStanga [ i ] . x − ←
CorespondenteDreapta [ i ] . x ;
65
66 X = CorespondenteStanga [ i ] . x * ( fLiniaDeBaza / fDisparitate ) ;
67 Y = CorespondenteStanga [ i ] . y * ( fLiniaDeBaza / fDisparitate ) ;
42 CORESPONDENŢE STEREO ŞI RECONSTRUCŢIA 3D A UNEI SCENEI

68 Z = fDistantaFocala * ( fLiniaDeBaza / fDisparitate ) ;


69
70 std : : cout << " Reconstructie 3D (X, Y, Z) punct " << i << ": "←
<< X << ", " << Y << ", " << Z << std : : endl ;
71 }
72
73 return 0 ;
74 }
5.4 Descrierea funct, iilor principale

45 void goodFeaturesToTrack ( InputArray image , OutputArray corners , int ←


maxCorners , double qualityLevel , double minDistance )
Calculează colt, uri ı̂ntr-o imagine gri.
ˆ image: imaginea de intrare;
ˆ corners: colt, uri detectate;
ˆ maxCorners: numărul maxim de colt, uri ce poate fi detectat (vor fi selectate cele mai
puternice colt, uri ı̂n cazul ı̂n care sunt detectate mai multe);
ˆ qualityLevel: calitatea minimă a unui colt, ;
ˆ minDistance: distant, a Euclidiană minimă ce poate exista ı̂ntre două colt, uri vecine.
52 void calcOpticalFlowPyrLK ( InputArray prevImg , InputArray nextImg , ←
InputArray prevPts , InputOutputArray nextPts , OutputArray status , ←
OutputArray err )
Calculează corespondet, ele dintre două imagini utilizând metoda Lucas-Kanade.
ˆ prevImg: imaginea de intrare stanga;
ˆ nextImg: imaginea de intrare dreapta;
ˆ prevPts: vectorul de puncte pentru care se caută corespondent, e;
ˆ nextPts: punctele corespondente din imaginea dreapta;
ˆ status: vector de status (ı̂n cazul ı̂n care o corespondent, a nu a fost găsita, acel index
va fi setat 0, altfel va fi 1);
ˆ err: vector de eroare (indică gradul de precizie a detect, iei de corespondent, e).
6. Procesarea datelor RGB-D

Reprezentarea datelor RGB-D


Manipularea voxelilor

În acest laborator se vor analiza datele achiziţionate utilizându-se senzori cu lumină struc-
turată. Datele furnizate de astfel de senzori sunt compuse din informaţie vizuală, reprezen-
tată sub formă de imagini RGB, cât şi din distanţele cameră-suprafaţa vizualizată. Aceste
distanţe sunt codate sub forma unui canal adiţional D. Procesarea informat, iei vizuale 3D
se va efectua cu ajutorul librăriei Point Cloud Library (PCL) http://pointclouds.org/.
Instalarea ei se face ı̂n mod similar cu instalarea librăriei OpenCV, descrisă ı̂n aplicat, ia 1 a
acestui ı̂ndrumar.

6.1 Baze teoretice


Punctul, notat ı̂n continuare cu p, este cel mai simplu element care poate descrie o
informaţie ı̂ntr-un spaţiul n-dimensional. Complexitatea acestuia este dată de proprietăţile
ce ı̂l definesc. O primă proprietate fundamentală a acestuia este legată de pozit, ia sa geo-
metrică. Considerând spaţiul Euclidian 3 , punctul p poate fi definit utilizându-se cele trei
coordonate carteziene (x, y, z). În acest sens, punctul devine tridimensional. Cea de-a doua
proprietate de bază este reprezintă de culoare. Asemenea pixelului utilizat la reprezentarea
imaginilor, culoarea punctului p poate fi reprezentată prin cele trei culori fundamentale
(Roşu, Verde şi Albastru)1 . Mai multe astfel de puncte pot fi grupate pentru a se forma o
densitate de puncte, care poate fi analizată ulterior. O astfel de aglomerare de puncte este
denumită simbolic nor de puncte 2 şi va fi notată ı̂n continuare cu P . Spre exemplificare, ı̂n
Fig. 6.1 este prezentat un nor de puncte ce descrie o scenă uzuală. Aceasta a fost percepută
utilizându-se un senzor cu lumină structurată Microsoft Kinect .
Norii de puncte conţin informaţia de bază achiziţionată din scena vizualizată. Coordo-
natele [xi , yi , zi ] ale unui punct pi ∈ P sunt raportate faţă de un sistem de coordonate fix,
având de obicei originea ı̂n centrul senzorului utilizat la achiziţie. Acest lucru simbolizează
faptul că fiecare punct pi reprezintă distanţa pe cele 3 axe de coordonate de la senzorul
video la suprafaţa obiectului vizualizat. Unele dintre cele mai populare tehnici de măsurare
a distanţelor 3D sunt:
ˆ tehnici de triangulaţie, care estimează adâncimea (distanţa) prin identificarea punctelor
corespondente ı̂n imaginile percepute de către doi senzori diferiţi, la acelaşi moment
de timp (vezi aplicat, ia 5 din acest ı̂ndrumar);
ˆ sisteme cu lumină structurată, care estimează distanţa dintre obiect şi senzor prin
proiectarea unui şablon luminos cu structură cunoscută. Relaţia liniară dintre grosimea
liniilor proiectate şi distanta reală permite estimarea cu precizie a adâncimii obiectului,
relativ la senzor. Datorită influent, elor luminii naturale (ı̂n spectrul infraroşu) acest
tip de cameră poate fi utilizat doar ı̂n spaţii ı̂nchise;
1
Eng. RGB - Red, Green, Blue
2
Eng. Point Cloud
44 PROCESAREA DATELOR RGB-D

(a)

(b)
Fig. 6.1 Exemple de nori de puncte 3D.

ˆ senzorii Time-of-Flight (ToF), care măsoară distanţele 3D prin determinarea timpului


de ı̂ntârziere dintre transmiterea şi recepţionarea unui semnal. Cunoscându-se viteza
de propagare a semnalului, distanţa d dintre senzor şi un punct 3D se poate calcula
prin relaţiea:
c·t
d= (6.1)
2
unde c reprezintă viteza semnalului (e.g. viteza luminii ı̂n cazul senzorilor laser, sau cu
infraroşu), iar t este timpul de ı̂ntârziere dintre momentul de transmitere a semnalului
şi recepţionarea lui.
Odată achiziţionat un nor de puncte 3D, utilizându-se una dintre metodele mai sus
menţionate, acesta este stocat sub diferite forme impuse de aplicaţia ı̂n cauză. Un aspect
important legat de reprezentarea norilor de puncte este acela că ı̂n aceste structuri se pot
stoca multiple caracteristici ale punctelor. Spre exemplu, ı̂n cazul ı̂n care se utilizează un
senzor de lumină structurată, pe lângă caracteristica geometrică (de distanţă) punctul 3D
mai prezintă şi informaţie de culoare, normală la suprafaţă, grad de apartenenţă la un anumit
grup de puncte sau distanţa Euclidiană faţă de originea senzorului video. Astfel, definiţia
unui punct pi = [xi , yi , zi ] se poate generaliza după cum urmează:

pi = [f0 , f1 , f2 , . . . , fn ], (6.2)
unde fj reprezintă o caracteristică ı̂ntr-un anumit spaţiu de caracteristici, spre exemplu
poziţie, culoare, clasa de apartenenţă, etc. Structura unui nor de puncte P poate fi stocată
Cerinţe 45

sub formă matriceală:

⎡ ⎤
x 1 y 1 z 1 r 1 g 1 b 1 n x1 n y 1 n z 1 e1 d1 ···
⎢ ⎥
⎢ x 2 y 2 z 2 r 2 g 2 b 2 n x2 n y 2 n z 2 e2 d2 ··· ⎥
P =⎢

⎥. (6.3)
⎣ ··· ⎥

x N p y N p z N p r N p g N p b N p n x N p n yN p n z N p e N p d Np ···

unde x1 , y1 , z1 reprezintă coordonatele unui anumit punct 3D, r1 , g1 , b1 culoarea asociată


acestui punct, n este normala la suprafaţă, e1 clasa obiectului faţă de care punctul aparţine,
iar d1 distanţa senzor video - punct 3D.
Pentru a se putea ı̂nţelege geometria scenei ı̂n jurul unui anumit punct de interes pi , este
necesară descoperirea setului de vecini P k localizaţi ı̂n jurul punctului pi . Unele dintre cele
mai utilizate soluţii ı̂n acest scop este utilizarea tehnicilor de decompoziţie spatială ı̂n arbori
(”KD-tree” sau ”Octree”) şi ı̂nlocuirea punctelor 3D prin cuburi de dimensiuni constante.

6.2 Cerinţe
1. Utilizându-se librăria PCL, să se ı̂ncarce de pe HDD un nor de puncte RGB-D;
2. Să se elimine din nor punctele care nu conţin informaţie de adâncime;
3. Să se vizualizeze norul de puncte ı̂ncărcat;
3. Să se identifice centrul de greutate al norului de puncte;
4. Să se translateze norul ı̂n originea sistemului de coordonate;
5. Să se vizualizeze norul de puncte translatat.

6.3 Codul sursă al aplicat, iei

1 # include <s t d i o . h>


2 # include <i o s t r e a m >
3 # include <p c l / p o i n t t y p e s . h>
4 # include <p c l / p o i n t c l o u d . h>
5 # include <p c l / i o / p c d i o . h>
6 # include <p c l / v i s u a l i z a t i o n / c l o u d v i e w e r . h>
7 # include <p c l /common/common . h>
8 # include <p c l /common/ t r a n s f o r m s . h>
9 # include <p c l / f i l t e r s / f i l t e r . h>
10
11 using namespace pcl ;
12 using namespace std ;
13
14 int main ( int argc , char ** argv )
15 {
16 cout << " Laborator 6: Introducere in PCL" << endl ;
17
18 string strCaleFisier ;
19 PointXYZRGBA ptCentruDeGreutate ;
20
21 // C r e a r e a u n e i s t r u c t u r i de d a t e nor de puncte
22 PointCloud <PointXYZRGBA > : : Ptr nor_puncte ( new PointCloud <←
PointXYZRGBA >) ;
23
46 PROCESAREA DATELOR RGB-D

24 if ( argc != 2 )
25 {
26 cout<<" Usage: aplicatie <cale -fisier -RGBD >"<<endl ;
27 exit ( 0 ) ;
28 }
29 else
30 {
31 strCaleFisier = argv [ 1 ] ;
32 }
33
34 // I n c a r c a r e a unui nor de puncte 3D u t i l i z a n d l i b r a r i a PCL
35 if ( io : : loadPCDFile ( strCaleFisier . c_str ( ) , * nor_puncte ) )
36 cout << " Norul de puncte nu a putut fi citit." << endl ;
37 else
38 cout << " Norul de puncte contine : " << nor_puncte−>points . ←
size ( ) << " puncte 3D " << endl ;
39
40 // E l i m i n a r e a p u n c t e l o r cu v a l o a r e n u l a
41 vector <int> vIndex ;
42 removeNaNFromPointCloud ( * nor_puncte , * nor_puncte , vIndex ) ;
43 cout<<" Norul de puncte filtrat contine : " << nor_puncte−>points . ←
size ( ) << " puncte 3D " << endl ;
44
45 // V i z u a l i z a r e a n o r u l u i de puncte 3D
46 visualization : : CloudViewer viewer ( " Viualizarea grafica a norului←
de puncte " ) ;
47 viewer . showCloud ( nor_puncte ) ;
48 while ( ! viewer . wasStopped ( ) )
49 {}
50
51 // Determinarea c e n t r u l u i de g r e u t a t e a l s c e n e i
52 float fSumX = 0 . 0 f , fSumY = 0 . 0 f , fSumZ = 0 . 0 f ;
53
54 for ( unsigned int a = 0 ; a < nor_puncte−>points . size ( ) ; a ++)
55 {
56 fSumX += nor_puncte−>points [ a ] . x ;
57 fSumY += nor_puncte−>points [ a ] . y ;
58 fSumZ += nor_puncte−>points [ a ] . z ;
59 }
60 cout<<" Coordonate centru de greutate (X, Y, Z): " <<
61 fSumX / nor_puncte−>points . size ( ) << ", " <<
62 fSumY / nor_puncte−>points . size ( )<< " , "<<
63 fSumZ / nor_puncte−>points . size ( ) << endl ;
64
65 // S a l v a r e a c o o r d o n a t e l o r c e n t r u l u i de g r e u t a t e
66 ptCentruDeGreutate . x = fSumX / nor_puncte−>points . size ( ) ;
67 ptCentruDeGreutate . y = fSumY / nor_puncte−>points . size ( ) ;
68 ptCentruDeGreutate . z = fSumZ / nor_puncte−>points . size ( ) ;
69
70 // T r a n s l a t o a r e a n o r u l u i de puncte i n c o o r d o n a t e l e de o r i g i n e a l e ←
scenei
71 PointXYZ ptTranslation ;
Descrierea funcţiilor principale 47

72 ptTranslation . x = 0 − ptCentruDeGreutate . x ;
73 ptTranslation . y = 0 − ptCentruDeGreutate . y ;
74 ptTranslation . z = 0 − ptCentruDeGreutate . z ;
75
76 for ( unsigned int b = 0 ; b < nor_puncte−>points . size ( ) ; b++)
77 {
78 nor_puncte−>points [ b ] . x += ptTranslation . x ;
79 nor_puncte−>points [ b ] . y += ptTranslation . y ;
80 nor_puncte−>points [ b ] . z += ptTranslation . z ;
81 }
82
83 // V i z u a l i z a r e a n o r u l u i de puncte 3D
84 visualization : : CloudViewer viewer_2 ( " Viualizarea grafica a ←
norului de puncte " ) ;
85 viewer_2 . showCloud ( nor_puncte ) ;
86 while ( ! viewer_2 . wasStopped ( ) )
87 {}
88
89 return 0 ;
90 }
6.4 Descrierea funcţiilor principale

35 io : : loadPCDFile ( const string& file_name , PointCloud<PointT> &cloud )

Încarcă un fişier tip nor de puncte.


ˆ file name: fişierul sursă;
ˆ cloud: structura ı̂n care va fi ı̂ncărcat norul de puncte.
42 removeNaNFromPointCloud ( const PointCloud<PointT>& cloud_in , ←
PointCloud<PointT>& cloud_out , vector<int>& index )
ˆ cloud in: norul de puncte de intrare;
ˆ cloud out: norul de puncte filtrat;
ˆ index: vectorul cu indecşii punctelor valide din norul de puncte de intrare.
48 PROCESAREA DATELOR RGB-D
7. Alinierea robustă a densităţilor de
puncte 3D

Măsurarea distanţei dintre diferite forme geometrice 3D


Estimarea rotaţiei şi a translaţiei optime ı̂ntre nori de puncte
Prezentarea generală a algoritmului ICP
Alinierea parţială şi globală a formelor utilizându-se ICP

În lucrarea de fat, ă se vor studia metode de măsurare a distant, elor ı̂n interiorul norilor
de puncte 3D, estimarea rotat, iei s, i translat, iei dintre diferite densităt, i de puncte 3D, cât s, i
potrivirea a două densităt, i de puncte utilizându-se algoritmul Iterative Closest Point (ICP).

7.1 Baze teoretice


Cunoscându-se doi nori de puncte, M s, i P , fiecare reprezentat ı̂n sisteme de coordo-
nate proprii, se pune problema identificării transformatei de coordonate optime (rotat, ie s, i
translat, ie) care să permită alinierea lui M relativ la P . Metoda ICP [1, 25] prezintă o soluţie
eficientă şi rapidă pentru o astfel de problemă. Aceasta, utilizează un simplu proces de min-
imizare a distantei Euclidiene dintre punctele norului, cu scopul de a se aduce modelele
considerate ı̂ntr-un sistem de coordonate comun. Această abordarea nu este dependentă de
modul de reprezentare al formelor, permiţând astfel alinierea unui număr mare de tipuri de
date geometrice [1]. Dintre acestea se pot menţiona:
ˆ seturi de puncte;
ˆ segmente de dreaptă;
ˆ curbe implicite: g (x, y, z) = 0;
ˆ curbe parametrizate: (x(u), y(u), z(u));
ˆ seturi de triunghiuri (suprafeţe reprezentate prin intermediul unui set de triunghi-
uri(mesh));
ˆ suprafeţe implicite: g(x, y, z) = 0;
ˆ suprafeţe parametrizate: g(x(u, v), y(u, v), z(u, v)).
Din punct de vedere al aplicabilităţii, algoritmul poate fi utilizat cu succes la fuzionarea
diferitelor perspective ale unui obiect. Scopul unui astfel de proces de fuzionare poate fi fie
de a se obţine un volum rigid, fie de a se compara două sau mai multe scene ı̂ntre ele (pentru
determinarea similitudinilor sau a diferenţelor dintre scene), fie de stabilire a congruent, ei
dintre două sau mai multe forme (identificarea formelor echivalente), sau de a se estima
mişcarea ı̂n spat, iu a senzorului video.
Considerându-se un caz concret, metoda ICP poate furniza o măsură de confident, ă a
apartenenţei unei suprafeţe percepute (de exemplu, o parte a corpului uman) faţă de o
suprafaţă de referinţă (de exemplu, ı̂ntreg corpul uman). Acest proces poartă numele de
potrivire. În exemplul prezentat se recurge la o potrivire locală, deoarece suprafat, a percepută
corespunde doar unei anumite regiuni din suprafat, a de referint, ă. Similar, poate exista s, i o
50 ALINIEREA ROBUSTĂ A DENSITĂŢILOR DE PUNCTE 3D

potrivire globală, ı̂n care alinierea se produce ı̂ntre două suprafet, e cu structură constructivă
similară, ca s, i dimensiune (de exemplu, două siluete ale aceleias, i căni). Principial, cele 6
grade de libertate necesare unui proces de potrivire, 3 pentru rotat, ie s, i 3 pentru translat, ie,
sunt determinate utilizându-se corespondent, e de tipul celui mai apropiat vecin.

7.1.1 Măsurarea distanţei dintre diferite date geometrice


Identificarea celui mai apropiat vecin se realizează diferit pentru fiecare tip de dată, de
natură geometrică. Se consideră un nor P format din Np puncte 3D, notate cu pi : P = {pi },
unde i = 1, . . . Np , şi un nor M format din Nm puncte 3D, notate mj : M = {mj }, unde
j = 1, . . . Nm . Distanţa Euclidiană dintre punctele celor doi nori se determină după cum
urmează:

d(r1 , r2 ) = ||r1 − r2 ||2 = (x2 − x1 )2 + (y2 − y1 )2 + (z2 − z1 )2 , (7.1)
unde, r1 (x, y, z) s, i r2 (x, y, z) sunt două puncte oarecare aparţinând norilor M s, i P , iar d
este distant, a Euclidiană dintre puncte. Distant, a dintre punctul m ∈ M s, i cel mai apropiat
punct de pe suprafat, a P se calculează folosindu-se următoarea ecuat, ie:

d(m, P ) = min d(m, pi ). (7.2)


i∈1,...Np

Cel mai apropiat punct pi ∈ P satisface egalitatea d(m, pi ) = d(m, P ).

7.1.2 Estimarea rotaţiei şi a translaţiei optime ı̂ntre nori de puncte


Pe lângă procedura prezentată anterior, pentru estimare a celui mai apropiat vecin,
metoda ICP mai implică utilizarea unui proces de transformare init, ială a datelor geome-
trice. Considerându-se spat, iul tridimensional, identificarea rotat, iei s, i a translat, iei se poate
realiza eficient utilizându-se vectorii quaternion (q). În spat, iul cu 2 sau 3 dimensiuni vectorii
quaternion reprezintă o alternativă eficientă a unghiurilor Euler. Principalul lor avantaj este
reprezentat de simplitatea reprezentării lor, cât s, i timpul de calcul redus [19]. Utilizându-se
unghiurile Euler, rotat, ia unui corp poate fi obt, inută prin multiplicarea a trei rotat, ii, câte una
pentru fiecare unghi Euler. Utilizându-se quaternionul, rotat, ia se obt, ine ı̂ntr-o singură etapă,
care ı̂nglobează deja funct, iile trigonometrice sin s, i cos. Totodată, conversia din quaternion
ı̂ntr-o matrice de rotat, ie este eficientă. În această lucrare, va fi utilizată o solut, ie simplă
pentru determinarea rotat, iei s, i translat, iei, descrisă de Horn ı̂n [12] .
Algoritmul iterativ de aliniere ICP urmăres, te mutarea (ı̂nregistrarea) unei suprafet, e M
(suprafat, ă transformată) cu scopul de a o suprapune, ı̂ntr-o manieră ideală, peste o suprafat, ă
de referint, ă P . Nm s, i Np reprezintă numărul de puncte ce descriu suprafet, ele considerate.
Distant, a metrică d, măsurată ı̂ntre punctele individuale mi s, i suprafat, a P , se poate descrie
astfel:

d(m, P ) = min ||p − m||. (7.3)


p∈P

Punctul din P care satisface condit, ia de cel mai apropiat vecin se notează cu y. Acesta
trebuie să respecte condiţia d(m, y) = d(m, P ), unde y ∈ P .
Din punctul de vedere al intervalului de calcul, identificarea lui y se realizează ı̂n maxim
O(Np ), iar timpul total (a tuturor punctelor din M ) este reprezentat de O(Nm Np ). Cu toate
acestea, timpul de calcul estimat este O(log(Np ) · log(Np )). Fie Y un vector care conţine cele
Baze teoretice 51

mai apropiate puncte s, i C operatorul de cel mai apropiat punct, atunci se poate considera:

Y = C(M, P ). (7.4)
Cunoscând vectorul celor mai apropiate puncte Y , alinierea celor două suprafet, e, uti-
lizând metoda celor mai mici pătrate, se calculează după cum urmează:

(q, d) = Q(M, Y ). (7.5)


În continuare, setul de puncte M este actualizat utilizând afirmat, ia M = q(M ).

7.1.3 Prezentarea generală a algoritmului ICP


Fiind cunoscute aspectele descrise anterior, algoritmul de aliniere ICP poate fi descris,
pe scurt, după cum urmează:
ˆ se definesc datele de intrare sub forma a doi nori de puncte. Se notează cu M norul
translatat s, i cu P norul de referint, ă. Dimensiunile celor doi nori sunt Nm s, i Np ;
ˆ se realizează iniţializarea iteraţiilor din algoritm, prin setarea M0 = M , q0 = [1.0, 0.0, 0.0, 0.0]t ,
s, i k = 0. Vectorii de aliniere sunt definit, i relativ la setul translatat M0 , astfel ı̂ncât
alinierea finală să reprezinte transformarea completă. Sunt aplicate etapele (a), (b),
(c) s, i (d) până când algoritmul converge către un minim, cu o toleranţă τ :
a. se calculează cel mai apropiat punct: Yk = C(Mk , P ) (timp maxim de calcul:
O(Nm Np ), timp mediu de calcul: O(Nm log Np );
b. se calculează matricea de transformare utilizată ı̂n procesul de aliniere: (q, dk ) =
Q(M0 , Yk ) (timp de calcul: O(Nm ));
c. se realizează alinierea: Pk+1 = qk (P0 ) (timp de calcul: O(Nm ));
d. dacă eroarea medie pătratică dintre punctele considerate şi cele de referinţă scade
sub o valoare de prag τ > 0 algoritmul se ı̂ncheie. Precizia procesului de aliniere
se determină ţinându-se cont de: dk − dk+1 < τ .

7.1.4 Alinierea parţială şi globală a formelor utilizându-se ICP


Acurateţea şi rapiditatea procesului de aliniere sunt dependente de structura formelor
implicate. Contextual, pot exista două situaţii distincte:
ˆ norul translatat descrie o formă globală similară cu acea a norului de referinţă;
ˆ norul translatat descrie o anumită regiune din norul de referinţă.
Aplicarea algoritmului ı̂n primul caz presupune, pe de o parte, translatarea centrului de masă
μm al formei M peste centrul de masă μp al formei P , iar, pe de altă parte, identificarea
setului de rotaţii optime care produc o eroare de potrivire (convergenţă) minimă. Cu toate
acestea, suprapunerea centrelor de masă nu este obligatorie. Se poate recurge la o pre-
translat, ie, utilizându-se un set de rotaţii iniţiale. Un exemplu de aliniere a doi nori de
puncte care ı̂nfăţişează silueta a două căni diferite este prezentat ı̂n Fig. 7.1. Cănile sunt
vizualizate din aceeaşi perspectivă. Eroarea de potrivire pentru cazul considerat este de
3.1866 · e−5 .
O problemă des ı̂ntâlnită ı̂n procesele de aliniere apare ı̂n momentul ı̂n care doar o mică
parte din punctele formei M au corespondent (cel mai apropiat vecin) ı̂n forma P . Un caz real
este acela ı̂n care se ı̂ncearcă alinierea unei mici port, iuni a unei căni relativ la o formă rigidă
(reprezentată printr-o structură globală). Totus, i, dacă regiunea potrivită prezintă suficient
de multe particularităţi, algoritmul ICP poate converge optim către un minim local. Trebuie
remarcat faptul că numărul de translaţii necesar este considerabil mai mare, deoarece cele
două centre de masă nu se mai comportă ı̂n mod similar. Un exemplu de aliniere, ı̂ntre o
52 ALINIEREA ROBUSTĂ A DENSITĂŢILOR DE PUNCTE 3D

(a) Vedere de sus

Vedere laterală
(b) (c)

Fig. 7.1 Alinierea a două suprafet, e cu siluete similare. (a) Model translatat (M ). (b) Model de
referint, ă (P ). (c) Modele aliniate utilizându-se metoda ICP.

suprafaţă rigidă şi o suprafaţă care descrie doar o anumită regiune a acesteia, este prezentat
ı̂n figura 7.2. Eroarea de potrivire pentru cazul considerat este egală cu 7.489 · e−8 .

7.2 Cerinţe
1. Să se ı̂ncarce doi nori de puncte de pe HDD;
2. Să se scrie utilizeze metoda ICP din librăria PCL pentru alinierea celor doi nori de
puncte;
3. Să se translateze s, i să se rotească un nor de puncte, fat, ă de celălalt, utilizându-se
matricea de transformare returnată de algoritmul ICP.

7.3 Codul sursă al aplicaţiei

1 # include <p c l / p o i n t t y p e s . h>


2 # include <p c l / p o i n t c l o u d . h>
3 # include <p c l / i o / p c d i o . h>.h>
4 # include <p c l / k d t r e e / impl / k d t r e e f l a n n . hpp>
5 # include <p c l / r e g i s t r a t i o n / i c p . h>
6
7 using namespace pcl ;
8 using namespace std ;
9
10 typedef PointXYZRGBA PclPointType ;
11 typedef PointCloud<PclPointType> PclCloud ;
12
13 PclCloud : : Ptr cloud_model ( new PclCloud ) ;
14 PclCloud : : Ptr cloud_aliniat ( new PclCloud ) ;
15 PclCloud cloud_rezultat ;
Codul sursă al aplicaţiei 53

(a) Vedere de sus

Vedere laterala
(b) (c)

Fig. 7.2 Alinierea unei regiuni la o suprafat, ă rigidă. (a) Model translatat (M ). (b) Model de
referint, ă (P ). (c) Modele aliniate utilizându-se metoda ICP.

16 double dConvergenta ;
17 Eigen : : Matrix4f transformare_ICP ;
18 float fDistMaxACorresp = 0 . 5 f ;
19 int nMaxIteratii = 1 0 0 0 ;
20
21 Eigen : : Matrix4f AliniereICP ( PclCloud : : Ptr cloud_model , PclCloud &←
cloud_aliniat , double &dConvergenta , int nMaxIteratii , float ←
fDistMaxACorresp )
22 {
23 Eigen : : Matrix4f transformare ;
24
25 PclCloud : : Ptr pCloud_aliniat ( new PclCloud ) ;
26 copyPointCloud ( cloud_aliniat , * pCloud_aliniat ) ;
27
28 // C l a s a a l g o r i t m u l u i ICP
29 IterativeClosestPoint<PclPointType , PclPointType> icp ;
30
31 // S t a b i l i r e a n o r u l u i de r e f e r i n t a
32 icp . setInputCloud ( cloud_model ) ;
33
34 // S t a b i l i r e a n o r u l u i t r a n s l a t a t ( a l i n i a t )
35 icp . setInputTarget ( pCloud_aliniat ) ;
36
37 // C o r e s p o n d e n t e l e cu d i s t a n t a mai mare d e c a t p r a g u l s t a b i l i t vor ←
fi rejectate
54 ALINIEREA ROBUSTĂ A DENSITĂŢILOR DE PUNCTE 3D

38 icp . setMaxCorrespondenceDistance ( fDistMaxACorresp ) ;


39
40 // S t a b i l i r e a numarului maxim de i t e r a t i i
41 icp . setMaximumIterations ( nMaxIteratii ) ;
42
43 // S e t a r e a f a c t o r u l e p s i l o n a l t r a n f o r m a r i i de s i m i l a r i t a t e
44 icp . setTransformationEpsilon ( 1 e−8) ;
45
46 PointCloud<PclPointType> Final ;
47
48 // A p l i c a r e a a l g o r i t m u l u i ICP
49 icp . align ( Final ) ;
50
51 cout << " Convergenta : " << icp . hasConverged ( ) << " avand confidenta←
: " << icp . getFitnessScore ( ) << endl ;
52
53 // S a l v a r e a v a l o r i i c o n v e r g e n t e i
54 dConvergenta = icp . getFitnessScore ( ) ;
55
56 // Retu rnar ea m a t r i c e i de t r a n s f o r m a r e d e t e r m i n a t a p r i n ICP
57 return icp . getFinalTransformation ( ) ;
58 }
59
60 int main ( int argc , char ** argv )
61 {
62 cout<<" Laborator 7: Alinierea suprafetelor "<<endl ;
63
64 string strCaleCloudA , strCaleCloudB , strCaleSalvareRezultat ;
65
66 if ( argc !=4)
67 {
68 cout<<" Utilizare : aplicatie <cale_nor_A .pcd > <cale_nor_B .pcd > <←
cale_salvare_nori_aliniati .pcd >"<<endl ;
69 exit ( 0 ) ;
70 }
71 else
72 {
73 strCaleCloudA = argv [ 1 ] ;
74 strCaleCloudB = argv [ 2 ] ;
75 strCaleSalvareRezultat = argv [ 3 ] ;
76 }
77
78 // C i t i r e a p r i m u l u i nor de puncte
79 if ( io : : loadPCDFile ( strCaleCloudA . c_str ( ) , * cloud_model ) )
80 cout<<" Norul de puncte nu a putut fi citit ."<<endl ;
81
82 // C o l o r a r e nor de puncte i n albastru
83 for ( unsigned int a = 0 ; a < cloud_model−>points . size ( ) ; a++)
84 {
85 cloud_model−>points [ a ] . r = 0;
86 cloud_model−>points [ a ] . g = 0;
87 cloud_model−>points [ a ] . b = 255;
Descrierea funcţiilor principale 55

88 }
89
90 // C i t i r e a c e l u i de−a l d o i l e a nor de puncte
91 if ( io : : loadPCDFile ( strCaleCloudB . c_str ( ) , * cloud_aliniat ) )
92 cout<<"Norul de puncte nu a putut fi citit."<<endl ;
93
94 // C o l o r a r e nor de puncte i n rosu
95 for ( unsigned int b = 0 ; b < cloud_aliniat−>points . size ( ) ; b++)
96 {
97 cloud_aliniat−>points [ b ] . r = 255;
98 cloud_aliniat−>points [ b ] . g = 0;
99 cloud_aliniat−>points [ b ] . b = 0;
100 }
101
102 // A l i n i e r e ICP
103 transformare_ICP = AliniereICP ( cloud_model , * cloud_aliniat , ←
dConvergenta , 3 0 0 , 0 . 0 5 ) ;
104
105 // O p e r a t i a de t r a n s f o r m a r e c e a l i n i a z a c l o u d a l i n i a t l a ←
cloud model
106 transformPointCloud ( * cloud_aliniat , * cloud_aliniat , ←
transformare_ICP ) ;
107
108 // S a l v a r e a n o r i l o r c l o u d m o d e l s i c l o u d a l i n i a t i n t r −un s i n g u r nor←
de puncte
109 for ( unsigned int i = 0 ; i < cloud_model−>points . size ( ) ; i++)
110 cloud_rezultat . push_back ( cloud_model−>points [ i ] ) ;
111
112 for ( unsigned int j = 0 ; j < cloud_aliniat−>points . size ( ) ; j++)
113 cloud_rezultat . push_back ( cloud_aliniat−>points [ j ] ) ;
114
115 io : : savePCDFile ( strCaleSalvareRezultat . c_str ( ) , cloud_rezultat ) ;
116
117 return 0 ;
118 }
7.4 Descrierea funcţiilor principale

21 Eigen : : Matrix4f AliniereICP ( PclCloud : : Ptr cloud_model , PclCloud &←


cloud_aliniat , double &dConvergenta , int nMaxIteratii , float ←
fDistMaxACorresp )
Această funcţie are rolul de a alinia un nor de puncte oarecare (cloud aliniat) la un nor de
puncte de referinţă (cloud model ). Parametrul dConvergenta returnează măsura potrivirii
celor doi nori de puncte sub forma unei erori de distanţă. Acest parametru descrie eroare
de potrivire ce poate exista ı̂nre suprafeţele celor doi nori de puncte, după ce aceştia au fost
aliniaţi.
ˆ cloud model: nor de puncte de referint, ă. Asupra acestuia nu trebuie să se aplice nicio
transformare de similaritate (coordonate);
ˆ cloud aliniat: nor de puncte ce urmează a fi transformat pentru a se suprapune
peste norul de puncte de referint, ă;
ˆ dConvergenta: returnează potrivirea dintre punctele celor doi nori;
ˆ nMaxIteratii: numărul maxim de iterat, ii a algoritmului ICP;
56 ALINIEREA ROBUSTĂ A DENSITĂŢILOR DE PUNCTE 3D

ˆ fDistMaxACorresp: distant, a maximă dintre punctele celor doi nori.


79 io : : loadPCDFile ( const string& file_name , PointCloud<PointT> &cloud ) ;

Încarcă un fişier tip nor de puncte.


ˆ file name: calea către fişierul sursă;
ˆ cloud: structura ı̂n care va fi ı̂ncărcat norul de puncte.
106 transformPointCloud ( const pcl : : PointCloud< PointT > &cloud_in , pcl : : ←
PointCloud< PointT > &cloud_out , Eigen : : Matrix4f &transform )
Aplică o transformare rigidă (rotat, ie s, i translat, ie), definită prin intermediul unei matrice
de transformare 4 × 4.
ˆ cloud in: norul sursă (care urmează a fi transformat);
ˆ cloud out: norul transformat;
ˆ transform: matricea de transformare.
115 io : : savePCDFile ( const std : : string &file_name , const pcl : : PointCloud< ←
PointT > &cloud )
Salvează un nor de puncte ı̂ntr-un fis, ier *.pcd.
ˆ file name: calea către fis, ierul destinat, ie;
ˆ cloud: norul de puncte ce urmează a fi salvat.
8. Segmentarea prin partiţionare a
norilor de puncte

Identificarea suprafeţelor plane din scena de lucru


Segmentarea prin partiţionare a datelor RGB-D

În această sect, iune se va prezenta o metodă de segmentare a norilor de puncte ı̂n funct, ie
de densităt, ile de puncte ce formează diferite obiecte ı̂n scena vizualizată prin senzori de
lumină structurată.

8.1 Baze teoretice


Scenele complexe conţin adesea un număr mare de obiecte sau de elemente necunoscute.
Reprezentarea unei astfel de scene ı̂ntr-un mediu virtual implică utilizarea unui nor de puncte
de o dimensiune mare. În consecinţă, operaţia de manipulare sau analiză a norului devine
costisitoare, atât din punct de vedere al timpului de procesare, cât s, i din punct de vedere al
puterii de calcul. O soluţie posibilă a acestor probleme constă ı̂n partit, ionarea norului P , ce
descrie scena iniţială, ı̂ntr-o serie de grupuri compacte de puncte 3D1 . Avantajele unei astfel
de abordări sunt date de interpretarea rapidă a datelor s, i de posibilitatea grupării punctelor
cu proprietăţi similare (culoare, curbură, etc.).
Procesul de grupare compactă a punctelor 3D poate fi considerat ca o segmentare trivială
a spat, iului Euclidian. Rezultatul unei astfel de segmentări este un set O de grupuri compacte,
fiecare conţinând puncte cu proprietăt, i similare.

8.1.1 Identificarea suprafeţelor plane din scena de lucru


O primă problemă, ı̂n contextul segmentării norilor de puncte, constă ı̂n identificarea
suprafet, elor plane din scenă. Exceptând cazurile ı̂n care suprafeţele plane sunt folosite la
navigarea roboţilor sau ı̂n evitarea obstacolelor, acestea constituie date redundante s, i pot
fi eliminate. O metodă robustă de identificare a suprafet, elor plane utilizând imagini RGB-
D (Red, Green, Blue, Depth) este prezentată ı̂n lucrările [11, 24] şi presupune parcurgerea
următoarelor etape:
ˆ selectarea aleatoare a trei puncte ne-colineare {pi , pj , pk } din norul de puncte P al
scenei;
ˆ calcularea coeficienţilor modelului planului, utilizându-se cele trei puncte definite an-
terior (ax + by + cz + d = 0);
ˆ determinarea distanţei euclidiene dintre toate punctele p ∈ P şi modelul planului
(a, b, c, d);
ˆ calcularea numărului de puncte p∗ ∈ P , puncte a căror distanţă până la plan respectă
condit, ia 0 ≤ |d| ≤ |dth |, unde dth reprezintă un prag de distanţă definit de utilizator.
1
Eng. Clusters
58 SEGMENTAREA PRIN PARTIŢIONARE A NORILOR DE PUNCTE

Etapele prezentate anterior sunt efectuate de k ori. Rezultatul unui proces de segmentare
a suprafeţelor plane este prezentat ı̂n Fig. 8.1. Cu lini roşi sunt definite laturile paralelogra-
mului care defineşte suprafaţa plană estimată, ı̂n timp ce cu albastru sunt colorate punctele
3D a căror distantă faţă de planul considerat respectă condiţiile impuse (inliers).

(a) (b)

Fig. 8.1 Identificarea suprafeţelor plane din scena de lucru. (a) Norul de puncte
iniţial. (b) Suprafaţa plană estimată.

8.1.2 Segmentarea prin partiţionare a datelor RGB-D


Procesul de segmentare a suprafeţelor plane prezentat anterior este doar un pas pre-
mergător obţinerii grupurilor compacte de puncte. Obiectivul real este acela de a se partiţiona
un nor de puncte P ı̂ntr-o serie de grupuri cu dimensiuni mai mici. O metodă simplă s, i efi-
cientă de formare a grupurilor compacte de puncte este prezentată ı̂n [20]. Metoda poate
fi folosită doar pentru aplicaţiile care necesită subdiviziuni spat, iale egale. Pentru grupuri
compacte cu dimensiuni variabile, algoritmul devine mai complex. Avându-se ı̂n vedere
obiectivul de partiţionare a spaţiului, cu scopul identificării obiectelor care pot fi manipu-
late, sistemul trebuie să facă distincţia ı̂ntre un nor de puncte obiect şi celelalte densităt, i de
puncte scenă. Un grup de puncte Oi = {Pi ∈ P } poate fi considerat, din punct de vedere
matematic, distinct faţă de un alt grup Oj = {Pj ∈ P } dacă şi numai dacă:

min ||Pi − Pj || ≥ dth (8.1)


unde, dth este distant, a maximă dintre două puncte ce aparţin aceluiaşi grup compact.
Apropierea dintre două sau mai multe puncte 3D poate fi determinată utilizându-se o struc-
tură de tipul kd-tree [23]. Algoritmul de extragere al grupurilor compacte de puncte pre-
supune parcurgerea următoarelor etape:
1. crearea unei structuri arborescente de căutare, de tipul kd-tree, utilizându-se norul P
al scenei;
2. crearea unei liste goale C, menită să stocheze grupurile compacte care vor fi identificate,
cât şi definirea unei stive Q cu punctele care urmează a fi verificate;
3. parcurgerea, pentru fiecare punct pi din setul Pi , a următorilor paşi:
ˆ adăugarea lui pi la stiva Q;
ˆ pentru fiecare pi ∈ Q trebuie să se realizeze:
– o căutare a unui set de vecini Pik , ı̂ntr-un perimetru sferic, cu raza r < dth ;
– verificarea, pentru fiecare punct vecin pki ∈ Pik , procesării punctului pi . În
situaţia ı̂n care punctul considerat nu a fost procesat acesta este adăugat ı̂n
lista Q;
Cerinţe 59

ˆ verificarea procesării tuturor punctelor din Q. Dacă această operaţie a fost făcută
cu succes Q este adăugat ı̂n lista grupurilor compacte C. Se şterge Q pentru a se
ı̂ncepe o nouă iteraţie;
4. terminarea algoritmului presupune că toate punctele din Pi să fi fost procesate, cât s, i
includerea acestora ı̂n lista de grupuri compacte C.
În Fig. 8.2 se pot observa mai multe densităţi de puncte compacte, reprezentând diferite
obiecte de uz general, extrase cu ajutorul algoritmului de estimare a grupurilor compacte de
puncte. Conform premizelor expuse anterior, obiectele au fost situate pe o suprafaţă plană
(masă).

(a) (b)

Fig. 8.2 Segmentarea prin partiţionare a norilor de puncte. (a) Nor de puncte
iniţial. (b) Grupuri (clustere) de puncte segmentate.

8.2 Cerinţe
1. Să se ı̂ncarce un nor de puncte de pe HDD;
2. Să se segmenteze suprafet, ele plane din norul de puncte;
3. Să se grupeze densităt, iile de puncte ı̂n funct, ie de distant, a euclidiană dintre ele;
4. Să se salveze s, i să se vizualizeze scene segmentată.

8.3 Codul sursă al aplicaţiei

1 # include <s t d i o . h>


2 # include <i o s t r e a m >
3 # include <c s t d l i b >
4 # include <b o o s t / thread . hpp>
5 # include <p c l / v i s u a l i z a t i o n / c l o u d v i e w e r . h>
6 # include <p c l / i o / p l y i o . h>
7 # include <p c l / M o d e l C o e f f i c i e n t s . h>
8 # include <p c l / p o i n t t y p e s . h>
9 # include <p c l / i o / p c d i o . h>
10 # include <p c l / f i l t e r s / e x t r a c t i n d i c e s . h>
11 # include <p c l / f i l t e r s / v o x e l g r i d . h>
12 # include <p c l / f e a t u r e s / normal 3d . h>
13 # include <p c l / k d t r e e / k d t r e e . h>
14 # include <p c l / s a m p l e c o n s e n s u s / method types . h>
15 # include <p c l / s a m p l e c o n s e n s u s / m o d e l t y p e s . h>
16 # include <p c l / s e g m e n t a t i o n / s a c s e g m e n t a t i o n . h>
17 # include <p c l / s e g m e n t a t i o n / e x t r a c t c l u s t e r s . h>
60 SEGMENTAREA PRIN PARTIŢIONARE A NORILOR DE PUNCTE

18
19 using namespace pcl ;
20 using namespace std ;
21
22 typedef PointXYZRGBA PclPointType ;
23 typedef PointCloud<PclPointType> PclCloud ;
24
25 PclCloud : : Ptr cloud ( new PclCloud ) ;
26 PclCloud : : Ptr cluster_cloud ( new PclCloud ) ;
27
28 void extractClusters ( PclCloud : : Ptr cloud , float fGranularitate , ←
vector<PointIndices>& indecsi_clustere , PclCloud &cloud_filtrat , ←
bool bDownsample )
29 {
30 indecsi_clustere . clear ( ) ;
31 PclCloud : : Ptr pCloud_filtrat ( new PclCloud ) ;
32
33 if ( bDownsample == true )
34 {
35 // C r e a r e a s t r u c t u r i i de d a t e c e va c o n t i n e n o r u l de puncte ←
filtrat
36 VoxelGrid<PclPointType> vg ;
37
38 vg . setInputCloud ( cloud ) ;
39
40 // A p l i c a r e a u n e i g r a n u l a r i t a t i de 1 cm
41 vg . setLeafSize ( fGranularitate , fGranularitate , fGranularitate ) ;
42 vg . filter ( * pCloud_filtrat ) ;
43 }
44 else
45 {
46 vector< int > index ;
47 removeNaNFromPointCloud ( * cloud , * pCloud_filtrat , index ) ;
48 }
49
50 // C r e a r e a s t r u c t u r i i de d a t e n e c e s a r a s e g m e n t a r i i s u p r a f e t e l o r ←
plane
51 SACSegmentation<PclPointType> seg ;
52 PointIndices : : Ptr inliers ( new PointIndices ) ;
53 ModelCoefficients : : Ptr coeficienti ( new ModelCoefficients ) ;
54 PointCloud<PclPointType > : : Ptr cloud_suprafata_plana ( new PointCloud ←
<PclPointType> ( ) ) ;
55 seg . setOptimizeCoefficients ( true ) ;
56 seg . setModelType ( SACMODEL_PLANE ) ;
57 seg . setMethodType ( SAC_RANSAC ) ;
58 seg . setMaxIterations ( 1 0 0 ) ;
59 seg . setDistanceThreshold ( 0 . 0 2 ) ;
60
61 int i=0, nr_points = ( int ) pCloud_filtrat−>points . size ( ) ;
62 while ( pCloud_filtrat−>points . size ( ) > 0 . 3 * nr_points )
63 {
64 // Segmentarea c e l e i mai mari s u p r a f e t e p l a n e
Codul sursă al aplicaţiei 61

65 seg . setInputCloud ( pCloud_filtrat ) ;


66 seg . segment ( * inliers , * coeficienti ) ;
67 if ( inliers−>indices . size ( ) == 0 )
68 break ;
69
70 // E x t r a g e r e a p u n c t e l o r d i n s c e n a c e s e a f l a c e l mai aproape de ←
p l a n u l model e s t i m a t
71 ExtractIndices<PclPointType> extract ;
72 extract . setInputCloud ( pCloud_filtrat ) ;
73 extract . setIndices ( inliers ) ;
74 extract . setNegative ( false ) ;
75
76 // S a l v a r e a n o r u l u i de puncte c e d e s c r i e s u p r a f a t a p l a n a
77 extract . filter ( * cloud_suprafata_plana ) ;
78
79 // E l i m i n a r e a p u n c t e l o r s u p r a f e t e i p l a n e
80 extract . setNegative ( true ) ;
81 extract . filter ( * pCloud_filtrat ) ;
82 cloud_filtrat = * pCloud_filtrat ;
83 }
84
85 // C r e a r e a u n e i s t r u c t u r i a r b o r e s c e n t a kd−t r e e p e n t r u i d e n t i f i c a r e a ←
c e l u i mai a p r o p i a t v e c i n
86 search : : KdTree<PclPointType > : : Ptr arbore ( new search : : KdTree<←
PclPointType >) ;
87 arbore−>setInputCloud ( pCloud_filtrat ) ;
88
89 EuclideanClusterExtraction<PclPointType> ec ;
90 ec . setClusterTolerance ( 0 . 0 2 ) ; // D i s t a n t a maxima d i n t r e puncte
91 ec . setMinClusterSize ( 1 0 0 ) ; // Dimensiunea minima a u n e i ←
d e n s i t a t i de puncte
92 ec . setMaxClusterSize ( 5 0 0 0 0 ) ; // Dimensiunea maxima a u n e i ←
d e n s i t a t i de puncte
93 ec . setSearchMethod ( arbore ) ;
94 ec . setInputCloud ( pCloud_filtrat ) ;
95 ec . extract ( indecsi_clustere ) ;
96 }
97
98 int main ( int argc , char ** argv )
99 {
100 cout << " Laborator 8: Segmentarea norilor de puncte 3D" << endl ;
101
102 string strCaleCloud ;
103 PclCloud : : Ptr cloud_filtrat ( new PclCloud ) ;
104 vector<PointIndices> indecsi_clustere ; // Contine i n d i c i i ←
punctelor c l u s t e r e l o r estimate
105 float fGranularitate = 0 . 0 0 1 ; // G r a n u l a r i t a t e a n o r u l u i de ←
puncte ( 1 mm)
106 char buffer [ 1 0 ] , buffer2 [ 1 0 ] ;
107
108 if ( argc !=2)
109 {
62 SEGMENTAREA PRIN PARTIŢIONARE A NORILOR DE PUNCTE

110 cout<<" Utilizare : aplicatie <cale_nor_sursa .pcd >"<<endl ;


111 exit ( 0 ) ;
112 }
113 else
114 {
115 strCaleCloud = argv [ 1 ] ;
116 }
117
118 // I n c a r c a r e a unui nor de puncte
119 if ( io : : loadPCDFile ( strCaleCloud . c_str ( ) , * cloud ) )
120 cout << "Norul de puncte nu a putut fi citit." << endl ;
121
122 // P a r t i t i o n a r e a n o r u l u i de puncte
123 extractClusters ( cloud , fGranularitate , indecsi_clustere , * ←
cloud_filtrat , true ) ;
124 cout << " Numarul de clustere = " << indecsi_clustere . size ( ) << endl←
;
125
126 // S a l v a r e a s i v i z u a l i z a r e a c l u s t e r e l o r
127 for ( unsigned int i = 0 ; i < indecsi_clustere . size ( ) ; i++)
128 {
129 sprintf ( buffer , "%d.pcd" , i ) ;
130 sprintf ( buffer2 , "%d.ply" , i ) ;
131 copyPointCloud ( * cloud_filtrat , indecsi_clustere [ i ] , * ←
cluster_cloud ) ;
132
133 visualization : : CloudViewer vizualizator ( " Viualizarea grafica a ←
norului de puncte segmentat " ) ;
134 vizualizator . showCloud ( cluster_cloud ) ;
135 while ( ! vizualizator . wasStopped ( ) )
136 {}
137
138 io : : savePLYFile<PointXYZRGBA >(buffer2 , * cluster_cloud , true ) ;
139 io : : savePCDFile<PointXYZRGBA >(buffer , * cluster_cloud , true ) ;
140 cluster_cloud−>clear ( ) ;
141 }
142
143 // S a l v a r e a i n t r e g i i s c e n e
144 io : : savePLYFile<PointXYZRGBA >(" scena .ply" , * cloud , true ) ;
145
146 return 0 ;
147 }
8.4 Descriere codului sursă

28 extractClusters ( cloud , fGranularitate , indecsi_clustere , ←


cloud_filtrat ) ;
Partiţionează norul de puncte al scenei de lucru ı̂ntr-o serie de grupuri compacte de uncte
3D2 . Fiecare grup de puncte segmentat descrie un obiect aflat pe o suprafat, ă plană. Codul
sursă al acestei metode poate fi găsit la adresa http://pointclouds.org/documentation/
tutorials/cluster_extraction.php#cluster-extraction
2
Eng. Clusters
Descriere codului sursă 63

ˆ cloud: nor de puncte ı̂nfăţişând scena de lucru;


ˆ fGranularitate: granularitatea finală a grupurilor de puncte extrase (de exemplu
0.01m = 1cm);
ˆ indecsi clustere: indecşii punctelor fiecărui grup de puncte segmentat;
ˆ cloud filtrat: norul de puncte ce descrie grupurile de puncte segmentate.
131 copyPointCloud ( const pcl : : PointCloud< PointT > &cloud_in , const std←
: : vector< int > &indices , pcl : : PointCloud< PointT > &cloud_out ) ;
Copiază o structură de tip nor de puncte ı̂ntr-o altă structură de acelaşi tip.
ˆ cloud in: nor de puncte sursă;
ˆ indices: indecşii punctelor care urmează a fi copiate. Dacă nu este furnizat nici un
index, atunci toate punctele din norul sursă vor fi copiate ı̂n norul destinaţie;
ˆ cloud out: nor de puncte destinaţie.
138 io : : savePLYFile<PointXYZRGBA >(const std : : string &file_name , const pcl←
: : PointCloud< PointT > &cloud ) ;
Salvează ı̂ntr-un fişier cu extensia *.ply norul de puncte segmentat. Acest fişier poate fi
citit mai departe de majoritatea programelor de modelare grafică precum MeshLab.
ˆ file name: calea către fişierul destinaţie. Aceasta, trebuie să conţină la sfârşitul
numelui extensia .ply;
ˆ cloud: norul de puncte care urmează a fi salvat.
64 SEGMENTAREA PRIN PARTIŢIONARE A NORILOR DE PUNCTE
9. Detectarea feţelor ı̂n imagini

Metode de clasificare
Detectarea fet, elor utilizând clasificatori ı̂n cascadă

În acest laborator se va studia o metodă de detectare a fet, elor ı̂n imagini gri utilizându-se
algoritmi de clasificare a caracteristicilor vizuale.

9.1 Baze teoretice


În lucrare de fat, ă este utilizată metoda dezvoltată de Viola şi Jones [22], ulterior com-
pletată de Rainer şi Mazdt [16], ı̂n care au fost propuse implementări ale unor noi algoritmi
pentru detecţia de obiecte ı̂n timp real. Avantajul acestei noi modalităţi de detecţie este
acela că algoritmii folosit, i au un grad de detecţie foarte ridicat şi pot fi aplicaţi pentru orice
tip de obiect. Una dintre aplicaţiile unde pot fi utilizate metodele propuse este aceea a
detectării fizionomiei şi caracteristicilor faciale. Metoda pentru detectarea fizionomiei are la
bază clasificatorul AdaBoost [5] şi caracteristici de tip Haar [16, 22], fiind cunoscută şi sub
denumirea de clasificator Haar [2].
Algoritmul pentru detecţia de obiecte propus de Viola şi Jones [22] are la bază caracteris-
tici, motivaţia alegerii acestora ı̂n detrimentul alegerii directe a pixelilor fiind dată de faptul
că, pe de o parte, caracteristicile pot fi codificate ı̂n aşa fel ı̂ncât să conţină ı̂ntr-un singur
loc mai multe informaţii iar, pe de altă parte, viteza de procesare este superioară utilizării
directe a pixelilor. În Fig. 9.1 sunt prezentate caracteristicile utilizate de algoritm pentru
detectarea fizionomiei.

1. Caracteristici de tip muchie

2. Caracteristici de tip linie

3. Caracteristici centrale înconjurate

Fig. 9.1 Caracteristici de tip Haar utilizate la detectarea de obiecte [2, 16].
66 DETECTAREA FEŢELOR ÎN IMAGINI

Caracteristicile utilizate pentru prima dată ı̂n [22] şi care pot fi folosite la detectarea
fizionomiei umane au suferit o serie de modificări. Acest lucru se datorează, ı̂n principal,
faptului că la prima apariţie a metodei au fost introduse doar caracteristici rectangulare,
având o reprezentare de la două până la patru module. Asupra acestei modalităţi de re-
prezentare iniţiale au apărut modificări ı̂n [16], lucrare ı̂n care s-a eliminat modelul rec-
tangular cu patru module şi a fost definită o nouă modalitate de reprezentare, sub forma
unor caracteristici Haar rotite. Introducerea acestei noi reprezentări conduce la o creştere a
performanţelor sistemului (şi anume la reducerea numărului de detectări incorecte) cu până
la 10%. Astfel, după cum se poate vedea şi ı̂n Fig. 9.1, se poate discuta despre 14 prototipuri
de caracteristici.

9.2 Cerinţe
1. Să se ı̂ncarce o imagine color;
2. Să se convertească imaginea color ı̂ntr-o imagine gri;
3. Să se instant, ieze s, i să se ı̂ncarce un clasificator Haar de detectare a fet, elor;
4. Să se detecteze fet, ele ı̂n imaginea gri utilizând clasificatorul Haar;
5. Să se afis, eze regiunile fet, elor detectate.

9.3 Codul sursă al aplicat, iei

1 # include <i o s t r e a m >


2 # include <s t d i o . h>
3 # include " opencv2 / objdetect / objdetect .hpp"
4 # include " opencv2 / highgui / highgui .hpp"
5 # include " opencv2 / imgproc / imgproc .hpp"
6
7 using namespace cv ;
8 using namespace std ;
9
10 int main ( void )
11 {
12 cout << "SVA Laborator 09: Detectarea fetelor in imagini " << endl ;
13
14 // I n c a r c a r e i m a g i n e
15 Mat img_in = imread ( " imagine .jpg" ) ;
16
17 if ( img_in . empty ( ) )
18 {
19 cout << " Imaginea nu a putut fi incarcata " << endl ;
20 return false ;
21 }
22
23 // D e f i n i t i a s i i n i t i a l i z a r e a c l a s i f i c a t o r u l u i
24 CascadeClassifier clasificator_haar ;
25
26 if ( ! clasificator_haar . load ( " haarcascade_frontalface_alt .xml" ) )
27 {
28 cout << " Clasificatorul nu a putut fi incarcat ...!" << endl ;
29 return false ;
30 }
31
Descriere codului sursă 67

32 // C o n v e r s i a i m a g i n i i c o l o r de i n t r a r e i n i m a g i n e g r i
33 Mat img_gri ;
34 cvtColor ( img_in , img_gri , CV_BGR2GRAY ) ;
35
36 // I m b u n a t a t i r e a i m a g i n i i p r i n e g a l i z a r e a h i s t o g r a m e i
37 equalizeHist ( img_gri , img_gri ) ;
38
39 // D e f i n i t i a unui v e c t o r de s t o c a r e a r e g i u n i l o r f e t e i
40 vector<Rect> regiuni_fete ;
41
42 // D e t e c t a r e a f e t e l o r u t i l i z a n d c l a s i f i c a t o r u l Haar
43 clasificator_haar . detectMultiScale ( img_gri , regiuni_fete , 1 . 1 , 2 , ←
CV_HAAR_SCALE_IMAGE , Size ( 4 0 , 4 0 ) ) ;
44
45 // Desenarea r e g i u n i l o r f e t e i
46 for ( unsigned int i = 0 ; i < regiuni_fete . size ( ) ; i++ )
47 rectangle ( img_in , regiuni_fete . at ( i ) , Scalar ( 1 0 0 , 2 5 5 , 1 5 0 ) , 2 ) ;
48
49 // A f i s a r e r e z u l t a t e
50 imshow ( " Detectia fetelor " , img_in ) ;
51 waitKey ( ) ;
52
53 return true ;
54 }
9.4 Descriere codului sursă

24 CascadeClassifier
Definirea unui obiect de tipul CascadeClassifier.
26 bool CascadeClassifier : : load ( const string& filename )
Acest apel este utilizat pentru a se ı̂ncărca clasificatorul din fişierul *.xml.
43 void CascadeClassifier : : detectMultiScale ( const Mat& image , vector<←
Rect>& objects , double scaleFactor =1.1 , int minNeighbors =3, int ←
flags =0, Size minSize=Size ( ) , Size maxSize=Size ( ) )
Realizează detectarea ı̂n imaginea de intrare a tuturor obiectelor (având dimensiuni vari-
ate) pentru care a fost clasificatorul antrenat. Obiectele detectate sunt returnate sub forma
unui vector cu dreptunghiuri (Rect).
ˆ image: imaginea de intrare;
ˆ objects: vectorul unde vor fi salvate obiectele (dreptunghiurile) detectate;
ˆ scaleFactor: acest parametru specifică cât de mult este redusă dimensiunea imagini,
pentru fiecare etapă de scalare a imagini. Alegerea unei valori mai mari are drept
rezultat reducerea timpului de calcul şi scăderea numărului de ipoteze detectate (dacă
factorul de scalare nu se ı̂ncadrează cu anumite obiecte având o dimensiune precisă);
ˆ minNeighbors: indică numărul de vecini pe care trebuie să ı̂i aibă fiecare ipoteză pen-
tru a fi considerată obiectul căutat. Acest parametru este util pentru că pe parcursul
procesului de căutare pot apărea mai multe ipoteze ı̂ntr-o aceeaşi regiune (pentru fac-
tori de scalare diferiţi). Setarea acestui parametru reprezintă numărul de suprapuneri
posibile pentru ca o ipoteză să fie considerată obiect.
ˆ flags: poate avea patru combinaţii posibile, acestea putând fi combinate utilizând
operaţia de SAU logic:
68 DETECTAREA FEŢELOR ÎN IMAGINI

– CV HAAR DO CANNY PRUNING – alegerea acestei valori pentru parametru considerat


conduce la rejectarea de către clasificator a regiunilor plate (fără linii);
– CV HAAR SCALE IMAGE – pentru această valoare algoritmul de detecţie v-a realiza
scalarea imagini, ci nu detectorul propriu-zis;
– CV HAAR FIND BIGGEST OBJECT – setarea la această valoare conduce la returnarea
de către algoritm a obiectelor de dimensiuni mari (numărul de obiecte returnate
va fi unu sau nici unu);
– CV HAAR DO ROUGH SEARCH alegerea acestei valori face ca algoritmul de căutare să
finalizeze procesul de căutare, indiferent de factorul de scalare la care este detectat
obiectul.
ˆ minSize: dimensiunea minimă pe care o poate avea un obiect ce urmează a fi căutat.
Obiectele cu o dimensiune mai mica decât aceasta sunt ignorate;
ˆ maxSize: dimensiunea maximă pe care o poate avea un obiect ce urmează a fi căutat.
Obiectele cu o dimensiune mai mare decât aceasta sunt ignorate;
10. Urmărirea formelor

Urmărirea formelor utilizând estimatori de stare


Filtrul Kalman

În această aplicaţie se va prezenta conceptul de urmărire a formelor ı̂ntr-o secvent, ă video
utilizându-se estimatori de stare. În mod particular, se va implementa o buclă de urmărire
a pozit, iei 2D a unui obiect cu ajutorul filtrului Kalman [15].

10.1 Baze teoretice


10.1.1 Estimatori de stare şi urmărirea formelor
Luând ı̂n considerare exemplul de urmărire a mişcării unei persoane ı̂ntr-o secvenţă video,
ı̂n fiecare imagine a secvenţei de intrare se va determina poziţia acelei persoane. Acest lucru
se poate efectua prin diverse metode, fiecare metodă livrând un estimat al poziţiei persoanei
ı̂n cauză. Estimatul este de obicei imprecis, ı̂n special datorită naturii sistemelor de vedere
artificială. Acest lucru se datorează lipsei de precizie a senzorului video, aproximărilor din
stagiile de segmentare, ocluziilor, umbrelor, sau a modificării siluetei persoanei datorită
mişcării braţelor şi a picioarelor. Indiferent de sursa de zgomot, măsurătorile efectuate prin
tehnicile de procesare de imagini variază stohastic ı̂n jurul valorii reale ce ar fi măsurată de
un senzor ideal. Toate aceste imperfecţiuni sunt sumate ca şi zgomot ı̂n sistemul vizual de
urmărire a formelor.
Scopul unui sistem de urmărire a obiectelor este de a estima mişcarea lor ı̂n aşa fel ı̂ncât
să se utilizeze la maxim măsurătorile efectuate. Astfel, efectul cumulativ al unui număr
de măsurători poate fi utilizat ı̂n observarea traiectoriilor reale ale obiectelor vizualizate.
Ingredientul cheie ı̂ntr-un astfel de proces este acela al includerii unui model de mişcare 1
al obiectelor. În cazul exemplului de mai sus, un astfel de model poate fi considerat ca s, i
informaţia apriori că o persoană intră ı̂n cadrul vizual din stânga şi ı̂l părăseşte prin dreapta.
După cum se poate vedea ı̂n Fig. 10.1, acest proces este divizat ı̂n două stagii:
ˆ Predicţia, unde informaţia deja achiziţionată este utilizată pentru predicţia următoarei
locaţii a obiectului;
ˆ Corecţia, unde o nouă măsurătoare este efectuată şi apoi fuzionată cu modelul luat ı̂n
considerare.
Tehnicile utilizate ı̂n sistemele de predicţie-corecţie sunt denumite estimatoare. Unele
dintre cele mai utilizate metode de estimare sunt aşa-numitele filtre Kalman [15] şi de par-
ticule [14].

10.1.2 Filtrul Kalman


Filtrul Kalman (KF) este ı̂n principiu un estimator de stare, care determină cea mai bună
aproximare (ı̂n sensul erorii pătratice) pentru variabilele de stare asociate unui sistem dinamic
1
Eng. Motion model
70 URMĂRIREA FORMELOR

Corec‫܊‬ie
Predic‫܊‬ie
(măsurare)

Fig. 10.1 Estimator ı̂n buclă ı̂nchisă bazat pe o fază de predicţie urmată de corecţia modelului.

liniar, ı̂n care se exercită perturbaţii cu caracter aleatoriu, pe baza mărimilor măsurabile,
care sunt, de asemenea, afectate de zgomote aleatoare.
Dezvoltarea KF este nemijlocit legată de sistemele stohastice. În aceste condiţii se poate
considera că filtrul Kalman se poate baza pe ipoteza că sistemul care urmează să fie estimat
poate fi modelat ca un proces aleatoriu normal distribuit X(k), având valoarea medie x̄k (ı̂n
acest caz x̄k = x̂k ) şi matricea de covarianţă a erorii Pk , k reprezentând momentul de timp.
Mărimea x̂k este cunoscută sub numele de stare estimată a stării reale necunoscute xk a
sistemului la momentul de timp k. Starea sistemului poate fi reprezentată, ı̂n cazul general,
ca un vector n-dimensional:
 T
x k = x k 1 x k 2 . . . xk n . (10.1)
Scopul urmărit este acela de a se obţine o stare estimată x̂k cât mai apropiată de starea
sistemului la momentul de timp considerat k sau, cu alte cuvinte, ca eroarea de estimare să
tindă la zero.

10.1.2.1 Modelul procesului


Examinat de-a lungul unei perioade de timp, sistemul este supus unor transformări.
Unele aspecte legate de aceste transformări sunt cunoscute şi pot fi modelate. Altele sunt
necunoscute, nu pot fi măsurate sau sunt prea complexe pentru a fi modelate. Aceste
transformări trebuie să fie aproximate de un model Ak al procesului. În cazul KF, acest
model trebuie să fie liniar. În conformitate cu această condiţie, distribuţia normală a stării
modelului este menţinută şi după ce starea a fost supusă transformării liniare Ak . Noua
valoare estimată a stării x̂k şi matricea de covarianţă Pk , pentru următorul moment de timp,
sunt date de relaţiile:

x̂k = Ak−1 x̂k−1 , (10.2)

P̂k = Ak−1 Pk−1 ATk−1 . (10.3)


unde Pk reprezintă matricea de covarianţă a erorii ce descrie eroarea dintre starea estimată
x̂k şi starea reală necunoscută xk .
Datorită caracterului aproximativ al lui Ak , valoarea estimată x̂k a stării este, de aseme-
nea, o valoare aproximată a stării reale xk . Diferenţa dintre starea reală şi starea estimată
este reprezentată cu ajutorul unei variabile aleatoare wk :

xk = Ak−1 xk−1 + wk−1 . (10.4)


Valorile variabilei wk , pentru fiecare moment de timp, sunt necunoscute, dar ele trebuie
Cerinţe 71

să fie utilizate ı̂n procesul de ı̂mbunătăţire a stării estimate. Vectorul wk mai este cunoscut
şi sub numele de vectorul zgomotului procesului şi este notat cu:

p(wk ) = N (0, Qk ), (10.5)


unde zero este valoarea medie a distribuţiei, iar Qk reprezintă matricea de covarianţă a
zgomotului procesului (ţinând seama de semnificaţia zgomotului precum şi de caracterul
aleatoriu al variaţiei sale ı̂n timp, necunoscută ı̂n sens determinist, se poate considera că
funcţia p(wk ) este un proces stohastic centrat (cu medii statistice nule) şi necorelat, mai
precis, zgomot alb caracterizat prin matricea de covarianţă Qk ). Deci fiecare element com-
ponent al vectorului wk , la fiecare moment de timp, se poate presupune că are o valoare
egală cu valoarea medie a distribuţiei, adică cu zero.

10.1.2.2 Ieşirea sistemului


Ieşirea sistemului este ı̂n strânsă legătură cu starea acestuia. Dacă această relaţie este
cunoscută şi totodată este cunoscută şi starea estimată la momentul de timp imediat următor
momentului de timp curent, atunci poate fi estimată mărimea măsurabilă corespunzătoare
ieşirii sistemului. În continuare, va fi introdus modelul mărimii măsurabile corespunzătoare
ieşirii sistemului şi va fi obţinută relaţia dintre starea şi ieşirea acestuia.
La fel ca şi ı̂n cazul stării sistemului, ieşirea acestuia poate fi modelată ca un proces
aleatoriu normal distribuit Z(k), având valoarea medie ẑk şi matricea de covarianţă S(k).
Valoarea medie ẑk reprezintă valoarea estimată a mărimii măsurabile corespunzătoare ieşirii
sistemului, valoare care depinde de starea estimată x̂k , la momentul de timp k. Mărimea
măsurabilă reală zk poate fi obţinută prin măsurarea ieşirii sistemului. Această mărime
măsurabilă poate fi reprezentată ca un vector m-dimensional:
 T
z k = z k1 z k2 . . . z k m . (10.6)

10.1.2.3 Modelul mărimii măsurabile


Relaţia dintre ieşirea sistemului şi starea acestuia poate fi aproximată cu ajutorul mode-
lului Hk al mărimii măsurabile, Hk fiind o matrice cu dimensiunea m × n. După obţinerea
unei stări estimate, se poate utiliza matricea Hk pentru a se determina valoarea estimată a
mărimii măsurabile ẑk şi matricea de covarianţă Sk :

ẑk = Hk x̂k , (10.7)

Sk = Hk Pk HkT . (10.8)

10.1.2.4 Predicţia şi corecţia


Pentru corectarea stării estimate a sistemului se utilizează diferenţa dintre valoare esti-
mată ẑk şi valoarea reală zk a mărimii măsurabile deci, aşa cum s-a mai precizat, eroarea de
estimare. Schema bloc a filtrului Kalman este reprezentată ı̂n Fig 10.2.

10.2 Cerinţe
1. Să se citească un fis, ier video de pe HDD;
2. Să se segmenteze un obiect de interes ı̂n funct, ie de culoarea sa;
3. Să se determine centrul de greutate al obiectului segmentat;
4. Să se calculeze predict, ia s, i corect, ia stării (pozit, iei 2D) obiectului utilizându-se filtrul
72 URMĂRIREA FORMELOR

Estimatele ini‫܊‬iale xˆ k ‫܈‬i Pk T


Ak 1 Pk 1 Ak 1 

Corec‫܊‬ie
(1) Calculul matricei de amplificare Kalman
  T
Predic‫܊‬ie Pk H k
Kk .
(1) Estimarea stării  T
H k Pk H k  Rk
ˆ (2) Corectarea valorii estimate a priori a stării
xk Ak 1 xˆ k 1.
(2) Estimarea matricei de covarian‫܊‬ă a erorii
  T

xk


xˆ k  K k z k  H k xˆ k .
Pk Ak 1 Pk 1 Ak 1  Qk 1. (3) Corectarea valorii estimate a priori a matricei
de covarian‫܊‬ă a erorii

Pk I  K k H k Pk .

Fig. 10.2 Bucla de predict, ie-corect, ie a filtrului Kalman.

Kalman;
5. Să se afis, eze traiectoriile pozit, iei măsurate s, i estimate a obiectului.

10.3 Codul sursă al aplicat, iei

1 # include < s t d l i b . h>


2 # include " opencv2 / opencv .hpp"
3 # include " opencv2 / highgui / highgui .hpp"
4 # include " opencv2 /video / tracking .hpp"
5
6 using namespace cv ;
7
8 int main ( int argc , char ** argv )
9 {
10 Mat ImagineIntrare , ImagineTracking ;
11 Mat ImagineHSV , ImagineSegmentata ;
12
13 // Vector a l t r a i e c t o r i e i o b i e c t u l u i
14 std : : vector <Point> TraiectorieMasurata ;
15 std : : vector <Point> TraiectorieEstimata ;
16
17 // I n s t a n t a f i l t r u l u i Kalman
18 KalmanFilter KF ( 4 , 2 , 0 ) ;
19
20 // M a t r i c i l e de s t a r e , zgomot s i m a s u r a t o r i
21 Mat Stare ( 4 , 1 , CV_32F ) ; / * ( phi , d e l t a p h i ) * /
22 Mat ZgomotProces ( 4 , 1 , CV_32F ) ;
23 Mat Masuratori = Mat : : zeros ( 2 , 1 , CV_32F ) ;
24
Codul sursă al aplicat, iei 73

25 // I n i t i a l i z a r e a m a t r i c e i de s t a r e
26 randn ( Stare , Scalar : : all ( 0 ) , Scalar : : all ( 0 . 1 ) ) ;
27
28 // I n i t i a l i z a r e a m a t r i c e i de t r a n z i t i i i n t r e s t a r i
29 KF . transitionMatrix = * ( Mat_<float >(4 , 4 ) <<
30 1 , 0 , 1 , 0 , 0 , 1 , 0 , 1 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 1) ;
31
32 // I n i t i a l i z a r e a f i l t r u l u i Kalman
33 setIdentity ( KF . measurementMatrix ) ;
34 setIdentity ( KF . processNoiseCov , Scalar : : all ( 1 e−5) ) ;
35 setIdentity ( KF . measurementNoiseCov , Scalar : : all ( 1 e−1) ) ;
36 setIdentity ( KF . errorCovPost , Scalar : : all ( 1 ) ) ;
37 randn ( KF . statePost , Scalar : : all ( 0 ) , Scalar : : all ( 0 . 1 ) ) ;
38
39 // C l a s a u t i l i z a t a i n a c h i z i t i a de i m a g i n i de l a camera v i d e o a ←
calculatorului
40 VideoCapture cap ( 0 ) ;
41
42 // V e r i f i c a r e d e s c h i d e r e camera v i d e o
43 if ( ! cap . isOpened ( ) )
44 return −1;
45
46 // Bucla i n f i n i t a de a c h i z i t i e de i m a g i n i
47 for ( ; ; )
48 {
49 double AriaMaxima ( 0 . 0 ) ;
50
51 std : : vector< std : : vector<Point> > Contururi ;
52 std : : vector<Vec4i> Ierarhie ;
53 Point ptPozitiePredictionata ;
54 Point ptPozitieMasurata ;
55 Point ptPozitieEstimata ;
56
57 /*
58 * P r e d i c t i e p o z i t i e u t i l i z a n d f i l t r u l Kalman
59 */
60 Mat PredictieKalman = KF . predict ( ) ;
61 ptPozitiePredictionata . x = PredictieKalman . at<float >(0) ;
62 ptPozitiePredictionata . y = PredictieKalman . at<float >(1) ;
63
64 /*
65 * E f e c t u a r e a m a s u r a t o r i l o r ( d e t e r m i n a r e a p o z i t i e i i n i m a g i n e a ←
obiectului )
66 */
67 // A c h i z i t i e i m a g i n e de i n t r a r e
68 cap >> ImagineIntrare ;
69
70 // C o n v e r s i t a i m a g i n i i d i n s p a t i u l de c u l o a r e RGB i n s p a t i u l HSV
71 cvtColor ( ImagineIntrare , ImagineHSV , CV_BGR2HSV ) ;
72
73 // Segmentarea p l a n u r i l o r H, S s i V d i n i m a g i n e a HSV
74 inRange ( ImagineHSV ,
74 URMĂRIREA FORMELOR

75 Scalar ( 1 0 , 1 5 0 , 1 0 0 ) ,
76 Scalar ( 4 0 , 2 5 5 , 2 5 5 ) ,
77 ImagineSegmentata ) ;
78
79 // E x t r a g e r e a c o n t u r u r i l o r d i n i m a g i n e a segmentata
80 findContours ( ImagineSegmentata . clone ( ) ,
81 Contururi ,
82 Ierarhie ,
83 CV_RETR_TREE ,
84 CV_CHAIN_APPROX_SIMPLE ,
85 Point ( 0 , 0 ) ) ;
86
87 // E x t r a g e r e a c o n t u r u l u i cu c e a mai mare a r i e
88 for ( size_t i = 0 ; i < Contururi . size ( ) ; i++)
89 {
90 // C a l c u l u l a r i e i conturului curent
91 double Aria = contourArea ( Contururi [ i ] ) ;
92
93 // Comparatie a r i e
94 if ( Aria > AriaMaxima )
95 {
96 AriaMaxima = Aria ;
97
98 // Determinare c e n t r u de g r e u t a t e a l o b i e c t u l u i u t i l i z a n d ←
momentele s p a t i a l e
99 Moments MomenteSpatiale = moments ( Contururi [ i ] , false ) ;
100
101 ptPozitieMasurata = Point2f ( MomenteSpatiale . m10 / ←
MomenteSpatiale . m00 ,
102 MomenteSpatiale . m01 / MomenteSpatiale . m00 ) ;
103 }
104 }
105
106 // S a l v a r e a p o z i t i e i masurate i n i m a g i n e a o b i e c t u l u i
107 TraiectorieMasurata . push_back ( ptPozitieMasurata ) ;
108
109 /*
110 * C o r e c t i a s t a r i i o b i e c t u l u i ( p o z i t i e i ) u t i l i z a n d n o i l e ←
masuratori
111 */
112 Masuratori . at<float >(0) = ptPozitieMasurata . x ;
113 Masuratori . at<float >(1) = ptPozitieMasurata . y ;
114
115 Masuratori += KF . measurementMatrix * Stare ;
116
117 Mat PozitieEstimata = KF . correct ( Masuratori ) ;
118
119 Stare = KF . transitionMatrix * Stare + ZgomotProces ;
120
121 ptPozitieEstimata . x = PozitieEstimata . at<float >(0) ;
122 ptPozitieEstimata . y = PozitieEstimata . at<float >(1) ;
123
Descrierea funct, iilor principale 75

124 // S a l v a r e a p o z i t i e i e s t i m a t e a o b i e c t u l u i i n i m a g i n e
125 TraiectorieEstimata . push_back ( ptPozitieEstimata ) ;
126
127
128 /*
129 * Afisare rezultate tracking
130 */
131 ImagineTracking = ImagineIntrare . clone ( ) ;
132
133 // Desenarea t r a i e c t o r i e i masurate s i e s t i m a t e o b i e c t u l u i
134 for ( size_t i = 1 ; i < TraiectorieMasurata . size ( ) ; i++)
135 {
136 line ( ImagineTracking ,
137 TraiectorieMasurata [ i −1] ,
138 TraiectorieMasurata [ i ] ,
139 CV_RGB ( 2 5 5 , 2 5 5 , 0 ) ,
140 2) ;
141
142 line ( ImagineTracking ,
143 TraiectorieEstimata [ i −1] ,
144 TraiectorieEstimata [ i ] ,
145 CV_RGB ( 0 , 0 , 2 5 5 ) ,
146 2) ;
147 }
148
149 // A f i s a r e a m a r i m i i p r e d i c t i o n a t e a o b i e c t u l u i
150 circle ( ImagineTracking , ptPozitiePredictionata , 6 , CV_RGB ( 1 0 0 , ←
255 , 0) , 3) ;
151
152 // A f i s a r e a m a r i m i i masurate
153 circle ( ImagineTracking , ptPozitieMasurata , 6 , CV_RGB ( 2 5 5 , 2 5 5 , 0 ) ←
, 3) ;
154
155 // A f i s a r e a m a r i m i i d e t e r m i n a t a de f i l t r u l Kalman
156 circle ( ImagineTracking , ptPozitieEstimata , 6 , CV_RGB ( 0 , 0 , 2 5 5 ) , ←
3) ;
157
158 // A f i s a r e r e z u l t a t e
159 imshow ( " Segmentare " , ImagineSegmentata ) ;
160 imshow ( " Tracking " , ImagineTracking ) ;
161
162 if ( waitKey ( 3 0 ) >= 0 ) break ;
163 }
164
165 return EXIT_SUCCESS ;
166 }

10.4 Descrierea funct, iilor principale

18 KalmanFilter : : KalmanFilter ( int dynamParams , int measureParams )

Constructorul unui filtru Kalman standard.


ˆ dynamParams: dimensiunea vectorului de stare;
76 URMĂRIREA FORMELOR

ˆ measureParams: dimensiunea vectorului măsurătorilor.


60 const Mat& KalmanFilter : : predict ( )
Calculul predict, iei stării sistemului.
117 const Mat& KalmanFilter : : correct ( const Mat& measurement )
Corect, ia stării sistemului utilizând factorul de amplificare Kalman.
ˆ measurement: măsurătorile efectuate asupra procesului.
Bibliografie

[1] P. J. Besl and N. D. McKay, “A method for registration of 3-d shapes,” IEEE Trans.
Pattern Anal. Mach. Intell., Vol. 14, No. 2, pp. 239–256, Feb. 1992. [Online]. Available:
http://dx.doi.org/10.1109/34.121791
[2] G. Bradski and A. Kaehler, Learning OpenCV: Computer Vision with the OpenCV
Library. Sebastopol, Canada: O’Reilly Media, 2008.
[3] J. Canny, “A Computational Approach to Edge Detection,” IEEE Trans. on Pattern
Analysis and Machine Intelligence, Vol. 8, No. 6, pp. 679–698, 1986.
[4] B. Cyganek and J. Siebert, An Introduction to 3D Computer Vision Techniques and
Algorithms. West Sussex, Great Britain: John Wiley & Sons, 2009.
[5] Y. Freund and R. Schapire, “Experiments with a New Boosting Algorithm,” Proc. of
the Thirteenth Inter. Conf. on Machine Learning, San Francisco, Canada, 1996, pp.
148–156.
[6] R. C. Gonzalez and R. E. Woods, Digital Image Processing, 3rd Ed. New Jersay, USA:
Prentice-Hall, Inc., 2006.
[7] S. Grigorescu, T. Cociaş, G. Măceşanu and F. Moldoveanu, “Stereo Vision-based 3D
Camera Pose and Object Structure Estimation - An Application to Service Robotics,”
Proc. of the Inter. Joint Conf. on Computer Vision, Imaging and Computer Graphics
Theory and Applications, Rome, Italy, 2012, pp. 355–358.
[8] S. Grigorescu, G. Măceşanu, T. Cociaş and M. F., “On the Real-time Modelling of a
Robotic Scene Perception and Estimation System,” Proc. of the 15th Inter. Conf. on
System Theory, Control, and Computing, Sinaia, Romania, 2011, pp. 273–276.
[9] C. Harris and M. Stephens, “A Combined Corner and Edge Detection,” Proc. of the
Fourth Alvey Vision Conference, 1988, pp. 147–151.
[10] R. Hartley, “In Defense of the Eight-Point Algorithm,” IEEE Trans. on Pattern Analysis
and Machine Intelligence, Vol. 19, No. 6, pp. 580–593, 1997.
[11] D. Holz, S. Holzer and R. B. Rusu, “Real-Time Plane Segmentation using RGB-D
Cameras,” Proceedings of the RoboCup Symposium, 2011.
[12] B. K. P. Horn, “Closed-form solution of absolute orientation using unit quaternions,”
Journal of the Optical Society of America A, Vol. 4, No. 4, pp. 629–642, 1987.
[13] P. V. Hough, “Method and means for recognizing complex patterns,” US Patent
3969654, 1962.
[14] M. Isard and A. Blake, “Condensation - conditional density propagation for visual
tracking,” International Journal of Computer Vision, Vol. 29, pp. 5–28, 1998.
[15] R. E. Kalman, “A new approach to linear filtering and prediction problems,” Trans-
actions of the ASME-Journal of Basic Engineering, Vol. 82, No. Series D, pp. 35–45,
1960.
[16] R. Lienhart and J. Maydt, “An Extended Set of Haar-like Features for Rapid Object
Detection,” Proc. of the 2002 Inter. Conf. on In Image Processing ICIP, New York,
USA, 2002, pp. 900–903.
[17] G. Macesanu, T. Cociaş, F. Moldoveanu and M. Cernat, “Active Vision System for 3D
Scene Reconstruction,” Proc. of the Inter. Conf. on Interdisciplinarity in Education,
Athens, Greece, 2011, pp. 376–381.
78 BIBLIOGRAFIE

[18] R. Rakesh, P. Chaudhuri and C. Murthy, “Thresholding in edge detection: A statistical


approach,” IEEE Transactions on Image Processing, Vol. 13, No. 7, Jul. 2004.
[19] B. Rozenfeld, The History of Non-Euclidean Geometry: Evolution of the
Concept of a Geometric Space, ser. Studies in the History of Mathematics
and Physical Sciences Series. Springer-Verlag, 1988. [Online]. Available: http:
//books.google.ro/books?id=DRLpAFZM7uwC
[20] R. B. Rusu, “Semantic 3d object maps for everyday manipulation in human
living environments,” Ph.D. Thesis, Computer Science department, Technische
Universitaet Muechen, Germany, October 2009, advisor: Univ.-Prof. Michael
Beetz (TUM) Ph.D.; Committee: Univ.-Prof. Dr. Nassir Navab (TUM), Univ.-
Prof. Michael Beetz (TUM) Ph.D., Prof. Kurt Konolige (Stanford) Ph.D.,
Prof. Gary Bradski (Stanford) Ph.D.; summa cum laude. [Online]. Available:
http://files.rbrusu.com/publications/RusuPhDThesis.pdf
[21] E. Trucco and A. Verri, Introductory Techniques for 3-D Computer Vision. New Jersey,
USA: Prentice-Hall, Inc, 1998.
[22] P. Viola and M. Jones, “Rapid Object Detection Using a Boosted Cascade of Simple
Features,” Proc. of the 2001 IEEE Computer Society Conf. on Computer Vision and
Pattern Recognition, Vol. 1, Kauai, USA, 2001, pp. 511–518.
[23] I. Wald and V. Havran, “On building fast kd-trees for ray tracing, and on doing that in
o(n log n),” Proc. of the 2006 IEEE Symposium on Interactive Ray Tracing, 2006, pp.
61–70.
[24] Z. Wang, H. Liu, Y. Qian and T. Xu, “Real-time plane segmentation
and obstacle detection of 3d point clouds for indoor scenes,” Proceedings
of the 12th international conference on Computer Vision - Volume 2, ser.
ECCV’12. Berlin, Heidelberg: Springer-Verlag, 2012, pp. 22–31. [Online]. Available:
http://dx.doi.org/10.1007/978-3-642-33868-7 3
[25] Z. Zhang, “Iterative point matching for registration of free-form curves and surfaces,”
Int. J. Comput. Vision, Vol. 13, No. 2, pp. 119–152, Oct. 1994. [Online]. Available:
http://dx.doi.org/10.1007/BF01427149

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