Platforma Wireless Robotizata Pentru Captura Si Analiza de Imagine In Timp Real

LUCRARE DE DISERTAȚIE

Platformă wireless robotizată pentru captură și analiză de imagine în timp real

Cuprins:

Cap. 1. Introducere – Formularea problemei
Cap. 2. Criterii de evaluare ale obiectivului

2.1 Noțiunea de sistem embedded

2.2 Avantajele arhitecturii embedded în inplementare

2.3 Noțiunea de robot mobil
Cap. 3. Resursele proiectului  

3.1 Resurse hardware

3.1.1 Microcontroller

3.1.2 Drivere motoare

3.1.3 Senzori

3.1.3.1 Sonar

3.1.3.2 Camera vodeo PAL
3.1.4 Modul wireless comandă

3.1.4.1 Conexiunea serială  

3.1.4.2 Modul wireless de comunicație serială

3.1.5 Modul wireless streaming video
3.1.6 Motoare

3.1.6.1 Motoare c.c. cu demultiplicare

3.1.6.2 Motoare pas cu pas
3.1.7 Acumulatori
3.1.8 Conectică

3.2 Resurse software

3.2.1 Mediul de dezvoltare Processing + Arduino

3.2.2 Limbajul de programare C

3.2.3 Framework-ul .NET

3.2.3.1 Limbajul de programare C#

3.2.3.2 Facilități de interfatare
3.2.4 Platforma Emgu.CV pentru procesare de imagine

3.2.4.1. Detecție facială

3.2.4.2. Detecție similarități

3.2.4.3. Detecție siluete

3.2.4.4. Detecție caractere

Cap. 4. Strategia de atingere a obiectivului

4.1 Proiectarea hardware

4.1.1 Proiectarea modulului de control

4.1.2 Proiectarea modulului senzorial

4.1.3 Integrarea modulului de transmisie video

4.1.4 Schemă bloc hardware
4.2 Proiectarea software

4.2.1 Programarea microcontrolerului ATMega328 în limbaj C

4.2.2 Schemă bloc software a programului microcontroller  

4.2.3 Interfațarea cu PC-ul  

4.2.4 Proiectarea unei aplicații de control (Windows) în limbaj C# (.NET)

4.2.5 Schemă bloc software a aplicației PC
4.3 Rezultate și ghid de utilizare  

Cap. 5. Concluzii

Cap. 6. Bibliografie

Cap. 7. Anexe

7.1 Cod sursă program microcontroller – limbaj C
7.2 Cod sursă program aplicație PC (Windows) – limbaj C#
7.2.1 Cod sursă form configurare conexiune serială
7.2.2 Cod sursă form „Main”

Cap. 1. Introducere – Formularea problemei

În societatea actuală, implicarea directă a omului în activitățile industriale și nu numai, tinde să fie din ce în ce mai redusă, foarte multe dintre procese fiind automatizate cu ajutorul roboților. În aceste circumstanțe explorarea mediilor ostile, periculoase, toxice, greu accesibile sau dăunătoare omului se dorește o activitate cât mai robotizată.

Această lucrare urmărește dezvoltarea și implementarea unei platforme – sistem de tip robot mobil, cu comandă wireless în bandă de 2,4 GHz, capabilă să furnizeze imagini în timp real către un PC ce dispune de un Framework Microsoft .NET compatibil la nivelul căruia se realizează prelucrări grafice complexe care au că rezultat identificare de forme, texturi, obiecte. Principalele obiective se concentrează asupra studierii și implementării următoarelor aspecte:

– realizarea practică a robotului mobil, compus din senzori, camera video etc.

– realizare unui soft cu rol de configurare, coordonare și monitorizare a sistemului.

– integrarea unor algoritmi avansați de prelucrare grafică în softul PC

– realizarea setului de protocoale de comunicație pentru rețele de senzori inteligenți

În urma unor procese de analiză și proiectare au rezultat niște specificații preliminare pentru fiecare dintre componentele hardware și software utilizate.

Robotul constă dintr-un șasiu pe care sunt montate șase motoare de curent continuu care dispun de reductoare, pe axul cărora sunt montate roțile, două drivere adecvate necesare pentru comandă motoarelor în tensiune (câte trei motoare conectate la un driver), un microcontroller pe care să fie scris algoritmul de control, patru senzori de proximitate cu ultrasunete care vor oferi informație cu privire la perimetrul robotului, un modul de emisie-recepție wireless a datelor (comenzi și informație senzori), un modul pentru emisia semnalului video preluat de o camera CMOS adecvată și un braț ce dispune de două servomotoare capabil să orienteze camera video pe două axe de coordonate (direcțiile sus-jos, stânga-dreapta). Pentru alimenarea tuturor acestor componente au fost necesare trei tensiuni principale: cea asigurată de acumulatori cu o valoare de 14,4 V cu care s-au alimentat driverele de motor și din care au derivat și celelalte două valori 12 V și 5 V prin intermediul unuor circuite integrate de tip regulator de tensiune.

La nivel software se va face o distincție clară între scrierea algoritmului ce va rula pe microcontrolerul robotului și scrierea algoritmului aferent aplicației ce va rula pe un PC care dispune de o serie de tool-uri software utile. Așadar pentru programarea microcontrolerului s-a optat pentru mediul de dezvoltare Processing, ce dispune de o sintaxa C++, iar pentru dezvoltarea aplicației Windows s-a optat pentru framework-ul Microsoft .NET – limbaj C#.

Cap. 2. Criterii de evaluare ale obiectivului

Obiectivul principal al acestui proiect se referă la dezvoltarea unui sistem embedded de tipul unei platforme controlată wireless pentru supraveghere video care să reușească să satisfacă necesitățile de siguranță în cadrul unor operațiuni de explorare și care să dispună de algorimi dedicați de prelucrare video pentru detectarea și identificarea unor elemente prestabilite. Astfel că cele mai importante criterii de care va trebui să se țină cont în proiectarea și implementarea să vor fi: stabilitatea, fiabilitatea, robustețea, rază de acțiune a modulelor wireless, autonomia robotului și eficientă algoritmilor de prelucrare de imagine.

Realizarea unui robot care să imite comportamentul uman în cazul unui scenariu de tip explorare de medii periculoase reprezintă o problematica de interes major, având la baza principii ale electronicii digitale și analogice combinate cu module software performanțe, integrate prin intermediul unor microcontrolere dimensionate corespunzător.

2.1 Noțiunea de sistem embedded

Un sistem embedded este un sistem de tip computer proiectat pentru asigurarea unei funcții specifice (sub-funcție) din cadrul unui sistem mai complex, având de cele mai multe ori capacitatea de funcționare în timp real. Acesta este integrat, după cum sugerează și denumirea să, că parte a unui dispozitiv complet, incluzând de cele mai multe ori componenete electronice (hardware) și componente mecanice. Un sistem embedded poate fi definit prin contrast cu un dispozitiv de uz gereral precum un computer, a cărui funcționalitate este foarte flexibilă și poate satisface o mare masă de end-useri (utilizatori).

Sistemele embedded integrează de cele mai multe ori unități de procesare precum microprocesoare sau procesoare pentru semnale digitale (DSP-uri Digital Signal Processor). Principala caracteristică a acestora se referă la posibilitatea de a rezolva un task specific la un anumit moment de timp. Această permite proiectanților și inginerilor să ofere soluții tehnice optimale în ceea ce privește performanță în raport cu dimensiunea și costul de implementare.

De cele mai multe ori sistemele embedded nu sunt niște dispozitive de sine stătătoare. Multe astfel de sisteme conțin o serie de dispozitive computerizate, de mici dimensiuni, interconectate pentru asigurarea unei funcționalități bine specificate.

Ansamblul de instrucțiuni program aferente sistemelor embedded sunt referite sub denumirea de “firmware” și sunt stocate în chip-uri de memorie read-only sau memorie flash.

În cazul sistemelor embedded se pot distinge două mari categorii de unități de procesare:

microprocesorul (pentru aplicații mai complexe) și microcontrollerul (destinat să asigure o anumită funcție, și care conține o serie de periferice integrate, raducandu-se astfel dimensiunea și costul). Arhitecturile acestora pot fi de mai multe tipuri, fapt ce influenteza decisiv performanțele de procesare: Von Neumann, RISC, VLIW (cuvânt de instrucțiune cu o lungime între 4 și 64 biți) etc.

Pentru asigurarea arhitecturii embedded se poate opta pentru tehnologia SoC (System on Chip) care constă într-un sistem complet asigurat de procesoare multiple, memorii cache și periferice pe o singură placă de siliciu. Pentru implementarea acestei arhitecturi se recurge fie la tehnologia de tip ASIC (application-specific integrated circuit) sau la FPGA (field-programmable gate array).

Multe dintre sistemele embedded oferă facilități de interfatare cu utilizatorul, începând cu interfețe de tip touch-screen și terminând cu foarte comunele porturi de comunicație serială, paralelă, I2C, USB, ethernet etc. Astfel este permisă de cele mai multe ori programarea microcontrorelelor, monitorizarea diverșilor parametrii de funcționare și introducerea de date în timp real în sensul prelucrării lor.

2.2 Avantajele arhitecturii embedded în implementare

Pentru implementarea electronicii robotului s-a optat pentru utilizarea unei arhitecturi embedded întrucât oferă o serie de avantaje esențiale pentru acest tip de platforma hardware.

A fost asigurată astfel respectarea unor principii de baza precum:

– menținerea unei autonomii generoase, datorată consumului redus specific arhitecturii embedded

– asigurarea unor dimensiuni compacte, datorată utilizării unui microcontroller dedicat, capabil să prelucreze atât semnalele analogice cât și digitale furnizate de către senzori

– comunicarea stabilă între PC și robot datorată modulelor periferice destinate interfațării cu utilizatorul (port comunicație serială, RS 232, USB, etc.)

– asigurarea unei fiabilități sporite, datorată unei structuri mecanice robuste specifică sistemelor embedded de tip SoC

2.3 Noțiunea de robot mobil

Un robot mobil desemnează un ansamblu de componente electronice și mecanice capabil

să execute anumite sarcini impuse fără intervenția factorului uman, având capacități de locomoție, de acționare, comunicare și interacțiune cu mediul real.

Un robot mobil integrează atât module harware (de natură fizică) cât și module software (de natură logică). Din perspectiva hardware, un robot mobil dispune de obicei de următoarele subsisteme:

• Acțiune și locomoție – subsistem responsabil cu modul de deplasare și interacțiune a robotului în mediul real;

• Modul senzorial – subsistem responsabil cu modul de măsurare (analogică și digitală) a mediului real de către robotul mobil;

• Procesare – subsistem responsabil pentru deciziile și logică robotului pe baza informațiilor provenite de la senzori și a algoritmilor interni de prelucrare;

• Comunicare – subsistem responsabil cu modul de interacțiune a robotului mobil cu factorul uman dar și cu alți roboți sau dispozitive computerizate cu care este interconectat;

Pentru a se putea deplasa între două puncte prestabilite și pentru a execută diverse mișcări de acționare roboții mobili integrează și componente terminale, care joacă rolul exementelor de execuție și a căror natură este de obicei electro-mecanică (au capacitatea de a transformă energia electrică în energie mecanică).

Dintre aceste elemente se pot aminti:

– Motoare de curent continuu, servomotoare, electromagneti;

– Transmisii, angrenaje;

– Roți, senile, picioare, perne magnetice, elice;

Cap. 3. Resursele proiectului

Platforma de explorare wireless integrează câteva module foarte bine definite, hardware și software, prin a căror îmbinare se asigură funcționalitatea propusă.

3.1 Resurse hardware

Structura hardware cuprinde în sens generic două subansamble:

– robotul mobil, de tipul unui vehicul robust dotat cu o serie de senzori, video și de proximitate, capabil să furnizeze atât imagini în timp real, cât și alte informații cu privire la mediul de explorat, în tehnologie wireless.

– modulul de emisie – recepție a fluxului de date asociat robotului mobil (semnal video și alte informoC

2.3 Noțiunea de robot mobil

Un robot mobil desemnează un ansamblu de componente electronice și mecanice capabil

să execute anumite sarcini impuse fără intervenția factorului uman, având capacități de locomoție, de acționare, comunicare și interacțiune cu mediul real.

Un robot mobil integrează atât module harware (de natură fizică) cât și module software (de natură logică). Din perspectiva hardware, un robot mobil dispune de obicei de următoarele subsisteme:

• Acțiune și locomoție – subsistem responsabil cu modul de deplasare și interacțiune a robotului în mediul real;

• Modul senzorial – subsistem responsabil cu modul de măsurare (analogică și digitală) a mediului real de către robotul mobil;

• Procesare – subsistem responsabil pentru deciziile și logică robotului pe baza informațiilor provenite de la senzori și a algoritmilor interni de prelucrare;

• Comunicare – subsistem responsabil cu modul de interacțiune a robotului mobil cu factorul uman dar și cu alți roboți sau dispozitive computerizate cu care este interconectat;

Pentru a se putea deplasa între două puncte prestabilite și pentru a execută diverse mișcări de acționare roboții mobili integrează și componente terminale, care joacă rolul exementelor de execuție și a căror natură este de obicei electro-mecanică (au capacitatea de a transformă energia electrică în energie mecanică).

Dintre aceste elemente se pot aminti:

– Motoare de curent continuu, servomotoare, electromagneti;

– Transmisii, angrenaje;

– Roți, senile, picioare, perne magnetice, elice;

Cap. 3. Resursele proiectului

Platforma de explorare wireless integrează câteva module foarte bine definite, hardware și software, prin a căror îmbinare se asigură funcționalitatea propusă.

3.1 Resurse hardware

Structura hardware cuprinde în sens generic două subansamble:

– robotul mobil, de tipul unui vehicul robust dotat cu o serie de senzori, video și de proximitate, capabil să furnizeze atât imagini în timp real, cât și alte informații cu privire la mediul de explorat, în tehnologie wireless.

– modulul de emisie – recepție a fluxului de date asociat robotului mobil (semnal video și alte informații) , dotat cu interfață USB pentru conectarea la un PC convențional (pentru emitere comandă și recepție diverse date) și interfață RCA (pentru recepția semnalului audio-video);

Pentru implementarea celor două subansamble, toate componentele hardware au fost alese și dimensionate corespunzător în urmă unor analize asupra simulărilor procesului, astfel încât să̆ se obțină cele mai bune performanțe.

3.1.1 Microcontroler

Un microcontroler desemneaza un dispozitiv electronic care integreaza un circuit electric autonom compus din unitate centrala de prelucrare (CPU), memorie rapida FLASH, memorie program precum si porturi pentru intrari si iesiri analogice.

Componentele existente la nivelul circuitului integrat contureaza urmatoarele entitati functionale:

a. o unitate centrală de procesare (CPU)

b. o memorie locală EPROM / FLASH și eventual una RAM;

c. sistem de întreruperi;

d. I/O – intrări / ieșiri

e. o interfata seriala de tip asincrona și / sau sincrona;

f. un sistem de timere programabile.

g. covertoare analog numerice (una sau mai multe intrări analogice);

h. convertoare numeric analogice cu ieșiri PWM (cu modulare în timp);

i. comparator analogic;

j. memorie de date de tip EEPROM;

k. facilități suplimentare pentru sistemul de temporizare / numărare (captare și comparare);

l. elemente pentru optimizare consumului

Orice microcontroler dispune la nivelul unității centrale de instrucțiuni specifice la nivel de bit, mecanisme eficiente de gestionare a întreruperilor precum și sistem de interfatare și acces pentru porturile I/O.

Avantajul major al utilizării unui microcontroller se referă la dimensiunea redusă, costurile semnificativ mai mici, consumul de energie și flexibilitatea la implementare.

Este bineînțeles necesară păstrarea caracteristicilor de interfatare cu mediul pentru orice tip de microcontroler, indiferent de generație sau de performanțele obținute. Astfel, în componentă unui microcontroler, apar subsisteme pentru conversia analog-numerică, numeric-analogică și PWM, subsisteme necesare pentru izolarea galvanică precum și subsisteme de comutatie de putere precum relee etc.

Figura 3.1. Componentele principale ale unui microcontroller

În figura 3.1 de mai sus se pot identifica elementele principale ale unui microcontroler:

Memorie FLASH – se utilizeaza in scopul memorarii programelor. Avantajul major este posibilitatea de stergere si rescriere in mai multe randuri, ceea ce confera versatilitate microcontrolerului

EEPROM – este un tip de memorie ce se utilizeaza in special pentru scenariul in care exista date ce trebuiesc salvate in situatia in care nu mai exista sursa de alimentare. De cele mai multe ori aceasta memorie se utilizeaza pentru memorarea constantelor, a variabilelor ale caror valori nu vor trebui setate din nou in situatia in care alimentarea este sistata si repornita. Performantele acestui tip de memorie sunt mediocre insa costul de integrare este relativ scazut

RAM – este un tip de memorie ce utilizata de programul mucrocontroler in timpul executiei. In memoria RAM se vor stoca date temporare, calcule si rezultate intermediare a caror importanta este relativ scazuta in scenariul intreruperii alimentarii.

PORTUL A și PORTUL B – sunt interfete de conectare (pini) intre circuitul integrat si mediul extern (A – 5 pini, B – 8 pini)

FREE-RUN TIMER – dupa cum sugereaza si denumirea este un timer, un cronometru care la nivel hardware este integrat preintr-un registru de 8 biti care se incrementeaza la fiecare al petrulea impuls de ceas al oscilatorului de la 0 pana la 255, apoi se reseteaza si ciclul este reluat.

CPU – are rolul decizional in ansamblul circuitului integrat fiint componenta responsabila cu coordonarea si logica celorlalte elemente.

Criteriile pentru selecția unui model de microcontroller

Criteriile pentru alegerea unui microcontroller au fost următoarele:

să conțină un convertor analog-numeric cu cel puțin 5 canale, dintre care cel puțin două să aibă o rezoluție de 10 biți

să aibă cel puțin sase ieșiri PWM pentru controlul a două drivere aferente celor sase motoare de curent continuu si pentru preluarea informatiei de la patru sonare

să conțină un timer de 16 biți pentru generarea PWM

să conțină un timer de 8 biți pentru implementarea rutinii regulatorului

să aibă suficientă memorie pentru încărcarea programului. Cantitatea de memorie necesară a fost determinată pe baza unui prototip al programului.

să aibă un preț cât mai redus

Atmel AVR ATmega328

Pe baza acestor criterii a fost ales microcontrollerul ATmega328 din clasa AVR, al cărui producător este firma Atmel.

Atmega328 este un microcontroller RISC pe 8 biți cu o arhitectură de tip Harvard (i.e. stocare separată a programului și a datelor) capabil de o viteză de procesare de până la 1MIPS (i.e. 1 milion de instrucțiuni pe secundă la o viteza de ceas de 1MHz). La această arhitectură există spații de memorie separate pentru program și date. În consecință ar trebui să existe și magistrale separate (de adrese și date) pentru codul instrucțiunilor și respectiv pentru date. Este arhitectura standard pentru procesoarele numerice de semnal (DSP).

Figura 3.2. Structura pinilor pentru microcontrollerul Figura 3.3. Arduino UNO R3

Atmel Atmega328

Datorită facilităților de interconectare și interfațare cu alte componente s-a optat pentru utilizarea platformei de dezvoltare Arduino UNO R3 (Figura 3.3) care integrează microcontrollerul Atmega328 P caracterizat de următoarele specificații tehnice (Tabelul 3.1):

3.1.2 Drivere motoare

Driverul de motor sau puntea H este o structură foarte des folosită pentru comanda sarcinilor cu tensiune reglabilă (de exemplu pentru a varia intensitatea luminoasă a unui bec sau pentru a comanda un motor de curent continuu). Structura de bază este formată din patru comutatoare, ca în figura 3.4:

Figura 3.4. Structura de bază a driverului motor

Deoarece este necesară o frecvența destul de mare a impulsurilor de comandă, nu convine folosirea comutatoarelor clasice (de exemplu relee). Vom fi nevoiți să implementăm comutatoare electronice, cu viteze net superioare. Un tip de comutator superior este tranzistorul FET (Q1,..,Q4).

Modul de operare de baza al unuei punți H (Figura 3.5) este destul de simplu: în cazul în Q2 și Q3 sunt închise, polul din stânga a motorului va fi conectat la masă, în timp ce polul drept este conectat la sursă de alimentare. Curentul care curge prin motor acționează motorul în (să zicem), direcția înainte și arborele motorului începe rotația. În cazul în care T1 și T4 sunt închise, se va întâmplă invers; motorul devine activat în direcția inversă, iar arborele va începe rotirea în acest sens. Dacă se dorește controlul turației motoarelor se va utiliza PWM.

Observație:

Un comutator electronic este caracterizat și de timpii de comutatie (directă, respectiv inversă). În cazul nostru, nu vom lua în considerare acești timpi, deoarece sunt mult mai mici decât durata și perioada impulsurilor de comandă.

O influență o vor avea timpii de comutatie ai optocuploarelor, acești timpi fiind mai mari decât cei după care comută tranzistoarele. Timpii de comutatie ai optocuploarelor ne vor da o limita pentru pasul în care incrementăm frecvența impulsurilor de comandă.

Figura 3.5. Principiul de funcționare al puntii H cu tranzistori FET

Funcționarea

Se descrie în continuare în mod calitativ funcționarea punții H cu schemă de principiu de mai sus. Presupunem că schemă este astfel configurată astfel încât tranzistoarele să funcționeze în stările de blocare și saturație.

O caracteristică importantă a punctii H este aceea că permite curentului să circule prin sarcina în ambele sensuri. În cazul unui motor de curent continuu, această înseamnă că putem comandă motorul să se rotească atât în sens pozitiv, cât și în sens negativ.

Rotația în sens pozitiv

Se alege un sens oarecare drept sens de referință al curentului prin motor (de exemplu de la stânga la dreapta). Astfel, pentru că motorul să se rotească în sens pozitiv este necesar că sensul curentului să fie același cu sensul de referință.

Puntea H trebuie comandată astfel încât tranzistoarele Q1 și Q4 să conducă (la saturație), iar tranzistoarele Q2 și Q3 să fie blocate. Așadar, pe bazele lui Q1 și Q4 se aplică logică înalta, iar pe bazele lui Q2 și Q3 se aplică logică joasă.

Curentul va circula de la sursă de alimentare, prin joncțiunea colector-emitor a tranzistorului Q1, prin sarcina (în cazul nostru motorul de curent continuu), prin joncțiunea colector-emitor a tranzistorului Q4, și se va scurge la masă.

În cazul în care se neglijeaza căderile de tensiune pe jonctiunile colector-emitor la saturație, tensiunea aplicată sarcinii va fi egală cu cea a sursei de alimentare. Dacă ținem seama și de tensiunile de pe joncțiuni, vom avea:

si, intr-o buna aproximatie:

Dacă se dorește controlul turației motorului, pe bazele tranzistoarelor Q1 și Q4 se vor aplică impulsuri PWM, iar pe bazele lui Q2 și Q3 se va aplică logică scăzută. Pentru a ne asigura de o funcționare corectă, presupunem că perioada și durata impulsurilor PWM sunt mult mai mari decât timpii de comutatie ai tranzistoarelor.

Rotația in sens negativ

Această situație este similară celei anterioare; diferența constă în sensul curentului prin sarcina.

În acest caz, curentul prin sarcina trebuie să fie opus sensului de referință. Pentru această, tranzistoarele Q1 și Q4 vor fi blocate, iar Q2 și Q3 vor conduce la saturație. La bazele tranzistoarelor Q1 și Q4 vom aplică logică joasă, iar la bazele lui Q2 și Q3 vom aplică logică înalta. Analog cazului anterior, dacă se dorește controlul turației motorului, pe bazele tranzistoarelor Q2 și Q3 se vor aplică impulsuri PWM, iar pe bazele lui Q1 și Q4 se va aplică logică scăzută.

Frânarea motorului

Dacă cele două regimuri de funcționare erau valabile pentru orice tip de sarcina, nu doar pentru motoare de curent continuu, regimul ce va fi descris în continuare se va referi la aplicațiile în care puntea H comandă în mod exclusiv un motor de curent continuu.

În exploatarea unui astfel de motor, poate interveni o situație în care să dorim oprirea motorului. O soluție simplă și la îndemână ar fi întreruperea motorului de la sursă de alimentare, caz în care motorul va încetini și se va opri de la sine. În cazul punții H, acest lucru se obține dacă aplicăm la bazele tuturor tranzistoarelor logică joasă.

Dezavantajul abordării de mai sus este constituit în principal de timpul mare consumat până la oprirea motorului. O soluție mai eficientă ar fi fructificarea faptului că motorul se comportă și că un generator: pentru a frână rapid un motor, îl deconectăm de la sursă de alimentare si ii scurtcircuitam bornele. Pe de-o parte, motorul se comporta ca un generator, deci va genera o tensiune la bornele sale. Pe de alta parte, acea tensiune va comanda motorul sa se roteasca in sens opus. Efectul ce se obtine este o oprire rapida a motorului.

Procedeul descris mai sus se numeste franare dinamica si este folosit pentru o larga clasa se motoare de curent continuu.

In cazul puntii H, pentru a obtine acest efect, avem doua variante:

– aplicarea de logica inalta tranzistoarelor Q1 si Q2, respectiv de logica joasa lui Q3 si Q4

– aplicarea de logica inalta tranzistoarelor Q3 si Q4, respectiv de logica joasa lui Q1 si Q2

Cele doua variante sunt echivalente, alegerea uneia dintre ele depinzand eventual de detalii constructive.

Criteriile pentru selecția unui set de drivere motor corespunzătoare

Definiție: curentul nominal – reprezintă curentul maxim pe care îl poate conduce în timpul funcționarii continue. Cele șase motoare alese necesită un curent maxim de 300 mĂ la tensiunea nominală de 12 V. Dar, pentru a facilita comandă direcției robotului s-a optat pentru asocierea acestora în două grupuri de câte trei motoare, conectate în paralel. Așadar s-au utilizat două drivere de motor aferente celor două grupuri motor (stânga/dreapta), fiecare dintre acestea fiind caracterizat e un curent nominal mai mare decât 900 mĂ ~ 1 A.

Definiție: curentul „stall” – reprezintă curentul maxim care poate fi condus în situația în care motorul funcționează în regim blocat. Acesta mărime este de luat în calcul fie în cazul unui scenariu clasic în care sarcina atașată motorului depășește capacitatea acestuia, fie la pornirea (angrenarea) inițială a motorului de curent continuu. În cazul motoarelor alese curentul „stall” la tensiunea nominală de 12 V este de 5 A per motor. Așadar puntea H aferentă unui grup motor ar trebui dimensionată astfel încât să asigure un curent maxim de peste 15 A (în regim de blocare).

curentul maxim pe care îl poate conduce – trebuie să fie mai mare decât cerințele motoarelor la calare. Dacă motoarele necesită un curent mai mare decât puntea H poate să suporte, atunci cea din urmă se poate arde. (Cmax > 15 A).

gama tensiunii de alimentare a motoarelor – motoarele alese funcționează la 12 V, deci ar trebui ca tensiunea de 12 V să se afle în gama de funcționare a punții H.

facilitati de control in PWM la o frecventa compatibila cu microcontrollerul.

arhitectura cu unul sau maxim doua canale.

Pololu High-Power Motor Driver 24v20

Pe baza criteriilor din secțiunea anterioară au fost alese doua drivere Pololu High-Power Motor Driver 24v20.

Structura pinilor:

Figura 3.6. Structura pinilor pentru driverul motor Pololu High-Power Motor Driver 24v20

Tabelul 3.3. Funcționalitatea pinilor pentru driverul motor Pololu-High Power Motor Driver 24v20

Erori specifice:

Driverul poate detecta trei tipuri distincte de erori (Tabelul 3.4) raportate prin intermediul celor doi pini FF și în funcție de gravitatea acestora poate bloca sau nu ieșirile către motoare.

Tabelul 3.4. Erori specifice pentru driverul motor Pololu-High Power Motor Driver 24v20

3.1.3 Senzori

Senzorii desemnează componente ale roboților mobili și nu numai care au capacitatea de a măsură și de a transpune în format numeric (interpretabil de către microcontroler) informația oferită de mediul real precum: distanță, temperatura, culoare etc.

Senzorii pot fi activi sau pasivi. Dacă senzorii emit energie în mediu pentru realizarea măsurătorilor, atunci sunt numiți activi iar dacă absorb energie din mediu pentru a fi capabili să realizeze măsurători atunci se numesc senzori pasivi.

In general, urmatoarele ipoteze sunt valabile pentru toate categoriile de senzori:

• Orice senzor este afectat de interferențe;

• Orice senzor oferă o informație incompletă a mediului în care efectuează măsurătorile;

Senzorii din roboții mobili se pot clasifica în:

senzori de distanță – desemnează senzorii capabili să reproducă numeric distanța dintre locația senzorului și un element al mediului caracterizat de anumite proprietati (ex: opacitate)

senzori de poziție – desemnează senzorii care ofera informații despre pozitia relativă a robotului într-un anumit context

senzori de mediu – desemnează senzorii care oferă informații despre anumite proprietăți ale mediului (ex: temperatură, culoare);

senzori inerțiali – desemnează senzorii care măsoară caracteristici diferențiale ale poziției robotului (ex: accelerația)

Pentru asigurarea funcționalității platformei mobile de supraveghere video s-au folosit două tipuri distincte de senzori: senzori de proximitate de tip sonar (ultrasunete) și un senzor video de tip CMOS.

3.1.3.1 Sonar

Pentru furnizarea informațiilor cu privire la obstacolele existente în perimetrul apropiat robotului si pentru implementarea modului de scanare automată s-a optat pentru integrarea a patru senzori de tip sonar.

Senzorii cu ultrasunete sunt unii dintre cei mai utili și eficienți senzori din dotarea

roboților. Acesti senzori masoara foarte precis, distantele fata de obstacolele existente in mediul real si asigura datele de intrare pentru cele mai multe dintre task-urile importante ale robotilor:

• masurarea distantei fata de repere fixe in raport cu care se poate realiza pozitionarea robotului mobil

• detectarea obstacolelor din mediul real (poziția și configurația lor), in scopul dezvoltarii unor algoritmi complecsi pentru evitarea lor si pentru calcularea unei potentiale alternative la traseu.

• identificarea poziției și orientării unor elemente externe, pentru stabilirea coordonatelor specifice unei eventuale atașări și cuplări;

Principiul de functionare al sonarului sustine ca un emițător sonar transmite un semnal acustic în mediu urmând apoi ca reflecția acestuia să fie recepționată de componenta cu rol de detector a senzorului. Intervalul de timp specific acestui ciclu este cronometrat si pe baza rezultatului obtinut senzorul sonar este capabil sa ofere informatii despre prezenta si distanta.

Principiul de funcționare al unui senzor ultrasonic tipic este prezentat în figura 3.7:

(Vss, Vdd – tensiune alimentare).

Figura 3.7. Principiul de functionare al unui senzor cu ultrasunete

Măsurarea distanței constă în măsurarea timpului de propagare a undelor între reperele

considerate.

unde:

• D – distanța

• t – timpul măsurat

• v – viteza de propagare a undei în mediul considerat

În general v depinde de indicele de refracție al mediului, care la rândul său depinde de

mai mulți parametrii (temperatură, presiune, umiditatea aerului, lungimea de undă), iar cunoașterea exactă a acestui aspect poate îmbunătăți precizia măsuratorilor.

Criteriile pentru selecția unui model de senzor tip sonar

distanța de măsurare cât mai mare pentru furnizarea în timp util a informațiilor ce vor fi prelucrate ulterior în vederea adoptării unei decizii pentru pilotul automat.

tensiune de alimentare comună (fie 5 V, fie 12 V).

consum redus

spectru de detecție direcțional (NU wide) pentru o localizare cât mai precisă a obstacolelor.

Maxbotix LV-MaxSonar-EZ4

Pe baza criteriilor din secțiunea anterioară au fost aleși patru senzori Maxbotix LV-MaxSonar-EZ4 caracterizați de următoarele specificații tehnice:

tensiune de alimentare cuprinsă între 2,5 V si 5,5 V cc.

curent debitat 2 mA

citiri ale distanței cu o frecvență de până la 20 Hz (50 ms)

domeniu de măsurare de până la 6,45 m

frecvență de operare 42 kHz

Impulsul de declanșare a măsurarii: impuls pozitiv TTL, 2μs minim, 5μs tipic;

Semnal receptat ca ecou: impuls pozitiv TTL, între 115 μs și 18,5 ms;

Zona de sensibilitate a senzorului Maxbotix LV-MaxSonar-EZ4 este reprezentata in figura 3.8:

Figura 3.8. Zona de sensibilitate a senzorului MaxBotix LV-MaxSonar-EZ4

Din figura de mai sus se poate trage concluzia că senzorul are o sensibilitate mare concentrată pe axa acustică (generatoarea conului). Faptul că zona este îngustă este avantajos, deoarece permite evaluarea poziției obiectului. Precizia mare este datorată suprafeței drepte a paravanului și orientarea sa care reflectă majoritatea undelor sonore îinapoi spre senzor.

Nota: Nu poate fi măsurată corect distanța la un obiect care:

a. se află la mai mult de 3m distanță;

b. prezintă suprafețe care nu reflectă undele acustice înapoi spre dispozitiv;

c. este prea mic pentru a reflecta destule unde acustice.

O sensibilitate scăzută a senzorului se constată și în cazul în care obiectul este alcătuit din materiale moi sau prezintă forme neregulate. Senzorul poate detecta suprafața apei, dar este predispus la deteriorări din cauza umezelii și condensației, în consecință nu este recomandat pentru uz în aer liber sau în preajma apei.

Structura pinilor:

Figura 3.9. Structura pinilor pentru sonarul MaxBotix LV-MaxSonar-EZ4

3.1.3.2 Camera video PAL

Pentru capturarea imaginilor video a fost impusă integrarea unui senzor optic, sub formă unei camere video de mici dimensiuni și cu o rezoluție adecvată.

Noțiunea de senzor video

Toate camerele video digitale integrează un "senzor de imagine".Acești senzori conțin milioane de diode fotosensibile dispuse matriceal, numite puncte (pixeli). În momentul în care obturatorul de lumina se deshide, fiecare punct memorează intensitatea luminii la care este expus care ulterior este transpusă în format numeric pentru a putea fi prelucrată de un procesor digital. Captura video este reprezentată în formă digitală drept o matrice de mii / milioane valori, fiecare valoare fiind corespunzătoare unui element fotosensibil fizic al senzorului.

Senzorii CMOS

Senzorul de imagine este componentă cu cea mai mare importantă în cadrul unei camere digitale fiind interfață la nivelul căreia imaginea este transpusă în format digital.

Senzorii CMOS funcționează după principiul transformării sarcinilor electrice în informații digitale și pot fi programați să detecteze marginile și să preproceseze imaginea încă din faza de captura. Avantajul major al acestui tip de tehnologie este dimensiunea redusă pe care o poate lua camera video ce integrează un astfel de senzor, consumul de energie mic și zgomot termic redus, costuri de producție mici. Problemele principale cu care se confruntă un astfel de senzor se referă în principal la zogomul de ansamblu care este mai mare decât în cazul senzorilor CCD rezultat datorită rezistenței și interferenței. Fiecare element fotosensibil din cadrul senzorului CMOS transformă încărcătură electrică în tensiune, urmând că această să fie amplificată tot la nivelul senzorului. Are loc apoi prelucrare în vederea reducerii zgomotului de imagine. Toate aceste demersuri se realizează din dorința de a furniza direct imaginea digitală în formă finală, însă fiecare subansamblu de procesare crește complexitatea senzorului și reduce suprafață disponibilă pentru elementul fotosensibil în sine.

Criteriile pentru selecția unui model de senzor video

dimensiuni compacte

consum redus

rezolutie cat mai mare

tensiune de alimentare comuna (fie 5 V, fie 12 V).

FatShark PAL FPV Camera

Pe baza criteriilor din secțiunea anterioară a fost ales un sistem ce integrează atât camera video propriu-zisă, care la rândul sau înglobează și un set de două microfoane (stânga/dreapta) pentru capturarea sunetului, precum și un braț mobil cu două grade de libertate având asociate două servomotoare de mici dimensiuni.

Camera video dispune de o arhitectură internă de tip senzor 1/2.5" CMOS, cu o rezoluție de 5 MP cu distanță focală fixă 3.5 mm care asigura un unghi de deschidere de 146 grade. Tensiunea de alimentare este de 5 V iar consumul aproximativ este de 300 mA. Camera dispune de funcția AV out care este utilizată pentru transmisia cadrelor în timp real dar este dotată și cu un slot de memorie microSD pentru înregistrarea clipurilor video la o rezoluție maximală și la o calitate nealterată. Magistrala de comunicație cu dispozitivul de transmisie wireless este standardizată (Figura 3.10):

Figura 3.10. Structura internă a magistralei de comunicație cu dispozitivul de transmisie wireless

Figura 3.11. Senzorul video FatShark PAL FPV Camera

Cele două servomotoare au rolul de a orienta brațul pe cele două axe de coordonate, X si Y.

3.1.4 Modulul wireless de comandă

Conexiunea wireless între robot și PC a fost structurată în două module ce dispun de echipamente hardware distincte:

• un modul wireless pentru emisia comenzilor către robot și pentru recepționarea informației de la senzorii de proximitate.

• un modul wireless pentru recepționarea semnalului audio-video furnizat de camera CCD integrată la nivelul platformei mobile.

Tehnicile de comunicație utilizabile pentru transmiterea datelor între un robot mobil și PC restrâng, în majoritatea aplicațiilor specifice, gama tehnologiilor la cele cu o rază de acțiune mobilă dar limitată, care sunt reprezentate de standardele wireless (fără fir), radio sau infraroșu.

Prioritățile în proiectarea sistemelor de comunicație wireless au fost multă vreme axate pe creșterea performanțelor de transmisie prin aer iar principalele probleme apărute vizau interferențele și atenuarea generată de mediu. În ultimii ani însă aceste probleme au fost compensate treptat, în prezent luându-se puternic în calcul creștere eficienței spectrale.

3.1.4.1 Conexiunea serială

Transmisia digitală de date a evoluat de la conexiunea simplă între un calculator și echipamentele periferice, la calculatoare interconectate în rețele internaționale complexe. Chiar dacă transferul paralel este mai rapid, majoritatea transmisiilor de date între calculatoare sunt făcute în manieră serială datorită costurilor conectorilor și respectiv a cablului. Totodată abordarea paralelă este caracterizată de anumite limite pentru distanță de transmisie. În comunicația serială, datele sunt transmise bit cu bit. Orice tehnologie de comunicație este caracterizată de trei elemente:

Date – întelegerea lor, scheme de codificare, cantitate

Temporizari – sincronizarea între receptor si emițător, frecvență și fază

Semnale – tratarea erorilor, controlul fluxului și rutare

Un model standard de comunicație serială este ilustrat în figura 3.12:

Figura 3.12. Model standard de comunicatie seriala

1. ETD – Echipamente terminale de date (calculatoare, terminale de date). Acestea sunt dotate cu interfetele seriale sau alte controlerele de comunicație.

2. ECD – Echipamente pentru comunicația de date. Aceste echipamente se numesc si modemuri și fac posibila comunicatia utilizand linia telefonica sau aerul:

Funcțiile principale ale unui modem sunt:

• Conversia digital/analogică și conversia analog/digitală a informatiilor transmise de un ETD respectiv a semnalelor receptionate de un ETD.

• Modularea/demodularea unui semnal purtător. La transmisie, modemul suprapune

(modulează) semnalele digitale ale calculatorului peste semnalul purtător al liniei

telefonice. La recepție, modemul extrage (demoduleaza) informațiile transportate de

semnalul purtător și le transferă calculatorului.

3. Linia de comunicație – conexiune fizică sau o conexiune telefonică. Conexiunea / linia telefonică poate fi conectată la o centrală telefonică sau poate fi o linie dedicată.

4. Circuitul de date reprezinta elementul dintre două ETD, deci, modemurile și linia de comunicație. Daca distantele sunt mici modularea nu este necesara si deici este posibilă comunicația seriala directa intre doua ETD (fara modemuri).

5. Legătura de date include circuitul de date și interfetele seriale ale ETD. Conexiunea seriala poate fi stabilita intre doua ETD (point-to-point) sau intre mai multe ETD (multipoint). Protocolul de comunicatie seriala ramane acelasi insa configurarea modemurilor se modifica, fiind necesara de obicei dezvoltarea unei structuri de interconectare.

Parametrii comunicației seriale

Viteza de comunicație (bitrate) este măsurată în biți/s (bps):

D= 1/T [biți/s]

unde T este perioada de timp necesară pentru transmisia sau recepția unui singur bit.

Modemul asociaza semnaleleor de date diferite stări electrice, în funcție de tipul

modulației pe care îl utilizează: frecvență, amplitudine, sau fază. Fiecare stare electrică este menținută la ieșirea modemului pentru un interval de timp numit perioadă de modulație (∆).

Viteza de modulație este (baudrate) inversul perioadei de modulație, reprezentând numărul schimbărilor pe secundă ale stării electrice a modemului:

Vm=1/∆ [baud]

D = Vm * log2 n [biți/s]

unde n este numărul stărilor electrice distincte ale modemului. În cazul particular când există doar două stări electrice distincte ale modemului, viteza de comunicație este egală cu viteza de modulație.

Relatia intre viteza de comunicatie si viteza de modulatie sustine ca prima marime este un multiplu a celei de-a doua marimi.

Viteza de comunicatie nu trebuie confundata cu viteza de modulatie. Explicit, viteza de modulatie desemneaza rata schimbarilor starilor electrice ale modemului. Drept exemplu daca un modem are capacitatea de a modifica starea electrica cu o rata de 28800 ori pe secunda viteza sa de modulatie va fi 28800 baud. Daca modemul ar codifica aceasta informatie pe un singur bit atunci si viteza de comunicatie ar fi 28800 biti/s. Insa, modemurile contemporane reusesc codificarea mai multi biti de informatie printr-o singura stare electrica, pe patru sau chiar 8 biti. Asadar, reluand examplul initial, pentru o codificare de tipul 4 biti de informatie printr-o anumita frecventa, se va obtine o viteza de comunicatie de aproximativ 4 x 28800 = 115200 biti/s

Transmisie simplex și duplex

Comunicatia seriala poate fi realizată pe un singur canal sau pe două canale.

Pentru ca un sistem de tip robot mobil wireless să-și îndeplinească functia de control supervizare și functiile de achizitii de date informatiile trebuie vehiculate în ambele directii. Termenii care descriu capacitatea unui sistem de comunicatii de a vehicula informatia sunt: simplex, half duplex și duplex sau ful duplex.

Sistemele simplex permit ca informatia să fie vehiculată într-un singur sens. Exemplu: transmisia radio a informatiilor unei sonde meteorologice către o statie receptoare și toate retele comerciale de radio și televiziune.

Sistemele duplex sunt acele sisteme pentru care informatia este transmisă și receptionată în același timp. Duplex este echivalentul a două sisteme simplex lucrând în paralel în directii opuse (Figura 3.13).

Figura 3.13. Model duplex de comunicatie seriala

Este evident că sistemul duplex este avantajos din punct de vedere al utilitătii dar prezintă dezavantajul pretului ridicat fiind necesară dublarea căii de comunicatie. Ca un compromis există sistemul half duplex care permite utilizarea unei singure căi de comunicatie (pereche de fire sau frecventă radio) pe care datele sunt transmise uneori într-un sens alteori în celalalt (Figura 3.14).

Figura 3.14. Model half duplex de comunicatie seriala

Sincronizare – frecvență și fază

Este necesar un mecanism care să permită receptorului să citească corect bitul curent de intrare la jumătatea duratei lui. Receptorul trebuie să știe durata unui bit și de unde începe bitul respectiv, adică trebuie să cunoască frecvența și faza secvenței de date. Dacă emițătorul și receptorul au același semnal de tact, sincronizarea este perfectă; emițătorul scrie bitul pe frontul crescător al tactului, iar receptorul citește bitul pe frontul coborâtor al tactului. Problemele apar când receptorul și emițătorul nu au un semnal de tact comun. Dacă duratele celor două semnale de tact, pentru emițător și receptor, nu sunt egale, apare o decalare, care după un anumit număr de biți rezultă într-o eroare. Pentru a evita această, receptorul trebuie resincronizat regulat la nivel de bit. Din alte motive, trebuie resincronizate și începutul unui caracter, pachet sau mesaj. În figura 3.15, în primul caz, fiecare bit este citit la mijlocul duratei lui, iar în cazul al doilea, bitul 4 se pierde deoarece tactul receptorului este prea încet.

Figura 3.15. Exemplu sincronizare ideală și sincronizare coruptă

Dacă emițătorul și receptorul au același semnal de tact atunci se spune că lucrează în mod Sincron. Altfel, dacă au semnale de tact separate, atunci lucrează în mod Asincron.

În modul asincron, emițătorul nu trimite un tact deodată cu datele, ci inserează un pseudo-impuls de tact, cunoscut că Bit de Start, în față fiecărui octet transmis. Astfel, pentru fiecare caracter ASCII avem o transmisie independența, cu adăugarea biților de Start, Stop și Paritate. Viteză de lucru se stabilește manual la începutul transmisiei. Pentru informația de faza, receptorul trebuie să detecteze începutul bitului de Start. Pentru că această metodă să funcționeze, trebuie să existe, o perioada de liniște între caractere, realizată cu bitul de Stop.

În modul sincron, caracterele sunt transmise rapid, unul după altul, fără biți de Start și de Stop. Pentru sincronizare, mesajul transmis este precedat de caractere speciale de sincronizare, detectabile de circuistica receptorului. Acestea sunt transmise încontinuu și când nu sunt date de transmis. Transmisiile în mod sincron pot folosi scheme de inteligente de modulare, care se bazează pe circuistica suplimentară, iar semnalele de date și tact folosesc aceeași pereche de fire. Această metodă, cunoscută sub numle de codificare Manchester, este folosită în rețele Ethernet.

Paritatea este cea mai discutată metodă de detecție a erorilor pentru protecția transmisiilor seriale de caractere ASCII. La oricare din metode, emițătorul prelucrează o parte din date și generează un fel de semnătură pe care apoi o transmite împreună cu date utile. Când mesajul ajunge la receptor, acesta prelucrează datele primite și generează o semnătură pe care o compară cu cea primită. Dacă cele două semnături nu coincid, atunci s-a produs o eroare. Metodă bitului de paritate se poate aplică pentru date binare de orice lungime. Pentru fiecare cuvânt este adăugat un bit de paritate (semnătură). Paritatea poate fi pară (cuvântul conține un număr par de 1) sau împără (cuvântul conține un număr impar de 1). Calcularea parității se poate face cu operatorul XOR (SAU Exclusiv) între bîțîi cuvântului. Prin această metodă este posibilă doar detecția erorii singulare, când sunt afectați un număr impar de biți. O eroare dublă (afectează un număr par de biți) nu poate fi detectată prin acest mecanism. Prin urmare, această metodă nu oferă prea multă securitate. Un singur bit de paritate nu oferă informații despre poziția erorii.

Suma de control la nivel de bloc este un mecanism de detecție a erorilor de transmisie. Prima dată este necesar că datele să fie împărțite în blocuri, care apoi se însumează și se obține o suma care va fi trunchiată, inversată și adăugată la sfârșit. La recepție, blocurile primite, care includ și suma de la sfârșit, se adună pe măsură ce sosesc, și dacă suma obținută nu este 0 atunci înseamnă că datele sunt eronate și secvență trebuie retransmisă. Nu este posibilă corecția erorii. Pentru identificarea erorilor multiple și corecția lor, s-a dezvoltat mecanismul BCH, dar acesta nu va fi prezentat.

O altă metodă de detecție a erorilor este CRC (Cyclic Redundant Check). Și în acest caz se calculează o suma de control, dar prin împărțire aritmetică. Secvență de biți este împărțită cu un număr special ales. Împărțirea se face în modulo 2, adică folosind operatorul XOR. Restul împărțirii reprezintă semnătură care va fi adăugată la sfârșit, după bîțîi utili. Divizorul se obține cu algoritmul folosit la codurile Hamming. La recepție, se recalculează restul împărțirii și dacă nu coincide cu cel primit, atunci secvență este eronată.

Protocoale de comunicație serială

Există o multitudine de protocoale care au fost de-a lungul timpului utilizate pentru comunicația serială. Cele mai comune sunt însă:

I²C – Inovatia PHILIPS – IC 2 IC Comunication – sau IIC

Acest protocol inventat și dezvoltat de Philips a apărul prima oară pe plăcile televizoarelor. Este nevoie doar de două sârme: ȘCL (ceasul) și SDA (dată). Configurațiile posibile sunt mulți_master – mulți slave, existând mecanism de arbitrare între masteri.

Avantaje:

• configuratie multi master – posibilitatea arbitrarii masterilor

• clock-stretching – perifericele lente pot “cere” un delay de la master

• utilizarea intensiva a bit-ului ACK (acknowledge) o detectia foarte simpla a perifericelor active (in functie de configuratia placii, avand un soft unic, se poate detecta la start-up care sunt perifericele prezente pe magistrala) o validarea rapida a datelor

• doar doua sarme pentru toata magistrala

Dezavantaje:

• viteza mica de transfer

• selectia perifericului (prin adresa de slave) adauga overhead la comunicatie

SPI – Inovatie Motorola – Serial Periferical Interface

Motorola a dezvoltat aceast protocol și l-a impus prin intermediu microcontrolerelor HC11. Este un protocol foarte rapid, care însă nu permite direct prezența pe magistrala a doi sau mai mulți masteri.

Schema de arbitrare trebuie efectuată extern, folosind un circuit auxiliar. În plus, perifericele mai lente nu pot semnaliza o cerere de amânare/întârziere a comunicație. Față de IIC, mai apare o sârmă. Dacă la IIC, SDA este sârmă de date și este bidirecțională, la SPI apar două sârme, MasterOutputSlaveInput și MasterInputSlaveOutput. MOȘI și MISO sunt unidirecționale. Microcontrolerul folosit la laborator este capabil să utilizeze acest protocol (implementare hardware).

Avantaje:

• viteza foarte mare

• selectia directa a slave-lui (dar, pentru fiecare slave, este nevoie de o noua sarma)

• simplitate in utilizare (la nivelul legatura de date OSI)

Dezavantaje:

• chiar cu un singur slave, este nevoie de 4 sarme iar cu 2 slave, este nevoie de 5 sarme.

• lipsa arbitrarii intre masteri

• lipsa clock-stretching-ului – perifericele lente nu au ce cauta pe aceasta magistrala

• lipsa unui bit de ACK – validarea pachetelor trebuie facuta la un nivel superior

3.1.4.2 Modul wireless de comunicație serială

Criteriile pentru selecția modulului de comanda wireless

Capacitate de transmisie adecvata fluxului de date bidirectional (PC-robot si invers)

Raza de actiune cat mai mare (eventual posibilitatea de atasare a unor antene)

Folosirea de benzi radio fara licenta

Consum redus

Dimensiuni compacte

tensiune de alimentare comuna (fie 5 V, fie 12 V).

XBee Pro S28

Pe baza criteriilor din secțiunea anterioară a fost ales un echipament wireless de tip XBee Pro S28 RPSMA ce utilizează o infrastructură de tip ZigBee pentru realizarea comunicației.

ZigBee definește un set de protocoale de comunicație la nivel înalt, ce utilizează emițătoare radio de dimensiuni mici, cu un consum energetic redus, bazate pe standardul 802.15.4 ce definește rețelele WPAN (Wireless Personal Area Networks).

Tehnologia promovată de acest tip de rețele este mai simplă și prezintă costuri mai reduse decât în cazul rețelelor Bluetooth. Acest tip de rețele a fost proiectat și etichetat aplicațiilor ce necesită o viteză de transmisie a datelor redusă, o gestiune optimizată a consumului de energie pentru asigurarea longevității maxime a surselor și a securității rețelei de lucru. Tehnologia Zigbee este utilizată deja în aplicații foarte mari, interesante, deși nu sunt publice: securitate, sisteme de control, sisteme de monitorizare, aplicații militare sau industriale. Este o tehnolgie simplă și eficientă din punct de vedere economic. Este chiar mai ieftină decât tehnologia Wi-Fi, care este tot mai accesibilă. Există și numeroase aplicații în care cele două tehnologii conlucrează.

ZigBee oferă funcționalitate de nivel înalt în ceea ce privește structura rețelei rutarea mesajelor și securitatea. Această funcționalitate este oferită de nivelul software. Nivelul fizic sau legătură de date este bazat pe standardul IEEE 802.15.4.

Dispozitivele XBee reprezintă soluția hardware pentru implementarea unei comunicații ZigBee și, deși sunt produse în mai multe configurații tehnice, toate înglobează câteva principii de baza precum:

Topologii de retele mai flexibile

Rutare de mesaje inteligenta

Masuri de securitate imbunatatite

Consum de energie foarte redus

Folosirea de benzi radio fara licenta

Instalarea usoara

Cost redus

Modelul ales, XBee Pro S28 (Figura 3.17) face parte, așa cum o transmite însuși numele sau, din seria profesională de module emisie-recepție, fiind caracterizat de următorii parametrii tehnici (Tabelul 3.6):

Configurația pinilor de baza este similară pentru toate modulele XBee existente (atât prima generație cât și cea secundă).

Structura pinilor:

Figura 3.16. Structura pinilor pentru modulul XBee Figura 3.17. Modulul wireless de comunicație serială Xbee

Realizarea comunicației între PC și robot a presupus integrarea a două module de tip XBee Pro S28 (asociate celor două puncte terminale). Problemele de interconectare cu PC-ul și respectiv cu placă de baza a robotului (Arduino UNO R3) au fost rezolvate prin intermediul unor adaptoare de tip “socket” adecvate configurației pinilor celor două plăci wireless. Socket-ul aferent robotului are rolul de a reproduce structura pinilor modulului wireless de comandă (Figura 3.19), în vederea realizării lipiturilor (nu are rol funcțional), pe când socket-ul aferent PC-ului (Figura 3.18), pe lângă funcționalitatea standard de a prelua/transmite informația dinspre/către modulul wireless de comandă prin intermediul USB, integrează și un chip de tip FTDI care permite programarea oricărui modul XBee.

Figura 3.18. Adaptor cu chip FTDI pentru Figura 3.19. Structura pinilor adaptorului de tip

programarea XBee de tip socket “socket”

Modul wireless streaming video

Soluția tehnică adoptată a presupus module distincte pentru implementarea părții de comandă a robotului respectiv recepție a datelor de la senzorii de proximitate și transmiterea/recepția semnalului video.

Modulul wireless pentru streaming video este definit că unul sau mai multe dispozitive electronice, având capacitatea de a transmite și respectiv recepționa wireless un semnal video în format analogic între două puncte aflate la distanță, separate printr-un mediu care permite comunicația radio.

Pentru evitarea perturbatiilor reciproce între modulul wireless de comandă și modulul wireless de streaming video, ar fi indicat că acesta din urmă să funcționeze într-un spectru de frecvența diferit ( orice frecvența diferită de 900 MHz).

Este cunoscut faptul că odată cu scăderea frecvenței, propagarea semnalului transmis are loc la distanță mai mare, însă volumul de date vehiculat scade. Întrucât aplicația se rezumă la transmisia unui semnal de tip video, care nativ este caracterizat de un volum ridicat de date vehiculate, abordarea unor frecvente mai mici decât 900 MHz nu s-a considerat.

Criteriile pentru selecția modulului wireless pentru streaming video

rata de transfer adecvata rezolutiei de 520 de linii (640×480) a camerei

frecventa de operare diferita si mai mare de 900 MHz

Raza de actiune cat mai mare (eventual posibilitatea de atasare a unor antene)

Folosirea de benzi radio fara licenta

Consum redus

Dimensiuni compacte

tensiune de alimentare comuna (fie 5 V, fie 12 V).

Sistem FPV TX/RX 200mW 2.4 GHz

Pe baza criteriilor din secțiunea anterioară a fost ales un echipament wireless de tip FPV avnad o putere de emisie de 200mW și o rază de acțiune standard de 500 m care poate fi extinsă cu ajutorul unor antene direcționale (Figura 3.20).

Figura 3.20. Echipament wireless de tip FPV TX/RX 200 mW 2.4 GHz

Acest echipament constă dintr-o pereche de module emisie-recepție dotate cu un conector SMA pentru atașarea antenelor omnidirecționale incluse (sau a altor tipuri de antene). Fiecare dintre cele două module dispune de câte un panou de configurare (panou de switch-uri) prin intermediul cărora se fixează bandă de operare, în jurul valorii de 2,4 Ghz. Interconectarea cu senzorul optic se realizează printr-un conector standardizat, iar cu monitorul sau placă de captura aferentă unui PC printr-un conector de tip RCA.

3.1.6 Motoare

Pentru construcția roboților mobili se folosesc în general două tipuri de motoare: motoare de curent continuu și motoare pas cu pas. Fiecare dintre ele prezintă avantaje și dezavantaje.

Motoarele de curent continuu sunt cele mai folosite în locomoția roboților mobili. Sunt curate, silențioase, destul de ușor de controlat și generează suficientă putere pentru a putea fi folosite într-o multitudine de situații. Pentru că turatiile la care lucrează sunt în general prea mari pentru a fi utile în aplicațiile de robotică, se obișnuiește folosirea de reductoare; astfel, toată gama de turații devine utilă, iar cuplul “la ax” crește.

Un motor pas cu pas diferă de un motor de curent continuu prin faptul că rotorul lui are o mișcare în pași discreți și nu una continuă. Tensiunea aplicată la borne nu este una continuă, ci este sub formă de impulsuri. Există o legătură directă între impulsurile aplicate la borne și pașii făcuți de motor. Deși au multe avantaje (pot menține o anumită poziție a rotorului, au un răspuns excelent la pornire/oprire/schimbarea sensului de rotație, caracterul discret al funcționarii înseamnă că interfațarea cu un sistem de prelucrare digital este naturală, pot fi folosite într-o schemă de control în buclă deschisă fără alte componente suplimentare), prin faptul că sunt gălăgioase, lente, imprecise (pot să sară pași), iar raportul greutate/performanță este mai mic decât în cazul motoarelor de curent continuu, motoarele pas cu pas sunt rar folosite în aplicațiile cu roboți mobili.

3.1.6.1 Motoare c.c. cu demultiplicare

Vom incerca sa modelam un motor de curent continuu ca pe un dipol activ, caracterizat prin constante concentrate. In primul rand, din punct de vedere electric, introducem urmatorii parametri ce caracterizeaza modelul motorului. Astfel, vom avea:

Φ -fluxul magnetic indus de magnetul rotorului

E – t.c.e.m

UM – tensiunea pe motor (la borne)

IM – curentul prin motor

M γ – rezistența electrică a indusului

Ke , KM – constante electrică și mecanică

Ω – turația

M – cuplul motor

Motorul de c.c. este descris de sistemul de ecuații :

Dacă motorul se rotește cu o anumită turație, înfășurările rotorului se vor mișcă într-un câmp magnetic, ceea ce se poate modela cu un generator de tensiune (vom vedea că această tensiune indusă este proporțională cu turația momentană a motorului). De asemenea, tensiunea electromotoare indusă se opune tensiunii de alimentare a motorului.

Introducând așadar mărimea e (tensiunea electromotoare indusă), putem alcătui următoarea schema ce modelează din punct de vedere electric un motor de curent continuu:

Figura 3.21. Modelul unui motor de c.c.

Pentru a caracteriza complet comportarea unui motor, avem nevoie de încă două presupuneri referitoare la fenomenele de transformare a energiei electrice în energie mecanică (comportament de motor) și invers (comportament de generator). Așadar, considerăm următoarele relații:

M = KM i

e = KE 

unde KM și KE sunt constantele mecanică și respectiv electrică ale motorului. Observăm că momentul de cuplu mecanic dezvoltat de motor este proporțional cu intensitatea curentului electric ce trece prin armături, iar tensiunea electromotoare indusă este proporțională cu turația motorului.

Criteriile pentru selecția motoarelor de c.c.

Posibilitatea de integrare a minim patru motoare pentru solutionarea problemei directiei

Consum in regim de stall cel mult egal cu 7 A

Alimentare la o tensiune de maxim 18 V

Cuplu adecvat

Demultiplicare pentru depasirea obstacolelor

Pololu 29:1 Metal Gearmotor 37D

Pe baza criteriilor din secțiunea anterioară au fost alese sase motoare de curent continuu marca Pololu, caractrizate de urmatoarele specificatii tehnice (Tabelul 3.8):

3.1.6.2 Motoare c.c. pas cu pas

Motoarele pas cu pas sau servomotoarele reprezintă componente esențiale, de execuție și de precizie, în structura unui robot mobil, utilizate în principal pentru deplasarea robotului, dar și pentru realizarea unor mișcări, ce pot fi complexe și de mare precizie, ale unor organe/părți ale robotului. Ultimele decade au fost marcate de evoluții remarcabile în ceea ce privește dimensiunile, viteză de rotație și cuplul motor al motoarelor de tip servo.

O îmbunătățire deosebită constituie dezvoltarea servomotoarelor digitale ce au avantaje funcționale semnificative față de servomotoarele analogice (standard). În principiu, un servomotor digital este asemănător cu un servomotor standard, cu excepția unui microprocesor care analizează semnalele de intrare și controlează motorul.

Una din diferențe constă în modul de procesare a semnalelor de intrare și transmiterea puterii inițiale de la servomotor, reducând timpul mort, crescând rezoluția și generând un cuplu de menținere superior. La motoarele servo convenționale, în faza de repaus, nu se alimentează servomotorul. În cazul servomotoarelor digitale, când este primită o comandă de pornire a servomotorului, sau când se aplică un cuplu la axul de ieșire, servo-ul răspunde prin alimentarea cu tensiune a motorului.

Această tensiune, care este de fapt tensiunea maximă, este pulsată sau transmisă on/off cu o rată fixă de (spre exemplu 50 de cicluri pe secunda), generând scurte impulsuri de tensiune. Prin creșterea duratei fiecărui impuls se creează un control al vitezei, care poate crește progresiv când se aplică motorului tensiunea maximă fără întrerupere, accelerând servomotorul și deci robotul, sau organul acționat, spre noua poziție.

Comanda (controlul) servomotoarelor reprezintă partea esențială a acestora care asigură posibilitatea interfațării cu procesoarele prin care se execută programele și aplicațiile specifice robotului.

De fapt, sistemul de comandă al servomotorului constituie elementul care se adaugă și face diferența față de un simplu motor. În general aceste motoare sunt de curent continuu, obișnuite sau „pas cu pas”. Comanda elementelor de execuție (roboți sau organe/părți ale acestora) cu ajutorul motoarelor pas cu pas și a servomotoarelor de curent continuu, pentru a obține o mișcare incrementală precisă, este o problemă destul de dificilă, cu mai multe tipuri de soluții în funcție de aplicație și de caracteristicile urmărite.

În general, modelul comenzii pentru roboți mobili se poate aborda și asimila sistemelor cu dinamică lentă, care nu sunt supuse perturbațiilor electromagnetice (spre exemplu: acționarea mașinilor cu comandă numerică, a imprimantelor, plotter-elor etc.).

Sistemul de comandă pentru un servomotor de c.c este, practic, un sistem de acționare electrică, având în componență motorul electric (servomotorul de c.c), obiectul acționat, transmisia și elementul de execuție.

Figura 3.22. Modelul unui motor pas cu pas

• Motorul electric – ME – realizează transformarea puterii electrice în putere mecanică.

• Obiectul acționat – OA – este antrenat de ME și realizează anumite mișcări impuse.

• Transmisia – T – reprezintă legatura mecanică dintre ME și OA cu rolul de a realiza transferul de putere mecanică și, eventual, de a schimba parametrii acestei puteri (viteza unghiulară, cuplu).

• Elementul de execuție – EE – are drept scop alimentarea cu energie electrică a ME și comanda funcționării în conformitate cu anumite cerințe.

Pentru proiectarea acestui element (EE), se ține seama de următorii factori:

• caracteristica viteza unghiulară () – moment/cuplu () în regim staționar atât a motorului, cât și a obiectului acționat:

• gama de viteze de lucru necesare, definită ca fiind raportul dintre viteza unghiulară minimă și maximă;

• precizia de menținere a vitezei.

Comanda concretă a servomotoarelor de c.c. se face cu convertoare statistice de c.c. – c.c. (chopper-e), care la rândul lor pot fi comandate în funcție de semnalele asociate cu unul sau mai mulți dintre factorii menționați mai sus, dar la aceștia se adaugă semnalele de comandă care trebuie să asigure, prin procesor, execuția programelor specifice aplicației.

Pentru aplicatia platforma wireless robotizata pentru captura si analiza de imagine in timp real s-au utilizat doua servomotoare asociate bratului mobil cu doua grade de libertate pe care a fost montata camera video.

Criteriile pentru selecția motoarelor pac su pas

Dimensiuni si masa reduse

Unghi descis de minim 180 de grade

Servomotor DECTRUM 9G

Pe baza criteriilor din secțiunea anterioară au fost alese doua servomotoare marca DECTRUM, de mici dimensiuni, care dispun de un cadru din plastic ce asigura o masa redusa de numai 9 g. Tensiunea de alimentare este cuprinsa intre 4,8 V si 6 V iar unghiul descis este de 180˚. Viteza de rotatie este de 0,10 sec/60 ˚ iar cuplul de 1,4 kg/cm.

3.1.7 Acumulatori

După cum este cunoscut, acumulatorul electric, desemnează un dispozitiv care înmagazinează energie electrică sub formă chimică în vederea restituirii acesteia. Există trei mari tipuri de tehnologii care vizează principiul de funcționare al acumulatorilor electrici:

Ni-MH

Ni-Cd

Li-Ion

Li-Po

Acumulatorii Ni-MH au o densitate înaltã de energie și livreazã panã la o capacitate dublã a acumulatorilor Ni-Cd de aceeași mãrime. Sunt perfect potriviți/adecvați pentru aplicațiile sofisticate, de exemplu a camerelor video, telefoanelor mobile.

Acumulatorii Ni-Cd sunt caracterizați de durata de viață ridicată, și în funcție de condițiile de uzurã, pot avea 300 panã la maxim 1000 cicluri de incãrcare / descãrcare . Sunt construiți într-o protecție chimicã împotriva polarității opuse la supradescãrcãrii. O supapã de protecție este încorporatã pentru a elibera presiunea internã în caz de folosire inadecvatã.

Acumulatorii Li-Ion sunt caracterizați de o densitate de energie cu aproximativ 25% mai mare decât la Ni-MH și cu aproximativ 50 % mai mare decât la Ni-Cd. Voltajul pe celulã este de 3,7 volți, de trei ori mai mare decât al acumulatorilor Ni-Mh, permițând o mai simplã configurare a acumulatorului și un spațiu mai bun de utilizare pentru voltajul scăzut al celulelor. Tipul de grafit electrod negativ prezintã voltaj de descãrcare stabil, esențial pentru echipamentul electronic.

Acumulatorii Li-Po reprezintă generația ce înlocuiește NiCd și NiMH și se folosesc în aplicații unde masă acumulatorului este importantă. Această tehnologie oferă o mare densitate a energiei, greutate mică, și durata de exploatare convenabilă comparativ cu alte baterii.

Criteriile pentru selecția acumulatorilor

Satisfacerea bilanțului de consum calculat (de maxim 4 A)

Satisfacerea criteriilor de dimensiune si greutate reduse

Raport optim autonomie/dimensiune

Tensiune minimă de operare de 12 V

Acumulator KyPOM Li-Po 2200 mAh 4S 30C

Pe baza criteriilor din secțiunea anterioară au fost alesi doi acumulatori marca KyPOM de tip Li-Po, asigurandu-se astfel performantele unei tehnologii de ultima generatie si a unui raport foarte bun autonomie/dimensiune (greutate).

Specificații tehnice (Tabelul 3.9):

Conectică

Calculul și dimensionarea circuitelor de putere, caracterizate de curenți mari, reprezintă o problematica foarte importantă în preîntâmpinarea unor riscuri precum arderea componentelor electronice, aprinderea circuitelor, funcționarea atipică a echipamentelor etc.

Circuitele realizate se pot clasifică în două categorii:Circuite logice

Circuite de putere

Pentru circuitele logice s-au utilizat secțiuni mici – 0,5 mm2, 1 mm2 – în funcție de aplicație. Pentru circuitele de putere, prin care s-a realizat interconectarea acumulatorilor, driverelor de motoare și a motoarelor s-a aplicat o convenție care susține că la fiecare 5 A – 10 A care circulă prin respectivul cablaj se alocă o secțiune de 1 mm2.

Conectorii utilizați au fost pe cât posibil standardizați iar lipiturile fizice au fost izolate cu termocontractil, pentru protecție la scurt circuit.

3.2 Resurse software

Modulele software reprezentative pentru robotul de tip "Platforma wireless robotizată pentru captura și analiză de imagine în timp real” stuncturate în două mari categorii:

Aplicația PC caracterizată de o interfață grafică cu utilizatorul în cadrul căreia se exercită controlul asupra robotului (transmisia comenzilor) și se vizualizează într-un mod interactiv informația de la senzorii de proximitate și se realizează procesarea de imagine pentru algoritmii inteligenți

Algoritmul intern ce rulează pe microcontrolerul robotului care prelucrează comenzile date (recepția comenzilor) și care determină comportamentul acestuia.

Fiecare dintre aceste două module software este caracterizat de câte un limbaj de programare diferit și respectiv de medii de implementare (framework-uri) diferite. Așadar pentru implementarea algoritmului intern al platformei mobile s-a utilizat mediul de programare Processing (Arduino) bazat pe o sintaxa de tip C (fără facilități de limbaj orientat-obiect) iar pentru implementarea aplicației PC s-a utilizat framework-ul .NET, cu o sintaxa C#, care oferă de o serie de avantaje pentru interfațarea cu utilizatorul.

3.2.1 Mediul de dezvoltare Processing + Arduino

Processing reprezintă mediu de programare open source dezvoltat inițial pentru a servi că suport indivizilor interesați de programare hardware, în înțelegerea conceptelor de baza și a noțiunilor fundamentale. Ulterior, profilul mediului de programare Processing a fost modificat treptat, transformându-se în prezent într-o unealtă simplă și accesibilă pentru crearea de animații, imagini și grafică tridimensională. Mediul de programare Arduino derivă din formulă inițială Processing, păstrând principii de baza precum simplitatea și accesibilitatea și aduce o serie de facilități de upload a unui algoritm pe o placă de tip I/O Arduino. Statutul sau open source conferă avantajele majore ale unei comunități largi de utilizatori și implicit a unui suport substanțial în realizarea de aplicații. Sintaxa care stă la baza Processing și respectiv Arduino este de limbaj C.

Pe lângă structurile de control clasice (ex: if..else, for, switch..case, do..while etc.) mediul de dezvoltare Arduino oferă niște funcții specifice de prelucrare a semnalelor de intrare/ieșire analogice și digitale, funcții pentru calcule matematice și trigonometrice, precum și funcții de manipulare a variabilelor temporale (foarte utile întrucât rularea programului nu mai are loc secvențial ci se produce la nesfârșit în cadrul unei structuri de tip “while (true)”).

3.2.2 Limbajul de programare C

Figura 3.23. Logo limbaj de programare C

C este un limbaj de programare standardizat, compilat, de nivel mediu. Este implementat pe majoritatea platformelor de calcul existente azi, și este cel mai popular limbaj de programare pentru scrierea de software de sistem. Este apreciat pentru eficiența codului obiect pe care îl poate genera, și pentru portabilitatea sa.

C este prezentat uneori ca "asamblor portabil", făcându-se astfel diferențele principale față de limbajele de asamblare: codul unui program C poate fi compilat și rulat pe aproape orice tip de mașină (calculator), asemănător altor limbaje de programare, în timp ce limbajele de asamblare sunt specifice unui anumit model de mașină. Limbajul C aparține clasei limbajelor de nivel scăzut sau de nivel mediu, aceasta indicând strânsa legătură între interoperabilitate și echipamentul hardware.

C a fost creat având drept scop important de a face ca programele mari să poată fi scrise mai ușor și cu mai puține erori în paradigma programării procedurale, dar fără a pune un obstacole în scrierea compilatorului de C, care este încărcat de caracteristicile complexe ale limbajului. C are urmatoarele caracteristici importante:

Este un limbaj de bază simplu, cu importante funcționalități cum ar fi funcțiile matematice sau cele de manipulare ale fișierelor

Este focalizat pe paradigma programării procedurale, care facilitează programarea într-un mod structurat

Utilizează un set simplu de tipuri de date ce împiedică multe operații neintenționate

Folosește un limbaj preprocesor, preprocesorul C, pentru sarcini cum ar fi definirea de macrouri și includerea mai multor fișiere sursă

Permite accesarea la nivel scăzut a memoriei calculatorului prin utilizarea pointerilor

Permite folosirea parametrilor, care sunt comunicați funcțiilor prin valoare și nu prin referință

Pointeri la funcții, ce permit forme rudimentare de închidere (engleză closure) și polimorfism

Declararea variabilelor

Structuri de date sau tipuri de date agregate, definite de utilizator prin (struct), ce permit ca date înrudite să fie combinate și manipulate ca un întreg[necesită citare]

Printre caracteristicile ce lipsesc în C, dar care pot fi găsite în alte limbaje de programare se enumeră:

Un sistem automat de colectare a reziduurilor (de memorie) (engleză Garbage collection)

Clasele și obiectele (programarea orientată pe obiecte)

Un sistem avansat de tipuri de date

Programarea generică

Supraîncărcarea

Metaprogramarea

Suport nativ pentru programarea multifir (engleză multithreaded) și funcțiile de rețea

Procesarea listelor

Deși lista minusurilor limbajului C este destul de lungă, aceasta nu reprezintă un dezavantaj suficient de mare pentru inhiba utilizarea limbajului C în practică, deoarece permite ca noi compilatoare să poată fi scrise pe noi tipuri de platforme și pentru că permite programatorului să țină bine sub control programul pe care îl scrie. Acesta este unul din motivele care face ca un cod scris în C să fie mult mai eficient decât dacă ar fi scris în alte limbaje de programare. Numai un cod scris cu foarte mare grijă într-un limbaj de asamblare poate fi mai performant, deoarece are control integral asupra mașinii, dar performanța avansată a compilatoarelor, combinată cu complexitatea noilor tipuri de procesoare, a făcut ca limbajul C să fie preferat și să fie acceptat din ce în ce mai mult de programatori.

Tipuri de date

C are un sistem de tipuri de date similar cu cel al descendenților ALGOL, cum ar fi Pascal, dar totuși cu anumite diferențe. Cuprinde tipuri de date cum ar fi întregi de diferite dimensiuni, cu sau fără semn, numere în virgulă mobilă, enumerări (enum), structuri de date (struct) și uniuni(union).

Alocarea memoriei

Una din cele mai importante funcții ale unui limbaj de programare este ca acesta să furnizeze metode de management a memoriei și al obiectelor stocate în memorie. C furnizează trei metode distincte de alocare a memoriei pentru obiecte:

Alocarea statică a memoriei: adresele și dimensiunile obiectelor ce fac uz de alocarea statică a memoriei sunt fixate în momentul compilării și pot fi plasate într-o zonă de dimensiune fixă ce corespunde unei secțiuni din cadrul fișierului linkedidat final. Acest tip de alocare a memoriei se numește statică deoarece locația și dimensiunea lor nu variază pe durata de execuție a programului.

Alocarea automată a memoriei: obiectele temporare (variabilele locale declarate în cadrul unui bloc de cod) sunt stocate în cadrul de stivă asociat funcției apelate, iar spațiul alocat este automat eiberat și reutilizat după ce s-a părăsit blocul în care acestea au fost declarate.

Alocarea dinamică a memoriei: blocuri de memorie de orice dimensiune pot fi alocate într-o zonă de memorie numită heap prin intermediul funcțiilor malloc(), calloc() și realloc(). Aceste blocuri de memorie pot fi reutilizate după ce zona de memorie a fost eliberată prin apelul funcției free().

Variabilele alocate static au alocată locația lor de memorie și inițializată înainte ca funcția main să fie executată și nu sunt dealocate până când se termină execuția funcției main. Variabilele alocate static nu sunt reinițializate la fiecare apel al funcției în cadrul cărora au fost declarate. O variabilă alocată static are avantajul că își păstrează valoarea, chiar dacă funcțiile care accesează acea valoare nu mai sunt active.

Acolo unde este posibil, alocarea automată sau statică este preferată deoarece alocarea memoriei este coordonată de compilator, nemaifiind nevoie ca programatorul să aloce iar apoi să elibereze memoria – operație ce adesea generează erori. Totuși, multe structuri de date sunt variabile în dimensini și deoarece alocarea automată și cea statică trebuie să fie de dimensiune fixă în momentul compilării, sunt multe situații în care alocarea dinamică trebuie folosită. Un exemplu ar fi tablourile de dimensiuni variabile.

3.2.3 Framework-ul .NET

 Microsoft .NET este un software care conecteaza informatie, oameni, sisteme si dispozitive. Cuprinde clienti, servere si tool-uri de dezvoltare, si consta din:

.NET Framework 1.1 , folosit la construirea si rularea diferitelor tipuri de software, incluzand aplicatii Web-based, aplicatii client inteligente si servicii Web XML – componente care faciliteaza integrarea prin folosirea in comun a datelor si a functionalitatilor in retea prin protocoale standard, independente de platforma, cum ar fi XML (Extensible Markup Language), SOAP si HTTP.

Tool-uri de dezvoltare , cum ar fi Microsoft Visual Studio .NET 2003, care asigura un mediu de dezvoltare integrat (IDE) pentru a maximiza productivitatea dezvoltatorului cu .NET Framework.

Un set de servere , inclusiv Microsoft Windows Server 2003, Microsoft SQL Server si Microsoft BizTalk Server, care integreaza, ruleaza, opereaza si controleaza aplicatii Web-based.

Software de client , cum ar fi Windows XP, Windows CE si Microsoft Office XP, care ajuta dezvoltatorii sa ofere experienta semnificativa utilizatorilor despre familia de dispozitive si produse existente.

 .NET Framework este integral o componenta Windows pentru construirea si rularea urmatoarei generatii de aplicatii software si servicii Web. .NET Framework:

suporta peste 20 de limbaje de programare diferite

administreaza multe din instalatiile implicate in dezvoltarea de software

usureaza mai mult ca oricand construirea, amplasarea si administrarea de aplicatii sigure, robuste si cu performante ridicate. .NET Framework este compus din common language runtime si un set unificat de biblioteci de clase.

Clasele de baza oferă funcționalități standard, cum ar fi intrare/ieșire, manipularea stringurilor, managementul securității, comunicație în rețea, managementul firelor de execuție, managementul de text și diferite trăsături legate de design-ul interfeței utilizatorului. Clasele ADO.NET oferă dezvoltatorilor posibilitatea să interacționeze cu date în format XML, accesate prin interfețe OLE DB, ODBC, Oracle și SQL Server. Clasele XML oferă posibilitatea manipulării, căutării și translatărilor XML. Clasele ASP.NET suportă dezvoltarea aplicațiilor Web și a serviciilor Web. Clasele Windows Forms suporta dezvoltarea de aplicatii de tip desktop-based smart client. 
     Împreuna, bibliotecile de clase ofera o interfata comuna si consistenta de dezvoltare pentru toate limbajele suportate de .NET Framework.

 Posibilitatea de a folosi unul dintre multiplele limbaje ale .NET Framework ofera dezvoltatorilor posibilitatea de a folosi limbajul de programare care este cel mai indicat pentru un anumit task si sa combine limbajele in cadrul aceleiasi aplicatii. Componente scrise in diferite limbaje pot functiona transparent intre ele, fara a fi necesara munca suplimentara din partea dezvoltatorului. .NET Framework a fost anuntat ca suporta peste 20 de limbaje de programare comerciale si academice. 
     Design-ul de "racordare" libera bazat pe componente al .NET Framework minimizeaza cantitatea de cod pe care dezvoltatorii trebuie sa o rescrie si maximizeaza potentialul de reutilizare al codului.

 In momentul de fata, .NET suporta urmatoarele limbaje:

  C#

  VB.NET

  C++

  J#

Limbajele anterioare sunt Microsoft. Multe alte companii scriu compilatoare pentru alte limbaje folosind suport .NET.

3.2.3.1 Limbajul de programare C#

C# este un limbaj simplu, cu circa 80 de cuvinte cheie și 12 tipuri de date predefinite. El permite programarea structurată, modulară și orientată obiectual, conform perceptelor moderne ale programării profesionale.

Principiile de baza ale programării orientate pe obiecte (ÎNCAPSULARE, MOȘTENIRE, POLIMORFISM) sunt elemente fundamentale ale programării C#. În mare, limbajul moștenește sintaxa și principiile de programare din C++. Sunt o serie de tipuri noi de date sau funcțiuni diferite ale datelor din C++, iar în spiritul realizării unor secvențe de cod sigure (safe), unele funcțiuni au fost adăugate (de exemplu, interfețe și delegări), diversificate (tipul struct), modificate (tipul strîng) sau chiar eliminate (moștenirea multiplă și pointerii către funcții). Unele funcțiuni (cum ar fi accesul direct la memorie folosind pointeri) au fost păstrate, dar secvențele de cod corespunzătoare se consideră "nesigure".

Structura unui program C#

O aplicație C# este formată din una sau mai multe clase, grupate în spații de nume (namespaces). Este obligatoriu că doar una din aceste clase să conțină "un punct de intrare" și anume metodă (funcția) Main.
– Clasa (class), in termeni simplificati, reprezinta principalul element structural si de organizare in limbajele orientate spre obiecte, grupand date cat si functii care prelucreaza respectivele date.
– Spatiul de nume (Namespaces): din ratiuni practicem programele mari, sunt divizate in module, dezvoltate separat, de mai multe persoane. Din acest motiv, exista posibilitatea de a aparea identificatori cu acelasi nume. Pentru a evita erori furnizate din acest motiv, in 1995 limbajul C++ introduce notiunea si cuvantul cheie namespace. Fiecare multime de definitii dintr-o librarie sau program este grupata intr-un spatiu de nume, existand astfel posibilitatea de a avea intr-un program definitii cu nume identic, dar situate in alte spatii de nume.

3.2.3.2 Facilități de interfațare

Utilizarea suitei de software .NET Visual Studio 2010 în combinație cu limbajul de programare C# a oferit numeroase avantaje și facilități de interfatare a aplicației PC.

Conceptul de Windows Forms Application definește modulul de programare a interfeței grafice cu utilizatorul (API) și este inclus că parte a framework-ului .NET, furnizând acces la elementele de interfață Microsoft Windows într-o formă interactivă de tip drag and drop. Această unealtă generează în mod automat instrucțiunile grafice necesare elementelor de interfatare „forms” și „controls”, ușurând substanțial muncă programatorului. Totodată, sunt oferite facilități de poziționare a obiectelor în cadrul unui form și de scalare a acestora, fără a fi necesară o evidență strictă a măricei de pixeli.

3.2.4 Platforma Emgu.CV pentru procesare de imagine

Emgu CV-ul este o platforma de procesare de imagine „open source” care se mulează pe framework-ul .NET și care integrează și adaptează funcțiile de prelucrare complexă din celebra biblioteca Open CV. Astfel Emgu CV implementează funcționalități ale Open CV pentru limbaje de programare specifice .NET, cum ar fi C #, VB, VC + +, IronPython etc. Codul Emgu.CV poate fi compilat și în Mono IDE și rulează pe Windows, Linux, Mac OS X, iPhone, iPad și dispozitive Android.

OpenCV (Open Source Computer Vision) este o biblioteca de funcții de programare care au că principal scop procesarea computerizată de imagine în timp real. Open CV a fost dezvoltată de Intel Rusia în cadrul centrului de cercetare din Nijni Novgorod, iar în prezent platforma este deținută de către Willow Garage și Itseez. Statutul Open CV este deasemenea „open-source” ceea ce presupune că poate fi utilizată fără drepturi de licențiere. Întrucât a fost dezvoltată inițial de Intel, biblioteca are subrutine dedicate care sunt accelerate substanțial în situația în care rulează pe module harware Intel ce dispun de tehnologia Intel's Integrated Performance Primitives.

3.2.4.1 Detecție facială

Detecția facială ca proces computerizat definește o problematică de interes ridicat în contextul evolutiei tehnologice actuale, fiind o functie elementară, din ce in ce mai prezentă pe o serie de dispozitive numerice cu suport video integrat (ex: all-in-one PC, tableta, telefon mobil, camera captură foto/video etc.).

Detecția facială reprezintă un proces complex de prelucrare a imaginilor care se bazează pe modalități de extragere a informațiilor utilizând data mining. Acest proces implică parcurgerea pașilor specifici data mining (Figura 3.24).

Figura 3.24. Etape ale procesului data mining pentru detectie faciala

Problematică: Omul poate distinge o față umană ca parte compomentă a unei persoane. Așadar:

CORPUL OMENESC = CONTEXTUL

Problema care apare este detecția unei fețe umane în condițiile unei lipse de context și a existenței mai multor parametrii ce pot varia foarte usor precum luminozitate, nuanța pielii, particularităti (ochelari, păr facial, tunsoare).

Există mai multe modalități și abordări pentru extragerea fețelor umane din imagini bidimensionale. Orice metoda folosită pentru detecția facială se bazeaza pe un process de învatare de formă algoritmică. Stagiul de învațare variază de le o metodă la alta: laborios / simplist. O soluție intuitivă ar fi o abordare geometrică a modelului feței umane, adică proiectarea unei imagini pe un subspațiu cunoscut și stabilirea apartenenței respectivei imagini la acest subspațiu.

Algoritmul de detecție are nevoie de o mulțime de imagini pozitive (imagini de chipuri) și imagini negative (imagini fără fețe) pentru a instrui clasificatorul. Apoi trebuie extrase anumite carateristici din aceste imagini. Modalitatea studiată si implementată în lucrarea de fața este metoda „Viola & Jones”. Această metodă utilizează undinele Haar pentru definirea unei clase asociată feței. O undină Haar este un tip particular de undină ce include funcții cu reprezentare “pătratică” (rectangulară) care impreună formează o baza ortonormată. Fiecare caracteristică Haar este o singură valoare obținută prin scăderea sumei de pixeli unui dreptunghi alb din suma de pixeli unui dreptunghi negru corespunzator aceleiasi zone.

Pentru detecție facială se vor utiliza colecții de imagini existente deja în baze de date cu rol educativ puse la dispoziție pe internet. Pentru procesul de învatare și clustering au fost dezvoltați de-a lungul timpului o serie de algoritmi. Cele mai frecvente abordări sunt algoritmii generativi și discriminativi:

– un algoritm generativ modelează modul în care datele au fost generate, în scopul de a clasifica un semnal. Se pune întrebarea: bazat pe ipotezele de generare, ce categorie este cel mai probabil să genereze acest semnal?

– un algoritm discriminativ nu pune accent pe modul în care au fost generate datele, pur și simplu cataloghează un semnal dat (aparține sau nu unei anumite categorii).

Metoda V&J desemnează un algoritm discriminativ care integrează patru concepte cheie pentru desfășurarea procesului de detecție facială:

Utilizarea unor caracteristici simple rectangulare (caracteristici Haar)

Construcția unei imagini integrale pentru detecție rapidă a caracteristicilor

Procesul de tip “machine-learning” AdaBoost

Clasificator în cascadă pentru operare eficientă

Având la dispoziție baza de date de tip imagini continand fețe umane prima faza este cea de extragere a caracteristicilor care semnaleaza prezenta unei fete. O caracteristica Haar este o reprezentare bidimensională ce presupune ca o undă patratică să fie de forma unei perechi de deptunghiuri adiacente – unul deschis la culoare și unul închis la culoare (Figura 3.25).

Figura 3.25. Exemplu de caracteristici Haar

Combinațiile între dreptunghiurile utilizate pentru detecția vizuală a obiectelor nu sunt undine Haar reale ci sunt alese preferențial pentru a se preta task-urilor de recunoaștere vizuală. Așadar reprezentarea bidimensională prin perechi de dreptunghiuri definește o caracteristică haar.

Algoritmul de stabilire a existentei unei caracteristici Haar dupa conversia în grayscale a imaginii inițiale implică urmatorii pași:

1. Se face media valorilor “light” corespunzătoare unei zone de pixeli.

2. Se face media valorilor “dark” corespunzătoare aceleiasi zone de pixeli.

3. Se face diferența dintre cele două medii: Dif=Mvl-Mvd

4. Dacă Dif este peste un threshold setat în etapa de învatare => caracteristică Haar

Problema care apare în această fază este reprezentată de necesarul de putere de calcul pentru localizarea și extragerea caracteristicilor din imagini întrucât acestea se pot regăsi sub diferite forme și la scale diverse. Soluția V&J pentru procesarea a sute de imagini și pentru detecția caracteristicilor Haar la diferite scale este IMAGINEA INTEGRALĂ care prezintă următoarele caracteristici:

– valori integrale pentru fiecare pixel

– valoare integrală = suma val. pixel deasupra + suma val. pixel stânga

Modul de funcționare a imaginii integrale este prezentat algoritmic astfel:

se parcurge matricea de pixeli începând cu colțul stânga sus (Figura 3.26 – 1)

divizare matrice de pixeli în regiuni (Figura 3.26 -2)

în fiecare punct (x,y) se va regăsi suma pixelilor zonei asociate

Exemplu:

pct 1 => sum(A)

pct 2 => sum(A+B)

pct 3 => sum(A+C)

pct 4 => sum(A+B+C+D)

Figura 3.26. Conceptul de bază pentru imaginea integrală

Avantajul major al acestei metode se referă la faptul că pentru determinarea valorii medii a pixelilor dintr-o zona stabilită în prealabil se împarte aria zonei la valoarea din punctul (x;y). Astfel timpul de executie scade iar volumul de calcule este diminuat substanțial.

Fiecare caracteristică Haar este extrasă prin intermediul regiunilor nou formate în urma divizării preferențiale în blocuri rectangulare de pixeli. Dimensiunea standard a acestor regiuni este de 24×24 pixeli. Există patru tipuri principale de caracteristici (modele) (Figura 3.27):

Figura 3.27. Principalele tipuri de caracteristici Haar

Sunt încercate toate posibilitatile de scalare, rotire si poziționare a acestor caracteristici pe fiecare regiune, având ca rezultat pentru o regiune 24×24 pixeli ~ 160 000 combinații posibile!

Această estimare induce deci o problemă de necesitate acută a unor capacități mari de calcul. Pentru reducerea complexității procesului de extragere a caracteristicilor metoda V&J propune o versiune modificată a procesului de „machine learning” AdaBoost.

Pașii asociati funcționării algoritmului AdaBoost sunt descriși în secțiunea următoare:

Pasul 1: Se va selecta automat prima regiune asupra căreia va acționa procesul machine-learning (Figura 3.28).

Figura 3.28. Pasul 1 – Algoritmul AdaBoost

Pasul 2: Se clasifică datele existente. Sunt evidențiate erorile și sunt redimensionate regiunile în funcție ponderea erorilor. Se definește un clasificator inițial (Figura 3.29).

Figura 3.29. Pasul 2 – Algoritmul AdaBoost

Pasul 3: Se definește un al doilea clasificator prin repetarea primilor doi pași aplicați regiunii redimensionate (Figura 3.30).

Figura 3.30. Pasul 3 – Algoritmul AdaBoost

Pasul 4: Se repetă pașii 1 și 2 până la generarea unui număr de T clasificatori => situație clară a datelor (imaginii) (Figura 3.31).

ex: Daca T=3 => se generează un al treilea clasificator (ultimul)

Figura 3.31. Pasul 4 – Algoritmul AdaBoost

Pasul 5: Clasificatorul final rezultat în urma procesului de învățare este obținut prin suprapunerea tuturor clasificatoarelor parțiale (Figura 3.32).

Figura 3.32. Pasul 5 – Algoritmul AdaBoost

Având la bază principiul conversiei imaginii analizate în imagine integrală și utilizându-se versiunea modificată a algoritmului AdaBoost procesul de detecție facială poate fi implementat într-o formă optimala. Însă metoda V&J oferă încă o fază de optimizare a detecției: clasificatorul în cascadă.

Principiul de bază a algoritmului de detectare a feței Viola-Jones este de a scana prin intermediul detectorului detaliat anterior, de mai multe ori aceeași imagine, de fiecare dată cu o nouă dimensiune. Chiar dacă o imagine tcontine mai multe fete este evident că o cantitate excesiv de mare de sub-ferestre evaluate ar fi încă negative (non-fețe). Această abordare conduce la o formulare diferită a problemei: decat sa fie identificate fete mai bine se vor neglija non-fetele. Ideea din spatele acestei afirmații este faptul că este mai rapid să se neglijeze o non-față decât sa se găseasca un chip. In acest sens un detector alcătuit dintr-un singur (puternic) clasificator pare ineficient deoarece timpul de evaluare este constant, indiferent de intrare. De apare nevoia de un clasificator cascadă.

Clasificatorul cascadă este compus din faze fiecare conținând un clasificator puternic. Scopul fiecarei etape este de a determina dacă o sub-fereastra data poate contine o fata sau nu contine cu siguranta. Când o sub fereastră este clasificata drept lipsita de posibilitatea de a contine o fata etapa urmatoare de analiză este pasată. Pe de altă parte in cazul in care o sub-fereastra ar putea conține o imagine se trace la o noua etapa de analiză (rescalare) și procesul se va repeta în mod iterativ (Figura 3.33).

Figura 3.33. Principiu functionare clasificator in cascada

Prin integrarea acestui concept, metoda V&J alocă o capacitate de calcul majoră pentru regiunile care indică o probabilitate mare de prezența a unei fete crescând astfel eficiența procesului de detecție.

3.2.4.2 Detecție similarități

Detecția similarităților punctuale între două elemente grafice integrate în imagini distincte captate în condiții diferite și cu variatiuni puternice de luminozitate, zgomot, orientare etc. constituie o problematică de actualitate în sfera aplicatiior de tip Computer Vision. Imagistica în robotică defineste o arie complexa de prelucrare a imaginilor digitale, care se pliază din ce în ce mai puternic pe conceptul de “Computer Vision Analisys”. În aceste circumstante studiul similarităților între elemente grafice specifice sferei medicale se definește a fi un proces ce se dorește a fi puternic automatizat prin tehnici de analiză și prelucrare de imagine computerizată.

Procesul de căutare a unor corespondențe între puncte corespondente aflate în două imagini discrete distincte poate fi divizat în trei etape esențiale:

Detectarea “punctelor de interes” în fiecare dintre cele două imagini (colțuri, limite, intersecții etc) – cea mai importanta proprietate a unui punct de interes este repetabilitatea.

Definirea vecinătații unui punct de interes sub forma unui set de vectori de caracteristici, denumit in continuare descriptor. Un descriptor trebuie sa distinct la un anumit moment de timp, invariabil la zgomot etc.

Compararea vectorilor din descriptorii asociați celor două imagini ce se doresc comparate prin raportare la distanța Euclidiana. Dimensiunea unui descriptor afecteaza in mod direct timpul de comparatie, de unde se poate deduce cu usurinta ca pentru comparatii rapide se vor utiliza descriptori de dimensiuni reduse.

Analiza presupune focus pe descriptorii invarianți la scalare sau la rotație în acelasi plan întrucat la nivel experimental s-a demonstrat că acestia ofera un bun compromis intre complexitatea caracteristicilor de detectat si robustete in cazul celor mai frecvente deformari de imagine.

Detecția punctelor de interes

Abordarea propusă pentru detecția punctelor de interes are la bază ideea de aproximare bazată pe matricea Hessiană, care presupune utilizarea conceptului de imagine integrală, concept specific metodei Viola&Jones, si care are ca efect reducerea drastica a timpului de calcul.

Soluția V&J pentru procesarea a sute de imagini pentru detectia caracteristicilor la diferite scale este imaginea integrală, care presupune definirea unei imagini I in punctul X = (x; y), punct care să reprezinte suma tuturor pixelilor în imaginea I (Figura 3.34).

Modul de funcționare a imaginii integrale este prezentat algoritmic astfel:

se parcurge matricea de pixeli începand cu colțul stanga sus (Figura 3.34 – 1)

divizare matrice de pixeli în regiuni (Figura 3.34 -2)

în fiecare punct (x,y) se va regăsi suma pixelilor zonei asociate

Exemplu:

pct 1 => sum(A)

pct 2 => sum(A+B)

pct 3 => sum(A+C)

pct 4 => sum(A+B+C+D)

Figura 3.34. Conceptul de bază pentru imaginea integrală

Avantajul major constă în faptul că pentru determinarea valorii medii a pixelilor dintr-o anumită zonă se împarte aria zonei la valoarea din punctul de coordonate (X,Y) desemnat de colțul dreapta-jos al zonei în cauză (Figura 3.35).

Figura 3.35. Calcularea valorii medii pentru o regiune

Utilizând imaginea integrală este nevoie de efectuarea a numai trei operații de adunare/scadere și de patru cicluri de acces la memorie pentru calcularea intensităților din interiorul unei zone rectangulare internă unei matrice, avaâd orice dimensiune.

Pe scurt este de luat în calcul faptul că o imagine integrală prezintă următoarele caracteristici:

– valori integrale pentru fiecare pixel

– valoare integrală = suma val. pixel deasupra + suma val. pixel stânga

Odată ce imaginea regăsită în sistemul de calcul sub forma unei matrici cu dimensiune specificată având ca elemente valori cuprinse intre 0 si 255 (reprezentare pe 8 biti) este convertită in imagine integrala timpul de calcul pentru prelucrari ulterioare este independent de marimea sa, ipoteza extrem de importanta pentru algoritmul curent intrucat acesta presupune aplicarea unor filtre de dimensiuni mari.

Operațiile de filtrare (box filtering) utilizează de cele mai multe ori maști care afectează vecinatatea unui pixel de referință. Altfel formulat, o masca de coeficienti este centrata intr-un pixel. Coeficientii unei masti sunt inmultiti cu valorile pixelilor din vecinatatea pixelului referinta si rezultatele sunt sumate. Rezultatul este aplicat pixelului referinta (determinat prin pozitie – coordonate x, y) si astfel se obtine imaginea prelucrata (Figura 3.36).

Figura 3.36. Exemplu de aplicare a unei măști pe imagine

Detectorul punctelor de interes se bazează pe matricea Hessiană din cauza performanțelor sale bune în precizie. Mai precis, se detecteaza initial structuri specifice în locatii în care factorul determinant este maxim. Dandu-se un punct X=(x;y) asociat unei imagini integrale I, matricea Hessiana H este de forma:

unde σ este factorul de scalare iar Lxx, Lxy, Lyy reprezintă convoluția între derivata gaussiană de ordin 2 și imaginea I în punctul X (Lxx) și similaritățile acesteia Lxy si Lyy.

O altă abordare, notând derivatele pentru punctul i0 cu I(i)xx si respentiv I(i)xy:

unde ω(t) este kernelul Gaussian. Această ecuație sugerează integrarea valorilor derivate în vecinatatea V a pixelului curent. Fiecare valoare a vecinilor este inmultita cu o valoare care scade pe masura ce distanta creste. Legea scaderii este de tip Gaussian intrucat ω(t) este Gaussianul centrat in i0.

Conform observațiilor empirice, dacă se utilizează exclusiv derivatele, și pixelul este parte dintr-o structură liniară (margine, contur etc.), se va obține un răspuns cu puternic caracter informativ. Pe de altă parte, dacă pixelul se află la un colț (o intersecție a două muchii) răspunsul la derivate se va anula reciproc.

Gaussienii (filtrarea Gaussiana) oferă o soluție optimală pentru analiza scala-spațiu dar de cele mai multe ori necesită discretizare și decupare ceea ce rezulta în pierderea informației la rotirea imaginii. Din acest motiv detectorii bazați pe matricea Hessiana sunt mai potriviți pentru aplicații care presupun invarianța la rotire și respectiv la scalare. După cum este sugerat în figura următoare performantele rezultate prin utilizarea matricei Hessiane sunt comparabile sau de cele mai multe ori mai bune decat cele rezultate prin urilizarea gaussienilor (Figura 3.37).

Figura 3.37. Comparație între filtre Gaussiene (stânga) și filtre integrate prin matricea Hessiană

Se poate afirma că matricea Hessiană este capabilă să ofere informații despre o structură locală într-o vecinătate fără să existe efectul de anulare reciprocă a răspunsului. Însă pentru rezultate conforme este necesară integrarea. Așadar matricea Hessiană înmagazinează informația despre vecinătatea unui pixel.

Revenind la noțiunea de “punct de interes”, pentru o mai bună intelegere a noțiunii, se poate imagina următorul scenariu drept analogie: un individ este teleportat intr-un oras strain, fara nici un fel de dispozitiv de localizare dar avand o harta buna. Daca locatia individului este la mijocul unei strazi, posibilitatea de a localiza strada pe harta exista dar este greu de stabilit (scala) si orientarea acesteia (rotatie in raport cu un sistem geografic). Daca locatia individului este intr-o intersectie se poate puncta cu mai mare usurinta pozitia pe harta. Asadar in cazul compararii a doua imagini, trebuiesc detectati acei pixeli care sunt unic descrisi in context si astfel sunt definite punctele de interes. Experimental s-a constatat ca punctele definind colturi ale obiectelor in imagini, nu isi schimba semnificativ “angulatia” la scalarea, rotirea, deformarea imaginii (=> transformate afine).

Este de remarcat că anumite puncte in imagine permit identificarea lor unica. De exemplu se poate imagina că un pointer indică faptul că vecinatatea V a unui pixel este o linie. Exceptând orientarea liniei, nu se poate deduce nimic altceva din respectiva vecinătate. Însă daca V este un colț, intersecție de linii etc, se pot deduce atât orientarile liniilor existente, angulația etc.

Algoritmic, detectorul de puncte de interes se aplică astfel:

Se scanează imaginea în formă matriceală și se calculează matricea Hessiană (cu o frecvență specificată de utilizator – calcul pt fiecare pixel, calcul la fiecare n pixeli etc.)

Se calculează determinantul matricei H

Se vor selecta punctele care au det(H) > val unde val reprezintă coeficientul (threshold-ul) de unicitate și este stabilit de utilizator.

Punctele de interes trebuie gasite la scală diferită întrucat de obicei comparația se realizează între imagini privite la scală diferită. Scalarea se implementează de cele mai multe ori sub forma unei "piramide de imagini". Imaginile sunt in mod repetitiv clarificate utilizând prelucrari Gaussiene si sub-esantionate pentru a atinge un nivel mai inalt al piramidei.

Prin utilizarea filtrelor și a imaginii integrale, nu este necesară o abordare iterativă de aplicare a aceluiași filtru pe rezultatul unei filtrari anterioare, ci se poate aplica un singur filtru direct pe imaginea initiala, putandu-se beneficia de o abordare de calcul paralel. Asadar, scalarea spatiului se poate analiza prin cresterea in scala a filtrului, metoda mult mai performanta decat reducerea iterativa a imaginii pana la dimensiunea vizata (Figura 3.38).

Figura 3.38. Principiu de aplicare a filtrelor la modificarea scalei

Spațiul de scalare este divizat în octave. O octavă reprezintă o serie de hărți de răspuns la filtrare obținute prin convoluție între o imagine aflată la o dimensiune constantă și un filtru de dimensiune incrementată crescător. În total o octavă include un factor de scalare egal cu 2. Fiecare octava este subdivizata intr-un numar constant de nivele de scalare. Datorita naturii discrete a imaginii integrale diferenta minima intre doua nivele de scalare consecutive depinde de lungimea l0 a lobului pozitiv/negativ a derivatei partiale de ordinul doi in directia de derivare (x sau y) care desemneaza o treime din dimensiunea filtrului. De exemplu pentru un filtru 9 x 9 lungimea l0 este 3.

Figura 3.39. Exemplu de scalare a filtrelor

În figura de mai sus (Fig. 6) sunt ilustrate filtrele Dyy (sus) si Dxy (jos) la doua nivele de scalare succesive (9 x 9 si 15 x 15). Lungimea lobului de culoare închisa trebuie incrementată de un numar de pixeli care sa garanteze existența unui pixel central (sus).

Construcția unui spatiu de scalare porneste de la un filtru 9 x 9 care calculează raspunsul unei imagini la cea mai mică scală și apoi procedura se repetă pentru dimesiunile de 15 x 15, 21 x 21, 27 x 27.

Descriptorul specific algoritmului SURF analizează intensitatea conținutului din jurul unui potetențial punct de interes și variantele pe care acesta le poate adopta. Altfel formulat, se detectează caracteristicile Haar. Ulterior, prin raportarea la orientarea acestor caracteristici si a regiunii circulare aferentă punctului de interes se traseaza o regiune patratica din care este extras un descriptor.

Fiecare caracteristică este extrasă în raport cu un punct de interes stabilit în faza anterioară. Există 4 tipuri principale de caracteristici (modele):

Figura 3.40. Tipuri principale de caracteristici (modele)

Uneori este necesară o faza de scalare care implică definirea unui spațiu de scalare care pornește cu un filtru de 9 X 9 pixeli (per celulă) și care crește ulterior primind valorile de 15 X 15 pixeli, 21 X 21 pixeli si 27 X 27 pixeli. Sunt încercate toate posibilitățile de scalare, rotire și poziționare a acestor patru modele de caracteristici pe fiecare regiune.

Pentru integrarea conceptului de invarianță la rotație se identifică posibilitațile de reproducere la orientare ale punctului de interes. Pentru aceasta se calculează răspunsul la undinele Haar în directie x si y pe o rază de vecinătate prestabilită (de obicei 6s, unde s este scala la care punctul de interes a fost găsit).

Figura 3.41. Exemplu pentru determinarea

orientării unei caracteristici

Dupa aplicarea undinei si calcularea răspunsului, acesta este reprezentat ca puncte în spațiu cu coordonatele: intensitatea raspunsului pe orizontala (axa x – abscisa) si intensitatea raspunsului pe verticala (axa y-ordonata). Deternimarea orientarii se va putea stabili simplist prin realizarea unei sume a raspunsului pe un arc de cerc cu deschidere π/ 3 (Fig. 8). Sumele vor fi stocate intr-un vector de orientare. Cel mai lung vector din cadrul va desemna orientarea punctului de interes. Alegerea cadrelor este o problema importanta intrucat alegand cadre cu dimensiuni mult prea mici afecteaza precizia stabilirii orientării iar alegand cadre cu dimensiuni prea mari determina lungimi mari ale vectorilor de orientare care pot deveni neconcludente.

Pentru extragerea unui descriptor primul pas constă în construirea unei regiuni pătratice în jurul unui punct de interes și cu orientarea stabilită conform principiului mentionat anterior (Figura 3.42).

Figura 3.42. Exemplu construcție regiune pătratică cu orientare stabilită

Fiecare regiune este ulterior imparțită în 4 x 4 subregiuni pătratice. Pentru fiecare subregiune se calculează răspunsul la undine Haar. Din motive de simplificare dx constituie răspunsul undinelor Haar pe orizontala iar dy răspunsul undinelor Haar pe verticala. Direcțiile "vertical" si "orizontal" sunt stabilite în raport cu orientarea punctului de interes stabilită anterior. După obținerea răspunsurilor la undinele Haar dx si dy, acestea sunt sumate pentru fiecare regiune în parte și sunt constituite primele date de intrare din vectorul de caracteristici. Pentru obtinerea informatiilor de pozarizare si de schimbari ale intensitarii se mai extrag si sumele modulelor dx si dy. Fiecare subregiune va dispune astfel de un vector care va evidenția structura sa (Figura 3.43):

Figura 3.43. Structura unei subregiuni caracterizată de vectorul v

Răspunsul la undinele Haar este invariant la interferențele de lumină (offset). Invarianța la contrast este obținută prin transformarea descriptorului intr-un vector unitar.

Figura 3.44. Exemple de imagini si mărimile caracteristice asociate

Mărimile specifice unui descriptor al unei subregiuni prezintă natura unui pattern (Figura 3.44). De exemplu în prima ilustrare (stânga) este prezentată o regiune omogenă și toate valorile sunt relativ mici, în cea de-a doua ilustrare (centru) suma dupa modulul dx este mare sugerand ca există o caracteristică Haar vericala cu schimbare de intensitate, iar restul valorilor raman mici, iar in cea de-a treia ilustrare (dreapta) se poate observa ca atat suma valorilor raspunsului undinelor Haar cat si suma modulelor acestuia au valori mari sugerand ca exista schimbare de intensitate dar si prezența de caracteristică Haar orizontală.

Pentru detecția rapidă a similarităților este utilizată notiunea de urmă (trace) a matricei Hessiene. De obicei un punct de interes se regăseste la intersecția dintre structuri de tip bi-lob (alternanta de contrast). Alternanta de signatura desemneaza structuri di-lob deschise pe background inchis si invers. În aceasta faza nu mai sunt implicate resurse de calcul substantiale ci doar comparatii simple intre caracteristici (Figura 3.45).

Figura 3.45. Comparații în structurile bi-lob

3.2.4.3 Detecție siluete

Detecția siluetelor umane a fost și rămane un subiect foarte puternic abordat în sfera „computer vision” datorită multitudinii de aplicații în care poate fi integrată. De-a lungul timpului au fost abordate și implementate mai multe metode de prelucrare grafică pentru identificarea siluetelor umane in context variabil. Lucrarea de față prezintă abordarea HOG (Histogram of Oriented Gradients).

Histogram of Oriented Gradients (HOG) desemnează descriptori de caracteristici folosiți în „computer vision” și de procesare de imagini în special pentru detecția obiectelor. Aceasta tehnică numără aparițiile similare de orientare a gradientului în regiuni localizate ale unei imagini. Această metodă este similară cu cea a or histogramelor de orientare a contururilor, cea a detectiei caracteristicilor prin intermediul invariantilor dar diferă prin faptul că totul este calculat pe o grilă densa de celule distanțate uniform și folosește suprapunerea contrastului local normalizat pentru acuratețe îmbunătățită.

Navneet Dalal si Bill Triggs, doi cercetători de la Institutul National Francez de Cercetare in Informatica si Control (INRIA), au descris pentru prima metoda HOG în lucrarea lor CVPR iunie 2005. În această lucrare s-au concentrat asupra algoritmului de detectie a pietonilor în imagini statice, si tot de atunci au extins testele si pentru detectia factorului uman în filme și clipuri video, precum și detectia unei varietatati de animale și vehicule comune în imagini statice.

Ideea de bază în cazul metodei HOG este că aspectul local al unui obiect și forma sa într-o imagine pot fi descrise prin distribuția gradientilor de intensitate sau a direcțiilor contururilor. Implementarea acestei metode poate fi realizată prin împărțirea imaginii în regiuni mici interconectate, numite celule, și pentru fiecare celulă are loc compilarea histogramei de gradient al direcțiilor sau orientările contururilor pentru pixelii din interiorul celulei. Combinația dintre aceste histograme reprezinta apoi un descriptor. Pentru o precizie îmbunătățită, histogramele locale pot fi normalizate la nivel de contrast prin calcularea unei măsuri a intensității pe o regiune mai mare a imaginii, numit bloc, si apoi folosind această valoare pentru a normaliza toate celulele în interiorul blocului. Aceasta normalizare duce la o mai bună invarianta la schimbările de iluminare sau umbrire.

Generic, detectecția siluetelor utilizând HOG folosește principiul „ferestrei glisante”, care este mutată succesiv pe suprafața întregii imagini. La fiecare poziție a ferestrei detector, este calculat un descriptor HOG. Acest descriptor este apoi comparat cu un clasificator (SVM) obtinut prin invatare (training pe un se de imagini), care decide daca exista sau nu siluete in cadru.

Descriptorul HOG menține câteva avantaje cheie față de alte metode ce utilizeaza descriptori. Având în vedere că descriptorul HOG funcționează pe celule localizate, metoda susține invarianta la transformari geometrice și fotometrice, cu excepția orientarii obiectului. Astfel de modificări ar apărea numai în regiunile spațiale mari. Mai mult decât atât, așa cum a descoperit Dalal si Triggs, eșantionarea grosier spațială, eșantionarea fina in orientare, și puternica normalizare fotometrică locală permite identificarea siluetelor umane in contitii de miscare continua a acestora atât timp cât acestea mențin o poziție aproximativ verticală. Astfel, descriptorul HOG este foarte potrivit pentru detectarea omului în imagini.

Implementarea algoritmului HOG

Calcularea gradientului

Primul pas, de obicei comun pentru metodele de procesare de imagine care presupun detectori de caracteristici, este faza de preprocesare pentru asigurarea unor valori normalizate pentru culoare și luminozitate. În metoda de fața acest pas este omis însă dar este înlocuit cu calculul gradientului. Cea mai comună metodă pentru aceasta este de a aplica o masca discret derivativa, unidimensional centrata pe una sau pe ambele directii (x si y). Aceasta metoda presupune filtrarea culorii sau intensitati unei imagini cu ajutorul urmatoarelor transformari (kerneli):

Pentru o mai bună înțelegere a conceptului, modul de funcționare va fi exemplificat. Așadar, s-a considerat un detector HOG care folosește o fereastră de detectie cu dimensiunea de 64 pixeli lățime si 128 pixeli înaltime. În figura 3.46 sunt câteva dintre imaginile originale folosite pentru a instrui detectorur, trunchiate pentru incadrare în fereastra de 64 × 128.

Figura 3.46. Imagini de trainig pentru detectorul HOG

Pentru a calcula descriptorul HOG, se va considera o celulă de 8 × 8 în cadrul ferestrei de detectare. În figura 3.47 este evidențiată celula de lucru, la nivelul căreia se vor efectua calculele specifice algoritmului, în raport cu imaginea scanată:

Figura 3.47. Celula de lucru în raport cu imaginea sursă

Pentru fiecare celulă se calculeaza gradientul. Un gradient poate fi calculat pentru fiecare pixel de imagine. Această mărime este pur și simplu o măsură a modificării valorilor pixelilor de-a lungul directiei x și respectiv y. In figura 3.48 se presupune ca se doreste calcularea gradientului pixelului marcat cu rosu:

Figura 3.48. Exemplu calcul gradient pixel – axa x

Aceasta este o imagine în tonuri de gri, astfel încât valorile pixelilor variază doar de la 0 la 255 (0 este negru, 255 este alb). Valorile pixelilor la stânga și la dreapta pixelului vizat sunt marcate cu 56 și respectiv 94. Se face diferenta valorii intre valoarea din dreapta si valoarea din stanga si rezultatul poarta numele de rata a schimbarii pe directia x (94 – 56 = 38). Parcurgerea imaginii se poate face si invers (valoarea din stanga – valoarea din dreapta) chiar daca rezultatul este negativ, insa procesarea trebuie sa fie consecventa pentru intreaga imagine.

Se poate face același lucru pentru pixelii de sus și respectiv de jos pentru a obține rata de schimbare pe directia y (Figura 3.49) (93 – 55 = 38):

Figura 3.49. Exemplu calcul gradient pixel – axa x si axa y

Punând aceste două valori împreună, se obtine gradientul (vectorul gradient):

Putem folosi, de asemenea, ecuațiile pentru modul (magnitude) și unghi specifice vectorului:

În acest moment vectorul gradient poate fi trasat. Este important de observat faptul că acest vector are o proprietate specială, și anume faptul că este perpendicular pe contur (Figura 3.50).

Figura 3.50. Reprezentarea vectorului gradient

Marcarea regiunilor în funcție de orientare

A doua etapă de calcul presupune crearea histogramelor în fiecare celulă. Fiecare pixel din interiorul celulei constituie un vot ponderat pentru un canal din histogramă. Celulele pot fi de formă rectangulară sau în formă radială, iar canalele histogramei sunt distribuite uniform intre 0 si 180 de grade intre 0 si 360 de grade.

Exemplificând, după obținerea vectorilor gradient (64 la numar pentru scenariul propus anterior cu celula 8×8 pixeli) se plasează într-o histogramă de noua segmente. Histograma variază de la 0 la 180 de grade, astfel încât există 20 de grade pe segment (Figura 3.51):

Figura 3.51. Reprezentarea ponderilor gradienților în histogramă

Pentru fiecare vector gradient, contribuția la histogramă este dată de modulul vectorului (amploarea) (deci gradienți puternici au un impact mai mare asupra histogramei). Contribuția la histogramă, în situația în care valoarea angulației este diferită fața de pragurile de histogramă, este împarțită între segmentele învecinate. Astfel, de exemplu, dacă un vector gradient de are un unghi de 85 de grade, apoi se adaugă 1/4 din amploarea acestuia la segmentul centrat la 70 de grade, și 3/4 din amploarea acestuia la segmentul centrat la 90.

Este important de știut de ce se utilizeaza plasarea valorilor în histogramă și nu se practică utilizarea lor ca atare. Histograma de gradient este o formă de "cuantificare", având ca efect în cazul de fața reducerea numărului de valori de la 64 vectori cu cate 2 componente fiecare la un șir de doar 9 valori – marimea fiecarui segment. Aceasta măsură reprezintă o formă de optimizare de calcul si de generalizare a continutului celulei de 8×8 pixeli, cu efecte puternice asupra performanțelor clasificatorului. La o modificare subtilă în cadrul celulei care ar presupune modificări minore ale poziției vectorilor in cadrul celulei si respectiv modificari ale angulatiei acestora, distributia histogramei s-ar modifica subtil.

Normalizarea vectorilor gradient

Următorul pas în calcul descriptorilor este de a normaliza histogramele. Prin adaugarea sau scăderea unei valori fixe ​​a luminozitatii fiecărui pixel din imagine se va obtine acelasi vector gradient asociat unui pixel. Prin normalizarea vectorilor gradient acestia pot deveni totodata si invarianti la inmultirea pixelilor cu valori fixe (Figura 3.52).

Figura 3.52. Invarianta gradientului la adunare / inmultire a pixelilor cu valori fixe

Se observă modul în care a treia imagine afișează o creștere în contrast. Efectul multiplicareii este că pixeli luminoasi a devenit mult mai luminosi în timp ce de pixeli de culoare închisă a devenit doar un pic mai luminosi, crescând astfel contrastul dintre părțile luminate și părțile întunecate ale imaginii.

În ceea ce privește modul de evoluție al valorilor numerice specifice aceastea evolueaza conform calculului de mai jos:

Vectorii gradient sunt echivalenți în prima și a doua imagine, dar în a treia, modulul vectorului gradient a crescut cu un factor de 1,5. Prin impartirea tuturor celor trei vectori la modulul lor, se vor obtine aceleasi valori: [0.71 0.71]. Deci, din exemplul de mai sus, se constata că prin împărțirea vectorilor de gradient de modulul lor, se poate induce invarianța la schimbări în contrast.

Împartirea unui vecor la modulul sa poarta numele de normalizare. Normalizarea nu afecteaza oriectarea sa ci doar modulul.

Normalizarea blocurilor

Valoarea în fiecare din cele nouă segmente în histograma se bazează pe modulurile gradienților din celula 8 x 8 pixeli pentru care s-au calculat. Dacă fiecare pixel dintr-o celulă se înmulțește cu 1,5, de exemplu, atunci am văzut mai sus că modulul tuturor gradientilor in celula va fi mărită cu un factor de 1,5. Acest lucru înseamnă că valoarea pentru fiecare segment al histogramei va creste cu 1,5 ori. Prin normalizarea histogramei, se induce deci invarianta la iluminare.

O abordare mai bună decât a normaliza fiecare histogramă individual este de a grupa celulele în blocuri și a normaliza toate histograme din bloc. Blocurile utilizate de Dalal si Triggs a constat din 2 pe 2 celule. Blocurile au "50% suprapunere", care este cel mai bine descrisa prin figura 3.53.

Figura 3.53. Modalitatea de grupare a celulelor in blocuri

Normalizarea blocurilor se realizează prin concatenarea histogramelor celor patru celule din cadrul blocului într-un vector cu 36 componente (4 histograme x 9 segmente pe histogramă). Acest vector este impartit la modulul propriu pentru normalizare.

Efectul suprapunerilor celulelor in bloc este că fiecare celulă va apărea de mai multe ori în descriptorul final, normalizat de seturi diferite de celulele vecine. (celulele colț apar o dată, celelalte celule de contur vor apărea de două ori fiecare, iar celulele interioare apar patru ori fiecare).

Clasificatorul SVM

Ultimul pas în recunoașterea obiectelor, folosind HOG este să se integreze descriptorii în anumite sisteme de recunoaștere bazate pe învățarea supervizată. „Support Vector Machine Classifier” este un clasificator binar care caută un hiperplan drept funcție de decizie. Odată instruit (trained) si cu imagini care conțin un obiect special, clasificatorul SVM poate lua decizii în ceea ce privește prezența unui obiect, cum ar fi o ființă umană în imagini.

3.2.4.4 Detecție caractere

Recunoașterea automata a numerelor de înmatriculare (ANPR – abreviat în engleză) este un sistem de supraveghere în masă, care surprinde imaginea vehiculelor și recunoaște numărul lor de inmatriculare. ANPR poate fi oferi asistenta în detectarea vehiculelor furate. Detectarea vehiculelor furate se poate face într-un mod eficient prin utilizarea sistemelor ANPR situate în autostrăzi. Studiul prezintă o metodă de recunoaștere în care imaginea numarului de inmatriculare auto este obținută prin camerele digitale și imaginea este procesata pentru a obține caracterele numarului de inmatriculare (string) pentru procesari ulterioare. Zona plăcuței de înmatriculare este localizata initial prin algoritmi care presupun binarizare, extragerea mastii corespunzatoare numarului si extragerea contururilor. Apoi se va prezenta metoda de extracție a caracterelor (OCR) din zona stabilită anterior.

Marea majoritate a algoritmilor de localizare pentru plăcuțe de înmatriculare îmbina mai multe proceduri secvențiale de prelucrare de imagine, rezultând în timpi de calcul mari. Acest inconvenient poate fi redus prin aplicarea unor principii de filtrare algoritmica mai simple si a unui numar mai mic de secvente de filtrare. Rezultatele sunt foarte dependente de calitatea imaginii, deoarece fiabilitatea procedurilor variază puternic în cazul imaginilor complexe, cu zgomot pronuntat sau care conțin o mulțime de detalii . In majoritatea cazurilor performanta algoritmilor influențează relativ rata de succes a procesului de detecție iar solutia de baza este reglarea precisă a camerei sau a elementului de captura. Acest lucru înseamnă că mașina trebuie să fie fotografiata într-o maniera in care mediul (contextul) este exclus cat de mult posibil și dimensiunea numărului de inmatriculare este cat mai mare cu putință . Ajustare a dimensiunii este deosebit de dificilă în cazul de mașinilor rapide ,iar momentul optim de expunere poate fi cu greu stabilit.

Cele mai populare metode de detecție a numerelor de înmatriculare au la baza localizarea bazată pe contur: algoritmii se bazează pe observația că numărul de inmatriculare, de obicei, apare in zone caracterizate de contrast puternic (negru / alb sau negru / galben ).

Pentru implementarea unei aplicații care sa fie capabilă să furnizeze un șir de caractere (string) asociate unui numar de înmatriculare detectat și recunoscut în manieră optica este necesară parcurgerea unor etape specifice:

– capturarea unei imagini statice sau a unui flux video de la un dispozitiv de captură adecvat (cameră video) (Figura 3.54).

Figura 3.54. Imaginea capturata initial

– conversia imaginii în format grayscale – tonuri de gri (Figura 3.55).

Figura 3.55. Imaginea in tonuri de gri

– exragerea contururilor în vederea localizării numărului de înmatriculare

– binarizarea imaginii dupa un threshold stabilit

– extragerea dreptunghiului asociat ariei identificate prin raționamentul anterior precum și prin efectuarea unor validări cu privire la formatul și la rotatia acestuia în cadru

– rularea unui motor OCR pentru identificarea caracterelor din dreptunghiul binarizat

Soluția tehnică pentru implementarea algoritmilor de procesare de imagine este biblioteca de clase dedicată EmguCV (OpenCV) care oferă funcții suport pentru implementarea algoritmului de recunoaștere a caracterelor OCR prin integrarea conceptului de segmentare.

Implementarea algoritmului de localizare număr înmatriculare și OCR

Capturare imagine, conversie imagine în grayscale și binarizare ca etape de preprocesare

Achiziția de imagine este procesul de obținere a unei imagini de la elementul fizic de captură. Aceasta este primul pas de orice sistem bazat pe conceptul computer vision. Scopul este de a obține o imagine frontală a vehiculelor care conțin numere de înmatriculare. Aplicația dezvoltată este capabilă să opereze pe imagini statice dar și pe flux video. Schema bloc a algoritmului de captură este evidențiată mai jos (Figura 3.56):

Figura 3.56. Schema bloc a algoritmului de captură

Imaginile în niveluri de gri conțin o cantitate enormă de date. O mare parte din acestea sunt irelevante. În general detectarea contururilor implică trei etape: de filtrare, de diferențiere și de detectare. În prima etapă, imaginea este trecuta printr-un filtru pentru a elimina zgomotul. Cea mai importanta caracteristica a etapei de diferențiere este evidentierea zonelor in care au loc schimbari pronuntate de intensitate. Contururile caracterizeara obiectele si limitele și sunt utile pentru segmentare (proces de partiționare a imaginii digitale in segmente). Contururile dintr-o imagine pot fi detectate folosind o convoluție periodică operatie integrata in asa numita metoda Canny.

Imaginile binare (binarizate) sunt reprezentari numerice matriceale cu valori binare ale pixelilor (doua valori). Prin threshold se intelege pragul de conversie a imaginii în tonuri de gri în imagine binara (pixeli care conțin pixeli alb-negru). Imaginile binare se pot obține din imagini in niveluri de gri sau din imagini color prin setarea unui threshold pe fiecare canal. In această lucrare am considerat imaginea de nivel de gri. Funcția caracteristică de binarizare este:

b (x, y) = 1 dacă g (x, y) < T

= 0 dacă g (x, y)> = T

Algoritmul propus pentru a converti imaginea în tonuri de gri în imagine binara este explicat în figura de mai jos (Figura 3.57):

Figura 3.57. Schema bloc a algoritmului de conversie în grayscale

Extragerea contururilor în vederea localizării numărului de înmatriculare și filtrarea regiunilor candidate

Imaginea originală este convertită în imagine în tonuri de gri, care oferă contrast ridicat. Pentru localizarea numărului de înmatriculare trebuie identificată coordonata orizontală a dreptunghiului care il încadrează. O caracteristică a numerelor de înmatriculare este că literele și cifrele sunt plasate în același rând (adică la niveluri verticale identice) care rezultă în schimbări frecvente în intensitatea orizontală. Astfel este importantă executarea unei prime scanări a imaginii pentru identificarea poziției rândului caracterelor din număr pe baza analizei schimbărilor de intensitate orizontala (Figura 3.58).

Figura 3.58. Graficul de prezență a variațiunilor de intensitate orizontală în imagine

Algoritmul determină mai întâi gradul de variație intensitate pentru fiecare rând , iar la al doilea pas selectează rândurile adiacente care prezintă cele mai mari schimbări. Plăcutele de înmatriculare se regasesc foarte probabil în aceste rânduri. Poziția orizontală a plăcii numărului auto trebuie să fie determinata în faza urmatoare avand deja o localizare la nivel vertical. Cele mai mari variatii apar la litere ( litere negre pe fond alb ). Prin urmare, se urmareste alternanta cea mai semnificativă de contrast din randul deja identificat (Figura 3.59).

Figura 3.59. Graficul de prezență a variațiunilor de intensitate verticală în imagine pe rândul selectat

Dupa o parcurgere prealabilă a pașilor specifici algoritmului de localizare bazat pe studiul schimbărilor de intensitate vor fi determinate mai multe zone potențiale asociate numerelor de înmatriculare numite regiuni candidate (Figura 3.60).

Figura 3.60. Regiuni candidate pentru numărul de înmatriculare

O problemă frecventă ce apare în această abordare bazată pe variațiuni puternice de contrast este că zonele identificate apropiate una de alta sunt unite (Figura 3.61). Pe de altă parte placuța de înmatriculare este caracterizată și de alte trăsături cheie precum forma rectangulară, dimensiuea și formatul aproximativ standard pentru toate țarile etc. Așadar pentru filtrarea regiunilor candidate se aplică uzual alte două metode de recunoaștere: extragerea ariei minime rectangulare ale cărei limite sunt punctele rezultate din procesele anterioare de localizare și analiza raportului între lățime si inaltime ale ariilor extrase. Procesul de extragere a ariei minime rectangulare presupune identificarea și unirea celor patru extremități ale regiunilor candidate. În prima fază are loc identificarea celor patru colțuri: daca are loc cu succes sunt unite punctele asociate acestora prin linii drepte și se examinează unghiul format care trebuie sa se regasească între anumte valori luând în calcul ca o regiune nominal rectangulară transpusa in plan devine trapezoidala, iar dacă nu are loc cu succes regiunea candidată este eliminată și se trece la următoarea examinare. Analiza matematică a raporturilor dimensiunilor se bazează pe faptul că raportul dintre latura orizontală și cea vericala ale unei plăcute de înmatriculare se regăsește într-o plajă de valori aprioric stabilite.

Figura 3.61. Fenomenul de alipire a zonelor cu variatiuni puternice de contrast

După finalizarea filtrarii regiunilor candidate este ideal sa rămană o singură zona de interes, luând în calcul faptul că sistemul studiat este limitat la recunoașterea unui singur număr de înmatriculare dintr-un cadru video. În cazul in care acest lucru nu se intampla se va pastra regiunea cu cele mai multe schimbari ale intensitatii pixelilor, valoare reținuta în momentul scănarii inițiale.

Rularea unui motor OCR pentru identificarea caracterelor din dreptunghiul binarizat

Recunoașterea caracterelor are la baza extracția caracteristicilor, metodă foarte des utilizată în sfera “computer vision”. Extracția caracteristicilor este un proces de transformare a datelor de intrare din reprezentare bitmap într-o formă de descriptori, care sunt mai potriviți pentru prelucrare computerizată. Recunoașterea caracterelor trebuie să fie invariantă la tipul de font utilizat. În plus, toate instanțele aceluiași caracter ar trebui să aibă o descriere similară. O descriere a caracterului este un vector de valori numerice, așa numitul descriptori sau model. Etapele specifice procesului de recunoaștere de caractere alfanumerice (OCR) sunt prezentate în diagramă de mai jos (Figura 3.62):

Figura 3.62. Schema bloc a algoritmului OCR

Segmentarea caracterelor este o faza intermediară foarte importantă a algoritmului de recunoaștere a numerelor de înmatriculare după faza de localizare. Există mai mulți factori care influențează procesul de segmentare, cum ar fi zgomotul de imagine, cadrul plăcuței, spațierea rotația și variația luminozității. Preprocesarea la acest nivel are un rol foarte important pentru bună derulare a segmentării caracterelor. Această etapă presupune conversia în grayscale și binarizarea după un threshold setabil. Calitatea ariilor asociate numerelor de înmatriculare din diverse imagini variază mult în diferite condiții de captare . Variația de iluminare și zgomot face foarte dificil procesul de segmentare. Metodele de îmbunătățire a imaginii frecvent utilizare în acest proces sunt cele de egalizare a histogramei și scalarea nivelului de gri precum și reducerea zgomotului de imagine. Pentru segmentarea caracterelor, numai pixelii asociați caracterelor trebuie să fie reconstituiți cu acuratețe în timp ce pixelii de fond ar trebui să fie estompati. În majoritatea cazurilor aprximativ 20% din totalul pixelilor aferenți unei imagini a numărului de înmatriculare corespund caracterelor. Deci, în perspectiva optimizării procesului de preprocesare, doar acești 20 % dintre pixeli trebuie să fie îmbunătățiți iar restul pixelilor trebuie să fie estompati. Acest mod de abordare poartă numele de “object enhacement”. Algoritmul de “object enhacement” constă în două etape: în primul rând , nivelul de gri al tuturor pixelilor este scalat în intervalul 0 – 100 și apoi comparat cu intervalul inițial 0 – 255; pixelii aferenți caracterelor și pixelii de fond sunt estompati. Apoi, în a două faza, are loc sortarea tuturor pixelilor pe baza nivelului de gri în ordine descrescătoare și apoi sunt înmulțite valorile primilor 20% cu 2,55; are loc astfel îmbunătățirea pixelilor asociați caracterelor ce urmează a fi segmentate, în timp ce pixelii de fundal rămân estompati. În figura 3.63 sunt prezentate rezultatele procesului de “object enhacement”.

Imaginea originala

Imaginea imbunatatita

Figura 3.63. Rezultatele aplicării algoritmului “object enhacement” asupra unei plăcuțe de înmatriculare

Segmentarea orizontală reprezintă procesul de parcurgere orizontală a zonei rectangulare deja extrase corespunzătoare plăcuței de înmatriculare și identificare a variațiilor de intensitate care conduc la marcarea explicită zonelor care încadrează caractere alfanumerice. Pentru această se calculează proiecțiile orizontale și verticale de intensitate. Apoi se găsesc minimele locale pentru proiecția orizontală. Pe baza pragului (threshold-ului) reprezentat de aceste minime se găsesc și se marchează locațiile regiunilor segmentate. Pentru a localiza marginile din dreapta și din stânga regiunii aferente unui caracter din cadrul numărului de înmatriculare, proiecția verticală este schimbată în imagine binară după morfologia matematică.

unde este proiecția verticală iar T este threshold-ul.

Se scanează apoi funcția și sunt inregistrate pozitiile unde valorile se schimbă de la 0 la 1 si respectiv de la 1 la 0 în două stive distincte, iar lătimea fiecarei regiuni se calculează prin scăderea fiecărei valori din prima stiva din valoarea de pe acelasi nivel corespunzatoare celei de-a doua stive (Figura 3.64).

Figura 3.64. Determinarea regiunilor specifice fiecărui caracter prin metoda binarizării

Acestea dau coordonatele potențialelor regiuni candidate de caracter. Fuziunea sau separarea segmentelor orizontale se realizează prin varierea unui prag determinat de obicei in maniera experimentala si contituie o etapa necesata numai dacă formatul numarului de inmatriculare include caractere foarte aproapiate sau cu segmente de lățime mai mică decât un anumit prag.

Pentru fiecare dintre segmentele orizontale se urmează aceeași procedură pentru a obține limitele verticale. Rezultatul obtinut prin parcurgere orizontala iterativa este prezentat in figura 3.65.

Figura 3.65. Număr de inmatriculare segmentat la nivel de caracter

Propriu-zis, OCR reprezintă transpunerea mecanică sau electronică a imaginilor care conțin text scriss de mâna sau dactilografiat (de obicei capturat de către un scanner) în text editabil la nivel de mașină. Procedura constă din doi pași importanți, de training (antrenare, învățare) și de recunoaștere. În faza de învățare, programul este în primul rând antrenat cu un set de imagini eșantion pentru fiecare dintre caractere în vederea extragerii caracteristicilor importante pe baza cărora se va efectua operația recunoaștere.

Pentru crearea șablonului asociat fiecărui caracter (template) se creează mai întâi un vector bidimensional initializat cu toate valorile 0 (a cărui dimensiune este egală cu dimensiunea matricelor de învățare). Apoi se parcurge vectorul bidimensional reprezentat de una dintre imaginile proba utilizate pentru învățare, binarizata în prealabil. Pentru fiecare pixel negru din matricea proba se incrementează cu 1 pixelul corespunzător (că poziție) din matricea șablon și respectiv se decrementează cu 1 în cazul pixelilor albi. Operația se repetă pentru fiecare matrice proba (Figura 3.66).

Figura 3.66. Exemplificare proces de invatare

Imaginea obținută după segmentare este grayscale. Pentru fiecare regiune asociată unui caracter se procedează relativ similar procesului de învățare, numai că de această dată se calculează nivelul de similaritate. Astfel se parcurg pixelii negri din matricea aferentă regiunii unui caracter și sunt comparate pozițiile acestora în raport cu un șablon de caracter (obținut în faza de învățare). Dacă există corespondență (poziția unui pixel negru din regiunea caracterului corespunde cu poziția unui pixel negru din șablon) nivelul de similaritate este incrementat cu o unitate. Dacă nu nivelul de similaritate este decrementat cu o unitate. Procesul este repetitiv executându-se pentru fiecare șablon în parte. Chiar dacă teoretic ar constitui o operațiune greoaie, consumatoare de resurse de procesare, situația nu este critică întrucât în faza de preprocesare se scaleaza regiunea corespunzătoare numărului de înmatriculare și implicit regiunile asociate caracterelor pentru a există matching cu dimensiunea template-urilor care de obicei au dimensiuni reduse (ex: 15 x 15 pixeli, 30 x 30 pixeli).

Cap. 4. Strategia de atingere a obiectivului

Problematica implementării hardware și software a unui robot de tip "Platforma wireless robotizată pentru captura și analiză de imagine în timp real” a fost descompusă în câteva subprobleme caracteristice acestui tip de aplicație.

4.1 Proiectarea hardware

Proiectarea hardware a vizat trei module distincte:

Proiectarea modulului de control

Proiectarea modulului senzorial

Proiectarea modulului de transmisie video

Ca și principii luate în calcul în constucția hardware a robotului se pot menționa centrul de greutate cât mai apropiat de sol pentru stabilitate, robustețe sporită, acces facil la componentele electronice, dimensiuni compacte, cuplu ridicat.

4.1.1 Proiectarea modulului de control

Modulul de control al robotului de tip "Platforma wireless robotizată pentru captura și analiză de imagine în timp real”, din perspectiva hardware, desemnează ansamblul de componente fizice și electronice care fac posibilă transmitarea comenzilor de la operator, recepționarea acestora de către robot și descrierea comportamentului tuturor subansamblelor locomotoare ale robotului în sensul realizării mișcărilor dorite.

Tramsmisia comenzilor de la PC la robot

Componentele hardware alese pentru realizarea funcției de transmitere a comenzilor de la operator la robot și respectiv pentru recepția datelor provenite de la senzori sunt două plăci de tip XBee Pro S28, care funcționează în bandă de 900 MHz.

Pentru conexiunea unui modul XBee cu PC-ul s-a utilizat un soclu special, care dispune de pini “tată” orientați corespunzător amprentei de pini “mama” ce se regăsesc pe plăcută wireless, astfel încât să se asigure o conexiune robustă și sigură. Soclul dispune de un chip FTDI pentru interfatare USB și cu ajutorul căruia se pot realiza operațiunile de configurare preliminară a modulelor XBee. Această procedura implică parcurgerea a câțiva pași simpli utilizând software-ul specializat X-CTU:

Selectarea portului de comunicație, a ratei baud, a numărului de biți de date, paritate și bit de stop din meniul „PC Settings” (Figura 4.1):

Figura 4.1. Meniul “PC Settings” Figura 4.2. Meniul “Modem Configuration”

Citirea configuratiei initiale a chipului (si eventual firmware update) prin apasearea butonului „Read” din meniul „Modem Configuration”:

Setarea adreselor destinatie „DH” si „DL” aferente modulului cu care se doreste a fi imperecheat, setarea unei denumiri a nodului curent „NI”, setarea ratei baud „BD” si setarea tipului de criptare a datelor dorit din mediul „Modem Configuration”.

Scrierea noi configuratii in memoria interna a chipului wireless prin apasarea butonului „Write” din meniul „Modem configuration”.

Pentru aplicația "Platforma wireless robotizată pentru captura și analiză de imagine în timp real” s-a utilizat o configurație de dip MASTER-SLAVE pentru cele două chipuri wireless, stația fixă constituind elementul MASTER iar stația mobilă constituind elementul SLAVE.

Conexiunea USB a facilitat alimentarea plăcuței wireless direct la o tensiune de 5 Vcc.

Interconectarea modulului XBee cu microconrollerul Atmel ATmega 328P s-a realizat prin intermediul portului serial, disponibil atât la nivelul plăcii de baza Arduino UNO R3 care integrează acest tip de microcontroller cât și la nivelul plăcii wireless XBee – pînul TX (de transmisie a datelor pe magistrala serială) corespunzător unei entități a fost conectat la pînul RX (de transmisie a datelor pe magistrala serială) aferent entității pereche. Alimentarea modulului XBee atașat robotului s-a realizat utilizându-se o sursă de tensiune construită în regim propriu cu ajutorul unui circuit integrat de tip LM7805.

Pentru fiecare dintre cele două module wireless s-au prevăzut antene omnidirecționale dotate cu conectori de tip RPSMA în sensul creșterii razei de acțiune a patformei mobile.

Prelucrarea comenzilor provenite de la operator și acționarea motoarelor

În urma recepției datelor de pe interfața serială, algoritmul logic de prelucrare, care rulează pe microcontroller, stabilește comportamentul robotului și generează comenzi pentru driverele motor și implicit pentru motoarele de c.c. precum și pentru servomotoarele asociate brațului mobil cu două grade de libertate.

Fiecare dintre cele două drivere motor de tip Pololu High-Power Motor Driver 24v20 oferă posibilitaea de comandă PWM, care presupune existența a doi pini de interconectare caracteristici: un pin de intrare PWM și un pin de intrare digital care determina sensul de rotație al motoarelor de c.c. asociate.

Tehnologia PWM (Pulse Widith Modulation) este utilizată în această aplicație pentru controlul unei mărimi analogice – tensiunea – cu ajutorul unui procesor numeric. O explicație simplistă a principiului de funcționare PWM susține că, datorită tipului de procesor, capabil să genereze numai valori logice,“1” și “0”, adică tensiuni logice 5 V sau 0 V, este imposibil controlul în teniune cu valori mai mari de 5 V. Așadar este emis un puls din partea procesorului (succesiune de valori consecutive “1” logic sau “0” logic) pe un interval de timp proporțional cu tensiunea dorită, iar driverul recunoaște tipul de puls și lungimea acestuia și permite trecerea unei tensiuni corespunzătoare.

Placa de baza Arduino UNO R3 dispune de șase pini digitali care sunt capabili în a fi utilizați pentru PWM și încă șase pini digitali simpli. Așadar conexiunea între driverele motor și placă de baza a presupus alocarea a patru pini distincți, dintre care doi pini PWM și doi pini digitali convenționali. Din motive de infrastructură a cablajului aceștia au fost aleși consecutivi pe placă (pinii 3 și 5 PWM, pinii 2 și 4 digitali).

Motoarele pas cu pas pot fi controlate cu ajutorul câte unui singur pin digital, care însă trbuie să fie configurat în prealabil în acest sens cu ajutorul unei clase software specializate. S-au utilizat deci alți doi pini digitali pentru conectarea celor două servomotoare.

Circuitul de putere asociat ansamblului motor de c.c. – driver motor a fost dimenisionat utilizând convenția menționată în secvență 3.1.8, alimentarea făcându-se direct de la acumulatori, iar conexiunea celor șase motoare la cele două drivere este de tip paralel.

4.1.2 Proiectarea modulului senzorial

Modulul senzorial al robotului de "Platforma wireless robotizată pentru captura și analiză de imagine în timp real”, din perspectiva hardware, desemnează ansamblul format din totalitatea senzorilor atașați, al căror rol este oferirea unor informații vizuale și numerice cu privire la perimetrul în care se desfășoară evoluția robotului.

Platforma integrează două tipuri distincte de senzori:

Senzori de proximitate

Senzori video

Modelul de senzori de proximitate cu ultrasunete ales este Maxbotix LV MaxSonar EZ4 a cărui structura permite furnizarea datelor către microcontroller atât prin intermediul pinilor analogici, ceea ce conferă un grad de precizie ceva mai redus, cât și prin intermediul PWM, ceea ce oferă un grad de precizie foarte ridicat. Acest ultim mod de conexiune necesită în prealabil o calibrare a senzorilor.

Din dorința furnizării unei informații perimetrale cât mai precise s-a optat pentru conexiunea PWM în combinație cu un algoritm software avansat, astfel că au fost alocați patru pini digitali PWM pentru această aplicație (pinii 6,9,10,11). Alimentarea celor patru sonare s-a făcut cu ajutorul sursei de tensiune de 5 V integrată pe placă de baza Arduino UNO R3 întrucât consumul cumulat de curent nu depășește ordinul câtorva zeci de mĂ.

Senzorul video CMOS Boscam HD19 a fost amplasat în punctul terminal al brațului robot cu două grade de libertate, alimentat de la sursă dedicată de tensiune continuă de 5 V construită în regim propriu cu circuit integrat de tip LM7805, și interconectată cu transmițătorul video conform structurii cablajului prezentat în secțiunea 3.1.3.2.

4.1.3 Integrarea modulului de transmisie video

Modulul de transmisie video al robotului de tip "Platforma wireless robotizată pentru captura și analiză de imagine în timp real”, din perspectiva hardware, desemnează dispozitivul sau perechea de dispozitive a căror funcționalitate este reprezentată de preluarea semnalului video furnizat de senzorul CMOS și transmiterea acestuia sub formă analogică, wireless, între două puncte ce regăsesc la o distanță mai mică sau cel mult egală cu rază maximă de acțiune, calculabilă în prealabil.

Ansamblul FPV TX/RX 200mW 2.4 GHz conține două module distincte aferente celor două puncte terminale, ambele de tip plug&amp;play. Așa cum a fost menționat în secțiunea anterioară interconectarea emitorului cu senzorul CCD a presupus realizarea conexiunii video, audio-left și audio-right, întrucât pe lângă semnalul video, camera marca FatShark dispune și de două microfoane stânga-dreapta pentru furnizarea unui semnal audio stereo.

Alimentarea sistemului la 12 V a fost realizată cu ajutorul unei surse de curent continuu contruită în regim propriu, bazată pe circuitul integrat LM7812.

4.1.4 Schema bloc hardware

Figura 4.3. Schema bloc hardware

4.2 Proiectarea software

Proiectarea hardware a vizat trei module distincte:

Programarea microcontrolerului ATMega328 in limbaj C

Interfatarea cu PC-ul

Proiectarea unei aplicatii de control (Windows) in limbaj C# (.NET)

Ca principii de baza luate în considerare pentru proiectarea software trebuiec menționate eficiecta și stabilitatea algoritmilor, optimizarea acestora pentru un consum redus de resurse hardware, precum și menținerea unor scheme logice clare și simple pentru un regim de funcționare optim.

4.2.1 Programarea microcontrolerului ATMega328 in limbaj C

Programul scris pe microcontroller în limbaj C descrie toate stările în care se poate regăsi robotul și determina comportamentul acestuia în funcție de comenzile furnizate de operator. Sintaxa C utilizată în cazul de față prezintă anumite particularități specifice mediului de dezvoltare Arduino și integrează reguli logice asociate principiilor de funcționare hardware.

Structura programului relevă trei componente principale specifice:

1. componenta inițială în care se realizează declararea variabilelor si definirea pinilor

2. bucla void setup() în care se scriu instrucțiuni ce vor fi executate o sigură dată la lansarea în execuție programului (ex: inițializări, pornire conexiune serială, specificarea tipului pinilor digitali – IN/OUT etc.)

3. bucla void loop() în care se scriu instrucțiuni ce vor fi executate la nesfârșit, până la încetarea executiei programului

Declararea variabilelor și definirea pinilor au fost realizate prin instrucțiuni dedicate de tipul:

int viteza,factor;

long timp_anterior=0;

#define motor_dr_pin 5

#define motor_st_pin 3

Tipurile de date utilizate sunt caracteristice limbajului C iar funcția „#define” este inclusă în sintaxa de baza a medului de programare Arduino, având rolul definirii unei asocieri între un

număr semnificând numărul pinului și o denumire preferențială aleasă de obicei în funcție de rolul respectivei conexiuni (conexiunea pe acel pin).

Librăria specială Servo.h a fost inclusă prin intermediul instrucțiunii #include <Servo.h> pentru a servi la manipularea motoarelor pas cu pas. Funcțiile specifice incluse în aceasta librarie și utilizate pentru mișcarea servomotoarelor sunt:

servo_vert.attach(12); – pentru asocierea unui pin de comandă a servomotorului (i.e.12)

servo_vert.write(pos_vert); – pentru mișcarea motorului într-o anumită poziție (i.e. pos_vert). Valoarea atașată poziției desemnează unghiul cu care va fi rotit servomotorul față de o poziție de referință.

În cadrul buclei void setup() au fost executate instrucțiunile de atașare ale pinilor aferenți controlului servomotoarelor, au fost setate tipurile pinilor digitali (de intrare sau de ieșire) cu instrucțiunea pinMode (ex: pinMode(dir_dr_pin, OUTPUT)), a fost pornită conexiunea serială cu instrucțiunea Serial.begin(115200) și a fost setată poziția standard a bratului robot cu două grade de libertate ce susține camera video prin apelarea funcției initial(). Astfel că, la fiecare pornire a robotului și implicit lansare în execuție a programului brațul robot va fi mișcat în cele două planuri (vertical si orizontal) astfel încât să atingă pozitia standard.

void initial()

{

servo_vert.write(90);

servo_oriz.write(90);

delay(15);

}

Funcția delay() specifică mediului de programare Arduino permite oprirea execuției programului pentru o perioadă specificată în milisecunde, urmând ca ulterior acesta să fie reluat din punctul la care a fost întrerupt. De obicei această funcție se utilizează pentru a permite finalizarea executiei mișcărilor unor acționări fizice sau transmisii de date.

Bucla void loop() include toate rutinele de tratare a comenzilor furnizate de operator și transmise prin intermediul conexiunii seriale. Principiul de funcționare abordat prevede ca fiecare comandă emisă de PC să aibă un caracter alfanumeric asociat. Astfel că, în funcție de echivalentul ASCII al fiecărui caracter alfanumeric, se va executa o rutină specifică ce va determina comportamentul robotului. În acest sens a fost implementată o structură switch..case dupa valoarea citita de pe magistrala serială:

if(Serial.available())

{

x=Serial.read();

}

switch (x)

{

case 119:

inainte(viteza);

break;

case 115:

inapoi(viteza);

break;

case 97:

intoarcere_st(viteza);

break;

case 100:

intoarcere_dr(viteza);

break;

……………………………………….

}

Funcția Serial.available() returnează TRUE în situația în care există date în bufferul de intrare a conexiunii seriale și FALSE în caz contrar. Asa cum o susține și sintaxa proprie, funcția Serial.read() efectuează citirea datelor de pe magistrala serială (*este realizată o conversie implicită în format ASCII a datelor citite).

Funcțiile care vizează mișcarea șasiului robot (înainte, înapoi, întoarcere_st, întoarcere_dr, oprire) au o structură asemănătoare, elementele distinctive fiind constituite de valoarile asociate pinilor digitali desemnând sensul de roțatie al motoarelor. Astfel pentru mers înainte sensurile de rotație ale celor două seturi de motoare (stânga/dreapta) trebuie să fie similare, pe direcția înainte, pentru mers înapoi sensurile de rotație ale celor două seturi de motoare (stânga/dreapta) trebuie să fie similare, pe direcția înapoi, pentru întoarcere la stânga sensurile de rotație ale celor două seturi de motoare (stânga/dreapta) trebuie să fie distincte, cel stâng pe direcția înapoi iar cel drept pe direcția înainte, pentru întoarcere la dreapta sensurile de rotație ale celor două seturi de motoare (stânga/dreapta) trebuie să fie distincte, cel stâng pe direcția înainte iar cel drept pe direcția înapoi, iar pentru stop evident că toate cele două seturi de motoare vor fi oprite.

ex: intoarcere_st

void intoarcere_st(int viteza)

{

int viteza_viraj;

if(viteza>70)

{

viteza_viraj=70;

}

else

{

viteza_viraj=viteza;

}

digitalWrite(dir_dr_pin, HIGH);

digitalWrite(dir_st_pin, HIGH);

analogWrite(motor_dr_pin, viteza_viraj);

analogWrite(motor_st_pin, viteza_viraj);

}

Fiecare funcție de mișcare a șasiului robot primeste ca parametru viteza setată a robotului de tip int. În plus față de funcțiile înainte/înapoi, funcțiile pentru viraj integrează și câte o secvență de cod în care viteza motoarelor este limitată la o valoare prestabilită pentru a preveni imposibilitatea de control a robotului ca efect al executiei mult prea rapidă a virajului. Așadar, indiferent de nivelul la care este setată viteza motoarelor de către operator prin funcțiile de incrementare/decrementare, în situatia unui viraj, viteza nu va depăsi un prag prestabilit (i.e. 70) care sa permită operatorului uman să stabileasca traiectoria dorită, după care să treacă miscare în linie dreaptă (înainte/înapoi). Cu ajutorul funcției digitalWrite se poate seta o valoare binară (HIGH/LOW) pentru un pin definit anterior. Această valoare desemnează sensul motoarelor. Functia analogWrite utilizată pentru un pin digital configurat corespunzător (OUTPUT) permite generarea unui semnal PWM. În exemplul atașat, cu ajutorul acestui semnal se controlează tensiunea (marime analogică) în driverele motor și implicit viteza robotului.

Funcțiile de incrementare/decrementare a vitezei reprezintă simple incrementări și decrementări cu un pas fix ale unor variabile de tip int. Pentru limitarea plajei de valori ale variabilei asociate vitezei s-a utilizat funcția constrain (viteza=constrain(viteza,0,200)).

Citirea informației perimetrale de la senzorii de proximitate și transmiterea acesteia pe magistrala serială a reprezentat o problematică ceva mai complexa atât datorită conversiilor ce au trebuit efectuate în sensul operării cu mărimi metrice convenționale cât și datorită limitărilor pricipiului de funcționare al conexiunii seriale.

Conexiunea senzorilor de proximitate cu microcontrollerul putea fi realizată fie analogic, fie digital prin PWM. S-a optat pentru o conexiune PWM întrucât nivelul de precizie era semnificativ îmbunătățit. Însă, această soluție a necesitat un algoritm mai complex pentru citirea distanței și prelucrarea acesteia.

long readDistance_sf()

{

long duration, inches, cm;

pinMode(pingPin_sf, OUTPUT);

digitalWrite(pingPin_sf, LOW);

delayMicroseconds(2);

digitalWrite(pingPin_sf, HIGH);

delayMicroseconds(5);

digitalWrite(pingPin_sf, LOW);

pinMode(pingPin_sf, INPUT);

duration = pulseIn(pingPin_sf, HIGH);

cm = microsecondsToCentimeters(duration);

return(cm);

}

Rutina de citire a datelor de la senzorii conectați PWM susține emisia inițială a unor pulsuri de calibrare cu ajutorul funcției digitalWrite și ulterior citirea valorilor furnizate de senzori. Întrucât este abordat principiul PWM referința datelor de intrare va fi timpul și nu distanța în sine. Așadar durata pulsurilor HIGH obținută cu funcția pulseIn este convertită în centimetri printr-un calcul matematic asociat funcției microsecondsToCentimeters(). Acest calcul matematic rezultă din specificațiile tehnice ale sonarului.

Reprezentarea grafică a obstacolelor în cadrul aplicației PC a impus transmiterea distanțelor furnizate de senzori către PC prin intermediul magistralei seriale. Însă, conform principiului de bază al comnicației seriale, transmisia se efectuează caracter cu caracter prin intermediul bufferelor specifice, și deci transmiterea continuă către PC a celor patru distanțe aferente celor patru senzori de proximitate nu a reprezentat o soluție. O astfel de abordare ar fi generat întârzieri majore atât pentru transmiterea comenzilor cât și pentru recepționarea informației perimetrale de către PC. O idee mult mai bună a fost abordarea pe stări și prelucrarea datelor la nivelul microcontrollerului. Fiecărui senzor i-a fost asociată o rutină de prelucrare a datelor (distanțelor) citite. Au fost considerate patru nivele distincte care reflecta apropierea de un obstacol. În urma rulării rutinei asociate unui senzor este evaluată distantanța citită și stabilit nivelul de apropiere al obstacolului, și deci stabilirea unei stări. Numai în situația în care starea anterioară diferă de starea curentă este transmis pe magistrala seriala un șir de date specific, care identifică nivelul de apropiere al obstacolului.

if(distanta_sf<=60)

{

if(distanta_sf<=40)

{

if(distanta_sf<=20)

{

sf_curent=1;

}

else

{

sf_curent=2;

}

}

else

{

sf_curent=3;

}

}

else sf_curent=0;

Scrierea unui șir de caractere pe magistrala serială a fost posibila cu ajutorul funcției Serial.println().

Modul AUTO reprezintă un hibrid între toate funcțiile menționate anterior. Robotul evoluează singur și adoptă decizii de mișcare pe baza informațiilor furnizate de senzori. Ideea luată în calcul a fost structurarea algoritmului în funcție de două scenarii frecvente:

– situația în care un obstacol apare la o distanță suficient de mare astfel încat să poată fi evitat din mers

– situatia în care obstacolul este mult prea aproape pentru a fi evitat și deci este necesară o manevră cu spatele

Distanțele vizate pentru aceste două scenarii sunt 40 cm respectiv 20 cm. Algoritmul propune o soluție diferențială cu factor compensator. Pe scurt, în oricare dintre cele două scenarii, se evaluează care dintre senzorii frontali furnizează o distanță mai mare (obstacol mai îndepărtat). Se efectuează diferența, scăzându-se distanța mai mică din cea mai mare și astfel se obține factorul de compensare. Întrucât modalitatea de stabilire a unghiului de cârmire este dată de durata (timpul) în care se executa virajul (se trece în starea la_stânga), factorul de compensare va fi utilizat ca parametru al functiei delay() și deci ca temporizator pentru efectuarea virajului. Schema logică a algoritmului este prezentată in figura 4.4.

Figura 4.4. Schema logica a algoritmului AUTO

4.2.2 Schema bloc software a programului microcontroller

Figura 4.5. Schema bloc software a programului microcontroller

Interfatarea cu PC-ul

Comunicatia seriala intre PC si robot a presupus existenta unui port COM alocat acestei aplicatii, configurat astfel incat sa corespunda setarilor de transmisie asociate modulelor wireless XBee. Operatiunea de alocare a portului de comunicatie consta din cativa pasi simpli precum:

Conectarea placii Xbee la PC prin intermediul USB (FTDI)

Accesarea mediului „Device Manager” (Windows 7: click dreapta pe „MyComputer” si selectia „Device Manager” din meniul din stanga) si selectarea portului de interes din sectiunea „Ports (COM & LPT)” (Figura 4.6).

Click dreapta pe portul vizat si selectarea optiunii „Properties”

Navigarea la meniul „Port Settings” si setarea acestora conform valorilor stabilite in sectiunea de donfigurare a modulelor wireless (Figura 4.7).

Baud rate: 115200

Data bits: 8

Parity: None

Stop bits: 1

Flow control: None

Figura 4.6. Meniul “Device Manager” Figura 4.7. Meniul “Port Settings”

Configurarea portului serial asigura buna functionare a transmisiei datelor intr-un regim optimal. La nivelul aplicatiei PC realizata in limbaj de programare C# utilizand framework-ul .NET a fost utilizata libraria System.IO.Ports care ofera posibilitatea accesului la porturile de comunicatie seriala ale PC-ului. Asadar a fost declarata o variabila de tip SerialPort avand urmatoarea configuratie:

public SerialPort sp;

sp = new SerialPort(port, baud, Parity.None, nrBiti, StopBits.One);

in care variabila port desemnează denumirea portului pe care se va realiza transmisia iar variabila baud desemnează rata baud asociata comunicației (115200). Totodata a mai fost specificata si metoda de handshake pentru asigurarea coerentei datelor transmise.

sp.Handshake = Handshake.XOnXOff;

După configurarea portului serial, la sosirea oricărei date pe respectivul port va genera un event specific a cărui rutină de tratare este specificată de sintaxa:

sp.DataReceived += new SerialDataReceivedEventHandler(receptieDate);

Pentru scrierea datelor pe portul serial configurat, se va utiliza functia predefinita

sp.Write(buff, 0, 1);

unde buff constituie bufferul de date ce urmeaza a fi transmis.

Pentru o interfatare intuitivă cu utilizatorul a fost creat un “Form” dedicat configurării conexiunii seriale (Figura 4.8) în cadrul căruia sunt introduse toate datele menționate anterior și care este lansat în execuție înaintea aplicației PC propriu-zise.

Figura 4.8. “Form-ul” pentru configurarea conexiunii seriale

În situația în care datele sunt valide pentru respectivă conexiune se va furniza acces la aplicația PC propriu-zisă, iar în caz contrar se vor afișa mesaje vizând câmpurile care conțin date eronate.

Algoritmul de validare este relativ simplu și se bazează pe erorile gererate în mod automat în cazul imposibilității de initializare a portului serial:

private void lInitializareConexiune_Click(object sender, EventArgs e)

{

bool ok=false;

try

{

sp = new SerialPort(cbPort.Text, Convert.ToInt32(cbBaud.Text), Parity.None, Convert.ToInt32(cbNrBiti.Text));

ok = true;

}

catch (Exception)

{

MessageBox.Show("Selectati toti parametrii conexiunii din box-ul corespunzator!");

}

if (ok == true)

{

try

{

sp.Open();

if (sp.IsOpen)

{

MessageBox.Show("Conexiune stabilita cu succes!");

sp.Close();

Main a = new Main(cbPort.Text, Convert.ToInt32(cbBaud.Text), Convert.ToInt32(cbNrBiti.Text));

a.Show();

}

}

catch (Exception)

{

MessageBox.Show("Conexiune esuata! Verificati daca robotul este pornit!");

}

}

}

Valorile care populează ComboBox-ul aferent portului de comunicație sunt generate dinamic în funcție de porturile COM de pe respectivul PC angrenate în diverse tipuri de comunicație serială. Totodată valorile care populează celelalte două ComboBox-uri sunt predefinite (valori standard ce definesc rate baud și numărul de biți).

4.2.4 Proiectarea unei aplicații de control (Windows) în limbaj C# (.NET)

Proiectarea unei aplicații de control pentru PC a reprezentat redarea într-o formă grafică orientată către utilizator a tuturor informațiilor și comenzilor care țin de funcționarea platformei mobile wireless pentru explorarea mediilor periculoase. Astfel că structura de baza a aplicatei conține trei module asociate celor patru funcționalități principale ale robotului (Figura 4.9):

Modulul conținând elementele de control

Modulul conținând informația video furnizată de robot

Modulul conținând informația de la senzorii cu ultrasunete sub formă grafică

Modulul conținând elementele de selecție și control pentru procesare de imagine

Figura 4.9. Structura de bază a aplicației PC

Modulul conținând elementele de control

Figura 4.10. Modulul conținând elementele de control

Acest modul integrează toate elementele grafice asociate comenzilor ce pot fi lansate către robot, dispuse într-o manieră intuitivă, conformă cu direcțiile orientării umane. Se pot distinge cu ușurință cele cinci butoane asociate celor cinci stări distincte în care se poate regăsi întregul ansamblu robot: înainte, înapoi, stânga, dreapta și stop, cele două scroll-uri care determina poziția brațului mobil cu două grade de libertate (și implicit poziția senzorului video), cele două butoane dedicate intrementarii/decrementării vitezei de mișcare, butonul “Reset” pentru readucerea brațului robot în starea inițială, precum și butonul “Auto” care trece platforma mobilă într-o stare specială în care deplasarea întregului ansamblu robot se face fără intervenția factorului uman, ci numai pe baza informațiilor de la senzori.

Fiecare dintre aceste entități de comandă are asociat câte un caracter alfanumeric folosit atât pentru facilitarea controlului robotului prin utilizarea tastaturii (scop secundar) dar mai ales pentru respectarea principiului de comunicație serială de tip “caracter cu caracter” și eficientizarea procesului de transmisie a datelor (scop principal).

Modalitățile de transmisie a comenzilor

Toate funcțiile care vor fi lansate în execuție la accesarea oricărei entități de control din acest meniu sunt implementate la nivelul programului ce rulează pe microcontrollerul robotului. Așadar comportamentul robotului este determinat de algoritmii existenți deja în cadrul funcțiilor dedicate, scrise în memoria microcontrollerului. Principiul de funcționare ales, presupune că, la recepția pe interfață serială a unui anumit caracter asociat în prealabil unei anumite funcții, să se lanseze în execuție repectivă funcție și să ruleze până la o nouă achiziție a unui nou caracter.

Așadar, rolul aplicației PC nu este acela de a stabili algoritmii decizionali în ceea ce privește comportamentul robotului ci numai de a transmite pe magistrala serială un caracter specific funcției selectate. Prin convenție, pentru simplitate, s-a recurs la utilizarea aceluiaș caracter alfanumeric atât pentru accesarea unei funcții de la tastatură cât și pentru identificarea respectivei funcții la nivelul programului de pe microcontroller.

Nota: programul scris la nivelul microcontrollerului va lucra întotdeauna cu echivalentul ascii al caracterului transmis.

Exemplu: caracterul “w” având echivalentul ascii 119, este asociat funcției “înainte”. Astfel că la apăsarea “w” sau a butonului asociat pe magistrala seriala va fi scris echivalentul ascii al caracterului “w”.

La recepționarea valorii 119 programul care rulează pe microcontroller va lansa în execuție funcția “înainte” care include algoritmul ce determină comportamentul robotului în acest sens – grupul motor stânga și grupul motor dreapta se vor învarti în aceeași direcție cu aceeași viteză.

Pentru implementarea procesului de scriere a datelor pe magistrala serială caracterizată de un anumit port de comunicație serială s-a utilizat următoarea structură:

private void btn_inainte_Click(object sender, EventArgs e)

{

try

{

buff[0] = 'w';

sp.Write(buff, 0, 1);

btn_inainte.BackColor = Color.Gray;

btn_inapoi.BackColor = Color.Transparent;

btn_stanga.BackColor = Color.Transparent;

btn_dreapta.BackColor = Color.Transparent;

btn_stop.BackColor = Color.Transparent;

bAuto.BackColor = Color.Transparent;

}

catch (Exception ex)

{

MessageBox.Show(ex.ToString());

}

}

unde buff[0] reprezintă prima valoare a bufferului de date ce urmează a fi trimise. Strunctura sp.Write(buff, 0, 1) se rezumă la scrierea pe portul serial definit anterior sp a unei valori din bufferul de date buff, valoare situată la pozitia 0 și de lungime 1 (o unitate din buffer).

Intr-un mod asemănător din punct de vedere principial s-a procedat și pentru scrierea pe magistrala serială a caracterelor corespunzatoare funcțiilor de rotire stânga/dreapta sus/jos a servomotoarelor brațului robot.

private void vSBcameraVert_ValueChanged(object sender, EventArgs e)

{

int poz_curenta=vSBcameraVert.Value;

if (poz_curenta > poz_anterioara_vert)

{

buff[0] = 'k';

sp.Write(buff, 0, 1);

poz_anterioara_vert = poz_curenta;

}

else

{

buff[0] = 'i';

sp.Write(buff, 0, 1);

poz_anterioara_vert = poz_curenta;

}

}

În această situație se analizează poziția actuală a scrolului în raport cu poziția precedentă și în funcție de rezultat se transmite un caracter corespunzător rotirii într-un anumit sens sau în sens contrar.

Modulul conținând informația video furnizată de robot

Figura 4.11. Modulul conținând informația video furnizată de robot

Acest modul integrează toate elementele grafice asociate semnalului video furnizat de robot și captat de PC prin intermediul unei plăci de captura dedicate. Tot la nivelul acestui modul a fost integrat algoritmul de captura de imagine și salvarea acesteia în format JPEG.

Entitățile specifice ce se pot distinge cu ușurință sunt: chenarul aferent cadrelor propriu-zise, meniul de selecție al sursei video, butonul “Refresh” pentru actualizarea opțiunilor din meniul de selecție, butonul “Start” pentru lansarea redării semnalului video precum și simbolul unui aparat foto, la apăsarea căruia se va realiza captura de imagine și salvarea acesteia într-un folder predefinit.

La nivel de implementare, au fost utilizate librării specifice care dispun de funcții video dedicate:

using Emgu.CV;

using Emgu.CV.CvEnum;

using Emgu.CV.Features2D;

using Emgu.CV.Structure;

using Emgu.CV.Util;

using Emgu.CV.GPU;

using Emgu.CV.OCR;

using DirectShowLib;

Pentru popularea ComboBox-ului asociat surselor video disponibile a fost scris urmatorul algoritm:

//funtie pentru popularea surselor video

public void populare_surse_video()

{

//populare combo box

DsDevice[] elemente_captura_disponibile = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);

for (int i = 0; i < elemente_captura_disponibile.Length; i++)

{

cbSursa_video.Items.Add(elemente_captura_disponibile[i].Name.ToString());

}

//daca exita surse video disponibile

if (cbSursa_video.Items.Count > 0)

{

cbSursa_video.Enabled = true;

cbSursa_video.SelectedIndex = 0;

bVideo.Enabled = true;

}

//daca nu exista surse video disponibile

else

{

cbSursa_video.Enabled = false;

bVideo.Enabled = false;

}

}

FilterCategory.VideoInputDevice returneaza toate dispozitivele video conectate la respectivul PC capabile sa furnizeze semnal video. Acestea sunt salvate intr-o colectie denumita intuitiv dispozitive_video cu ajutorul sintaxei:

dispozitive_video = new FilterInfoCollection(FilterCategory.VideoInputDevice);

În cazul in care exista cel putin o sursa video disponibila se realizeaza o parcurgere a colectiei mai sus mentionate (foreach) iar elementele sale (denumirile surselor video) sunt inserate in ComboBox-ul asociat (cbSursa_video.Items.Add(dispozitiv.Name)). In caz contrar este generata o exceptie, ComboBox-ul fiind populat cu un mesaj specific.

Pentru obținerea efectivă a imaginii video a fost utilizat un algoritm special care generează un eveniment special la apariția fiecărui frame nou care este tratat că atare, astfel încât să se respecte rezoluția și frecvența cadrelor:

//eveniment declansat la apasarea butonului start

private void bVideo_Click(object sender, EventArgs e)

{

//daca nu a fost instantiata captura

if (captura == null)

{

try

{

captura = new Capture();

}

catch (NullReferenceException excpt)

{

MessageBox.Show(excpt.Message);

}

}

//daca a fost instantiata captura

if (captura != null)

{

//verificare daca procesul de captura are loc

if (captura_in_progres)

{

//daca procesul de captura are loc, procesul se va opri iar textul butonului va redeveni "Start"

bVideo.Text = "Start";

Application.Idle -= proceseaza_cadru;

Application.Idle -= detecteaza_fete;

Application.Idle -= detecteaza_similaritati;

Application.Idle -= proceseaza_cadru_detecteaza_similaritati;

Application.Idle -= detecteaza_siluete;

cron.Stop();

pbVideo.Image = null;

if (esteFullScreen == true)

{

pCopyright.Visible = false;

}

else

{

pCopyright.Visible = true;

}

lProcesareImagine.Visible = false;

ctProcesareImagine.Visible = false;

}

else

{

//daca procesul de captura nu are loc, se porneste procesul de captura iar textul butonului va deveni "Stop"

bVideo.Text = "Stop";

Application.Idle += proceseaza_cadru;

setari_initiale_captura();

pCopyright.Visible = false;

ctProcesareImagine.Visible = true;

if (esteFullScreen == true)

{

lProcesareImagine.Visible = false;

}

else

{

lProcesareImagine.Visible = true;

}

ctProcesareImagine.SelectedTab = ctProcesareImagine.TabPages[0];

}

captura_in_progres = !captura_in_progres;

}

}

//functie pentru preluarea unui cadru de la elementul de captura si transpunerea lui in ImageBox

private void proceseaza_cadru(object sender, EventArgs arg)

{

Image<Bgr, Byte> cadru_image_box_primar = captura.QueryFrame();

if (cadru_image_box_primar != null)

{

Image<Bgr, Byte> cadru_image_box = cadru_image_box_primar.Resize(pbVideo.Width, pbVideo.Height, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR);

pbVideo.Image = cadru_image_box.ToBitmap();

}

}

Pentru specificarea dimensiunii cadrelor vieo si implicit a rezolutiei acestora a fost utilizata functia Resize(pbVideo.Width, pbVideo.Height, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR). Dimensiuea unui cadru va fi dinamic stabilita in funcie de dimensiunea PicureBox-ului de monitorizare care la randul sau este scalat in momentul lansarii aplicatiei pentru operare fullscreen. Modalitatea de interpolare pentru redimensionare este interpolare liniara. La apasarea butonului “Start”, in conditiile in care exista o sursa video selectata, cadrele vor incepe sa se succeada, iar functionalitatea respectivului buton se va schimba. Asadar la o noua apasare transmisia video se va sista – “Stop”. Asadar toate procesele de prelucrare video lansate anterior prin sintaxa Application.Idle += nume_proces vor fi sistate (-=).

.

Modulul conținând informația de la senzorii cu ultrasunete sub forma grafică

Figura 4.12. Modulul conținând informația de la senzorii cu ultrasunete sub forma grafică

Acest modul integrează toate elementele grafice asociate informațiilor provenite de la senzorii de distanță montați pe robot. Astfel că, în situația în care este detectat vreun obstacol în spectrul de acțiune al unuia dintre cei patru senzori, se va afișa sub o formă grafică intuitivă nivelul de apropiere între respectivul obstacol și robot, precum și poziția relativă a acestuia față de robot (Figura 4.13). În situația în care obstacolul se regăsește la o distanță mai mică de 20 cm, atât în față cât și în spatele robotului, se va sugera oprirea de urgență a robotului prin schimbarea culorii semaforului în roșu (Figura 4.14).

Figura 4.13. Scenariu detecție obstacol la distanța Figura 4.14. Scenariu detecție obstacol în imediata apropiere

La nivel de implementare, pentru receptia datelor de pe magistrala seriala s-a utilizat un “event” special de tipul:

sp.DataReceived += new SerialDataReceivedEventHandler(receptieDate);

in care sp este portul serial declarat anterior asociat comunicatiei cu robotul, iar SerialDataReceivedEventHandler reprezinta rutina de tratare in cazul aparitiei unui eveniment de tip DataReceived , denumita intuitiv receptieDate.

Așa cum a fost menționat și în secțiunea 4.2.1, pentru optimizarea procesului de transmisie a datelor între PC și robot și invers, că urmare a limitărilor conexiunii seriale, s-a optat pentru o abordare pe stări, în ceea ce privește vehicularea informației perimetrale, provenită de la senzorii de distanță. Astfel că, algoritmul scris pe microcontroller prevede că robotul să transmită datele provenite de la un anumit senzor, numai atunci când starea acestuia se schimbă (i.e. dacă apare un obstacol sau dacă obstacolul se apropie/depărtează). În acest sens au fost definite patru stări distincte corespunzătoare pentru grade diferite de apropiere/depărtare a obstacolelor denumite adecvat:

Ex: “SF:1” – obstacol in Stanga-Fata la o distanta de aproximativ 60 cm

“SF:2” – obstacol in Stanga-Fata la o distanta de aproximativ 40 cm

“SF:3” – obstacol in Stanga-Fata la o distanta de aproximativ 20 cm

“SF:0” – obstacol in Stanga-Fata disparut

Pentru tratarea fiecărei stări communicate pe interfață serială s-au utilizat funcții delegat conform algoritmului:

public void receptieDate(object sender, SerialDataReceivedEventArgs e)

{

sp = (SerialPort)sender;

try

{

indata = sp.ReadLine();

}

catch (Exception)

{

}

if (indata == "SF:1" + indata[4])

{

this.BeginInvoke(new set_delegat(SF1), new object[] { });

}

if (indata == "SF:2" + indata[4])

{

this.BeginInvoke(new set_delegat(SF2), new object[] { });

}

if (indata == "SF:3" + indata[4])

{

this.BeginInvoke(new set_delegat(SF3), new object[] { });

}

if (indata == "SF:0" + indata[4])

{

this.BeginInvoke(new set_delegat(SF0), new object[] { });

}

}

In cadrul acestei secvente, se citeste informatia de pe portul serial dedicat cu ajutorul instructiunii sp.ReadLine() si in functie de mesajul existent se lanseaza (sau nu) in executie o functie delegat specifica.

Obs: Instructiunea indata == "SF:1" + indata[4] asigura ca stringul citit indata contine inclusiv caracterul specific cu care se incheie orice mesaj transmis prin magistrala seriala.

Functia delegat specifica fiecarei stari contine instructiunile de setare a vizibilitatii pentru entitatile grafice asociate:

public void SF1()

{

pStangaF1.Visible = true;

pStangaF2.Visible = false;

pStangaF3.Visible = false;

pbSemafor.BackgroundImage = global::Rbtz_App.Properties.Resources.semafor_rosu;

}

Modulul conținând elementele de selecție și control pentru procesare de imagine

Figura 4.15. Modulul continand elementele de selectie si control pentru procesare de imagine

Acest modul se activează în momentul în care este lansată captura video prin apăsarea butonului “Start”. Meniul de selecție integrat include cinci tab-uri de navigare, fiecare desemnând un tip distinct de prelucare complexă de imagine:

– detecție facială

– detecție de similarități între un element grafic de referință și o imagine cadru dinamică

– detecție de siluete umane

– detecție de caractere (OCR) și recunoaștere de numere de înmatriculare auto

Tab-ul “Captură Video”

Acesta este tab-ul inițial ce se lansează odată cu începerea procesului de captura video:

//daca este selectat primul tab – Captura Video

if (ctProcesareImagine.SelectedIndex == 0)

{

Application.Idle -= detecteaza_fete;

Application.Idle -= detecteaza_similaritati;

Application.Idle -= proceseaza_cadru_detecteaza_similaritati;

Application.Idle -= detecteaza_siluete;

Application.Idle -= detecteaza_numere_inmatriculare;

cron.Stop();

imagine_de_cautat = null;

imagine_OCR = null;

Application.Idle += proceseaza_cadru;

}

Instructiunile de tip Application.Idle deservesc la managementul proceselor in cadrul aplicatiei. Astfel, in situatia in care se doreste incetarea unui proces forma instructiunii va fi Application.Idle -= nume_proces iar in situatia in care se doreste lansarea unui proces forma instructiunii este Application.Idle += nume_proces.

La nivel de interfață, tab-ul “Captura Video” oferă facilități de îmbunătățire software a cadrelor capturate de senzorul CMOS care vizează luminozitatea, contrastul și claritatea. Fiecare din cele trei ansamble grafice este alcătuit dintr-un label care sugerează numele setării, un trackBar pentru oferirea unei soluții intruitive de reglaj (operare cu mouse-ul prin click simplu sau prin hold și mișcare stânga dreapta) și un textBox care să ofere informații despre valoarea parametrului reglat. La acționarea oricăruia dintre cele trei trackBar-uri se lansează evenimente care sunt tratate corespunzător:

private void tbLuminozitate_Scroll(object sender, EventArgs e)

{

tbValoareLuminozitate.Text = tbLuminozitate.Value.ToString();

if (captura != null)

{

captura.SetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_BRIGHTNESS, luminozitate + (tbLuminozitate.Value * 20));

}

}

Variabila captura desemneaza un obiect de tip Capture specific bibliotecii de procesare de imagine Emgu.CV. Valoarea asociata acestei variabile este un cadru (frame) capturat de dispozitivul video de intrare. Functia SetCaptureProperty permite modificarea parametrilor de captura. In cazul de fata luminozitatea este modificara cu un factor obtinut prin inmultirea treptei din trackBar cu “pasul” 20. Similar au loc si celelalte setari. Este de mentionat faptul ca spre deosebire de celelalte prelucrari video aceste modificari simple de parametrii de captura nu necesita oprirea si repornirea procesului totul realizandu-se in timp real intrucat este vorba despre o functie nativa Emgu.CV.

Tab-ul “Detectie faciala”

La accesarea acestui tab se va initializa procesul de detectie faciala:

//daca este selectat al doilea tab – Detectie faciala

if (ctProcesareImagine.SelectedIndex == 1)

{

Application.Idle -= proceseaza_cadru;

Application.Idle -= detecteaza_similaritati;

Application.Idle -= proceseaza_cadru_detecteaza_similaritati;

Application.Idle -= detecteaza_siluete;

Application.Idle -= detecteaza_numere_inmatriculare;

haar = new Emgu.CV.HaarCascade("haarcascade_frontalface_default.xml");

//mesaj

tbMesajDetectieFaciala.BackColor = Color.LightSalmon;

tbMesajDetectieFaciala.Text = "Se analizeaza fluxul video…";

Application.Idle += detecteaza_fete;

cron.Stop();

imagine_de_cautat = null;

imagine_OCR = null;

cron.Start();

}

Dupa secventa in care sunt stopate celelalte procese ce vizeaza procesare video prin intermediul instructiunilor Application.Idle -= nume_proces este instantiat un obiect de tipul Emgu.CV.HaarCascade. Acest obiect desemnează exact clasificatorul introdus de metodă V&J. Inițial, un clasificator este format (învățat) prin intermediul câtorva sute de imagini eșantion care prezintă un anumit obiect (de exemplu, o față sau o mașină), numite exemple pozitive, care sunt scalate la aceeași dimensiuni (ex: 20×20), și exemple negative, – imagini arbitrare de aceeași mărime care nu conțin obiectele vizate. După învățare, acesta poate fi aplicat pe o regiune de interes (de aceeași mărime). Clasificatorul returnează "1" în cazul în care regiunea analizată include formă de interes (de exemplu, față / mașină), și "0" altfel. Pentru a caută obiectul în întreagă imagine, se poate mută fereastră de căutare pe imagine și se verifică fiecare locație prin intermediul clasificatorului. Clasificatorul este conceput astfel încât să poată fi ușor redimensionat, pentru a fi în măsură să găsească obiectele de interes la diferite scale, metodă care este mai eficientă decât redimensionarea imaginii în sine.

Noțiunea de "clasificator în cascadă" provine de la faptul că un clasificator rezultat este format din mai mulți clasificatori simpli (etape) care sunt aplicați succesiv la o regiune de interes, fie până la identificarea unei incompatibilități, fie până la încheierea cu succes a procesului iterativ și deci identificarea obiectului dorit. Clasificatorii de baza sunt de tip arbore de decizie cu cel puțin 2 frunze iar pentru cazul detectiei faciale (haar) se utilizează următorul algoritm de analiză în cascadă (Figura 4.16):

Figura 4.16. Algoritm analiza clasificator in cascada

Prin intermediul celor doua instructiuni tbMesajDetectieFaciala.BackColor = Color.LightSalmon si tbMesajDetectieFaciala.Text = "Se analizeaza fluxul video…" sunt afisate informatii corespunzatoare in text-boxul asociat tab-ului “Detectie faciala” creat in scopul comunicarii permanente a unui feedback din partea masinii si a stadiului procesului de analiza video.

Algoritmul propriu-zis utilizat pentru detectie faciala este integrat in functia detecteaza_fete:

//functie pentru detectie faciala

private void detecteaza_fete(object sender, EventArgs arg)

{

//procesul de detectie faciala

Image<Bgr, Byte> cadru_image_box_primar = captura.QueryFrame();

if (cadru_image_box_primar != null)

{

Image<Bgr, Byte> cadru_image_box = cadru_image_box_primar.Resize(pbVideo.Width, pbVideo.Height, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR);

//se converteste imaginea in grayscale

Image<Gray, byte> cadru_sursa_grayscale = cadru_image_box.Convert<Gray, byte>();

//se detecteaza fete si stocheaza intr-un vector var

var fete = cadru_sursa_grayscale.DetectHaarCascade(haar, scala_df, treshold_nr_minim_vecini_df, tip_detectie_df, new Size(25, 25))[0];

//stocheaza numarul de fete pentru analiza

numar_fete_partial.Add(fete.Length);

//se deseneaza un contur verde care incadreaza fiecare fata

foreach (var fata in fete)

{

cadru_image_box.Draw(fata.rect, new Bgr(Color.Green), 2);

}

pbVideo.Image = cadru_image_box.ToBitmap();

}

}

Are loc procesul de captura a unui frame de la dispozitivul dedicat prin intermediul functiei Emgu.CV captura.QueryFrame(), dupa care se realizeaza o scalare a imaginii capturate pentru incadrare in picture box-ul dedicat in cadrul aplicatiei (care dispune de algoritmi specifici pentru redimensionare pe diverse configuratii si rezolutii – diverse computere). Apoi se converteste imaginea redimensionata in grayscale si se lanseaza procesul de detectie a caracteristicilor Haar:

var fete = cadru_sursa_grayscale.DetectHaarCascade(haar, scala_df, treshold_nr_minim_vecini_df, tip_detectie_df, new Size(25, 25))[0];

Parametrii specifici acestei functii sunt preluati din interfata grafica:

Exemplu scala:

private void tbScala_Scroll(object sender, EventArgs e)

{

tbValoareScala.Text = tbScala.Value.ToString();

if (captura != null)

{

Application.Idle -= detecteaza_fete;

scala_df = 1 + (Convert.ToDouble(tbScala.Value) / 10);

Application.Idle += detecteaza_fete;

}

}

Pentru acuratetea calculului numarului de fete detectate s-a utilizat un algoritm bazat pe ponderea numerelor de fete detectate intr-o unitate de timp fixata. Astfel numarul parial de fete detectat la fiecare moment de timp este adaugat intr-o lista de tip int numar_fete_partial.Add(fete.Length). O data la doua secunde sunt sortate datele din aceasta lista descrescator dupa numarul de aparitii in lista. Este returnata apoi valoarea corespunzatoare celui mai mare numar de aparitii care reflecta numarul real de fete existente in cadru.

if (ctProcesareImagine.SelectedIndex == 1)

{

var query = (from val in numar_fete_partial group val by val into g orderby g.Count() descending select g.Key).First();

numar_fete_partial.Clear();

if (Convert.ToInt32(query) != 0)

{

tbMesajDetectieFaciala.BackColor = Color.LightGreen;

tbMesajDetectieFaciala.Text = "Numar de fete detectate: " + query.ToString();

}

else

{

tbMesajDetectieFaciala.BackColor = Color.Gold;

tbMesajDetectieFaciala.Text = "Nu au fost detectate fete!";

}

}

Tab-ul “Detecție similarități”

La accesarea acestui tab se va initializa procesul de detecție similarități:

//daca este selectat al treilea tab – Detectie similaritati

if (ctProcesareImagine.SelectedIndex == 2)

{

Application.Idle -= proceseaza_cadru;

Application.Idle -= detecteaza_fete;

Application.Idle -= detecteaza_siluete;

Application.Idle -= detecteaza_numere_inmatriculare;

cron.Stop();

tbDSImDeGasit.Text = "";

imagine_OCR = null;

cron.Start();

//mesaj

tbMesajDetectieSimilaritati.BackColor = Color.LightSalmon;

tbMesajDetectieSimilaritati.Text = "Selectati imaginea de cautat!";

//continuare streaming video pentru capturarea imaginii de cautat

Application.Idle += proceseaza_cadru_detecteaza_similaritati;

}

Conventia de exprimare folosita este urmatoarea:

Imagine de cautat – obiectul/obiectele sau elementele grafice model, plasate in imagine conventionala ce se doresc identificate intr-un context

Imagine cadru – imaginea in care se va realiza procesul de cautare si identificare similaritati, imaginea context (fluxul video capturat).

Aplicația este proiectată astfel încât să poată opera cu două surse din care să se poată prelua imaginea sau obiectul grafic de căutat (într-o altă imagine): captura a unui frame din fluxul video furnizat de camera robot sau altă imagine statică de referință încărcată local din memoria PC-ului.

La accesarea acestui tab se trece în starea specificării imaginii de referință care se poate realiza în două moduri:

– prin apasarea butonului “Captureaza” care are ca efect preluarea imaginii din fluxul video furnizat

if (imagine_de_cautat == null)

{

Image<Bgr, Byte> cadru_image_box_primar = captura.QueryFrame();

if (cadru_image_box_primar != null)

{

//schimba text buton

bCaptureazaDetectieSimilaritati.Text = "Actualizati imaginea de cautat";

//mesaj

tbMesajDetectieSimilaritati.BackColor = Color.LightSalmon;

tbMesajDetectieSimilaritati.Text = "Se analizeaza fluxul video…";

cbPuncteInteres.Enabled = true;

cbLiniiSimilaritate.Enabled = true;

cbDetectieSimilaritati.Enabled = true;

tbDetectieSimilaritati.Enabled = true;

//captureaza imagine de cautat din fluxul video

imagine_de_cautat = cadru_image_box_primar.Resize(pbVideo.Width, pbVideo.Height, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR);

//modifica layout

pbVideo.BackgroundImage = null;

pbVideo.BackColor = Color.Black;

Application.Idle -= proceseaza_cadru_detecteaza_similaritati;

Application.Idle += detecteaza_similaritati;

}

}

else

{

Application.Idle -= detecteaza_similaritati;

Application.Idle += proceseaza_cadru_detecteaza_similaritati;

imagine_de_cautat = null;

bCaptureazaDetectieSimilaritati.Text = "Captureaza";

tbDSImDeGasit.Text = "";

//mesaj

tbMesajDetectieSimilaritati.BackColor = Color.LightSalmon;

tbMesajDetectieSimilaritati.Text = "Selectati imaginea de cautat!";

cbPuncteInteres.Enabled = false;

cbLiniiSimilaritate.Enabled = false;

cbDetectieSimilaritati.Enabled = false;

tbDetectieSimilaritati.Enabled = false;

}

}

În această faza are loc o sevcenta de preprocesare a imaginii capturate care vizează redimensionarea pentru încadrare în picture box-ul asociat și o secvență de adăugare informații în casetă text dedicată.

Este de menționat că funcționalitatea butonului se schimbă după capturarea imaginii de căutat, la o nouă apăsare reintrandu-se în starea selecției sursei imaginii de referință.

– prin apasarea butonului “…” care deschide un Dialog de tip OpenFileDialog care permite browsing in computer pentru selectia imaginii de cautat.

DialogResult dr = ofdDSImagineDeCautat.ShowDialog();

if (dr == DialogResult.OK || dr == DialogResult.Yes)

{

tbDSImDeGasit.Text = ofdDSImagineDeCautat.FileName;

}

else

{

return;

}

try

{

imagine_de_cautat = new Image<Bgr, Byte>(tbDSImDeGasit.Text);

}

catch

{

MessageBox.Show("Incarcarea nu a avut loc cu succes. Reincercati!");

imagine_de_cautat = null;

return;

}

Algoritmul propriu-zis utilizat pentru detectie similaritati este integrat in functia detecteaza_similaritati al carei mod de functionare este detaliat la nivelul comment-urilor asociate codului sursa din sectiunea “Anexe”.

Variatia parametrilor ce se regasesc in interfata grafica asociata tab-ului “Detectie similaritati: are ca efect modificarea functiilor de prelucrare Emgu.CV utilizare in interiorul algoritmului de detectie similaritati:

Exemplu: Numar vecini

Acest parametru influenteaza modul de formare a matricei de indicii a descriptorilor care ofera informatii despre punctele de interes:

m_indicii = new Matrix<int>(md_imagine_cadru.Rows, numar_vecini_ds);

Modificarea valorii acestui parametru din interfață are că efect ridicarea unui eveniment corespunzător care oprește procesul de detecție, modifică parametrul conform intenției utilizatorului și apoi repornește procesul de detecție care va avea un comportament diferit. Scalarea trackbar-ului se face în mod dinamic la selecția unuia dintre parametrii specifici algoritmului:

if (cbDetectieSimilaritati.SelectedIndex == cbDetectieSimilaritati.Items.IndexOf("Numar vecini"))

{

tbDetectieSimilaritati.Minimum = 2;

tbDetectieSimilaritati.Maximum = 10;

tbDetectieSimilaritati.Value = numar_vecini_ds;

tbValoareDetectieSimilaritati.Text = numar_vecini_ds.ToString();

tbDetectieSimilaritati.Focus();

}

Evenimentul urmarit in vederea schimbari valorilor parametrilor este tbDetectieSimilaritati_Scroll(object sender, EventArgs e):

if (cbDetectieSimilaritati.SelectedIndex == cbDetectieSimilaritati.Items.IndexOf("Numar vecini"))

{

if (captura != null)

{

Application.Idle -= detecteaza_similaritati;

numar_vecini_ds = tbDetectieSimilaritati.Value;

tbValoareDetectieSimilaritati.Text = numar_vecini_ds.ToString();

Application.Idle += detecteaza_similaritati;

}

}

Tab-ul “Detecție siluete”

La accesarea acestui tab se va initializa procesul de detectie siluete:

//daca este selectat al patrulea tab – Detectie siluete

if (ctProcesareImagine.SelectedIndex == 3)

{

Application.Idle -= proceseaza_cadru;

Application.Idle -= detecteaza_fete;

Application.Idle -= detecteaza_similaritati;

Application.Idle -= proceseaza_cadru_detecteaza_similaritati;

Application.Idle -= detecteaza_numere_inmatriculare;

cron.Stop();

imagine_de_cautat = null;

imagine_OCR = null;

chDetectieSiluete.Series["Numar siluete"].Points.AddXY(DateTime.Now.ToLongTimeString(), 0);

cron.Start();

Application.Idle += detecteaza_siluete;

}

La nivelul acestui tab a fost introdus și un grafic ce se autocompleteaza în timp real și care oferă o imagine de ansamblu a numărului de siluete detectate în intervalul de timp în care robotul rulează această funcție. Asfel, o dată la două secunde are loc citirea numărului de siluete detectate prin analiză ponderilor numerelor de siluete din vectorul care le memorează și sunt plasate în grafic valorile pentru care se constată cea mai ridicată pondere la momentul respectiv:

if (ctProcesareImagine.SelectedIndex == 3)

{

var query = (from val in numar_siluete_partial group val by val into g orderby g.Count() descending select g.Key).First();

numar_siluete_partial.Clear();

if (Convert.ToInt32(query) != 0)

{

tbMesajDetectieSiluete.BackColor = Color.LightGreen;

tbMesajDetectieSiluete.Text = "Numar de siluete detectate: " + query.ToString();

chDetectieSiluete.Series["Numar siluete"].Points.AddXY(DateTime.Now.ToLongTimeString(), query);

}

else

{

tbMesajDetectieSiluete.BackColor = Color.Gold;

tbMesajDetectieSiluete.Text = "Nu au fost detectate siluete!";

chDetectieSiluete.Series["Numar siluete"].Points.AddXY(DateTime.Now.ToLongTimeString(), 0);

}

}

Scalarea graficului se face în mod automat pe măsură ce noi valori sunt adăugate (la fiecare două secunde). Această abordare a fost introdusă cu scopul monitorizării fluxului de persoane într-un anumit cadru video, permițând utilizatorilor să folosească platforma în scopuri de supraveghere video.

Algoritmul propriu-zis utilizat pentru detecție de siluete este integrat în funcția detectează_siluete care oferă atât un mod de procesare utilizând resursele plăcii video integrate sau, în cazul în care această nu este agreată de funcțiile dedicate ale bibliotecii Emgu.CV, se trece automat în modul de procesare convențional utilizând CPU:

//verifica daca exista procesor grafic (GPU) care sa fie compatibil cu procesul de detectie siluete

if (GpuInvoke.HasCuda)

{

//versiunea GPU

using (GpuHOGDescriptor des = new GpuHOGDescriptor())

{

des.SetSVMDetector(GpuHOGDescriptor.GetDefaultPeopleDetector());

using (GpuImage<Bgr, Byte> gpuImg = new GpuImage<Bgr, byte>(cadru_image_box))

using (GpuImage<Bgra, Byte> gpuBgra = gpuImg.Convert<Bgra, Byte>())

{

siluete = des.DetectMultiScale(gpuBgra);

}

}

}

else

{

//versiunea CPU

using (HOGDescriptor des = new HOGDescriptor())

{

des.SetSVMDetector(HOGDescriptor.GetDefaultPeopleDetector());

siluete = des.DetectMultiScale(cadru_image_box);

}

}

Tipul de data GpuHOGDescriptor este utilizat pentru a creea un descriptor HOG in modul de functionare GPU iar HOGDescriptor este tipul de data care defineste acelasi lucru in modul CPU. Dupa initializarea detectorului SVM prin des.SetSVMDetector se apeleaza des.DetectMultiScale functie care extrage formatiunile de tip silueta umana indiferent la scala la care acestea apar in imagine. Este de mentionat faptul ca, de obicei, in aplicatii de supraveghere video a unui anumit obiectiv cu camera fixa se utilizeaza conceptul de detectie la aceeasi scala, luand in calcul faptul ca imaginea cadru este ajustata optic in acest sens. Insa, in cazul de fata, fiind vorba de o camera video mobila, s-a optat pentru o detectie multiscala.

Tab-ul “Detecție caractere”

La accesarea acestui tab se va initializa procesul de detectie caractere:

//daca este selectat al cincilea tab – Detectie caractere

if (ctProcesareImagine.SelectedIndex == 4)

{

Application.Idle -= proceseaza_cadru;

Application.Idle -= detecteaza_fete;

Application.Idle -= detecteaza_similaritati;

Application.Idle -= proceseaza_cadru_detecteaza_similaritati;

Application.Idle -= detecteaza_siluete;

cron.Stop();

imagine_de_cautat = null;

//daca este selectat modul dinamic

if (ctDetectieCaractere.SelectedIndex == 0)

{

tbMesajDetectieCaractere.BackColor = Color.LightSalmon;

tbMesajDetectieCaractere.Text = "Se analizeaza fluxul video…";

Application.Idle += detecteaza_numere_inmatriculare;

cron.Start();

}

//daca este selectat modul static

if (ctDetectieCaractere.SelectedIndex == 1)

{

Application.Idle -= detecteaza_numere_inmatriculare;

cron.Stop();

tbMesajDetectieCaractere.BackColor = Color.LightSalmon;

tbMesajDetectieCaractere.Text = "Selectati imaginea sursa!";

}

}

Aplicația oferă două modalități de abordare pentru detecția optică caracterelor: un mod static în care imaginea este preluată manual de utilizator dintr-o locație a HDD-ului sau dinamic în care fluxul video furnizat de elementul de captura al robotului reprezintă sursă de analiză și detecție. În ambele situații însă algoritmul rulat este detecteaza_numere_inmatriculare.

La nivel de implementare, algoritmul propus pentru extragerea regiunii aferente placutei de inmatriculare este structurat in trei secvente:

Aplicarea metodei Canny pentru evidentierea tuturor contururilor din imaginea grayscale

Pentru aceasta etapa au fost utilizare functii predefinite ale bibliotecii Emgu.CV:

//setare parametrii metoda Canny – threshold1 = 100, threshold2 = 50, Diafragma 3

CvInvoke.cvCanny(gray, canny, 100, 50, 3);

//memorare contururi in variabila stor

Contour<Point> contururi = canny.FindContours(Emgu.CV.CvEnum.CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_SIMPLE, Emgu.CV.CvEnum.RETR_TYPE.CV_RETR_TREE, stor);

Generic imaginea obtinuta dupa aplicarea acestei metode este prezentata in figura 4.17:

Figura 4.17. Filtrare Canny

Parcurgerea contururilor imaginii obtinute pe orizontala si apoi pe vericala pentru fiecare putentiala regiune orizontala identificata pentru studierea alternantelor de contrast

//parcurgere contururi orizontale

for (; contururi != null; contururi = contururi.HNext)

int numar_copii = determina_numarul_contururilor_copil(contururi);

Functiile predefinite HNext si respectiv VNext functioneaza conform diagramei prezentate in figura 4.18:

Figura 4.18 .Diagrama functionare functii HNext si VNext

Pentru fiecare contur orizontal identificat se numara variatiunile de contrast verticale care apar in ideea compararii ulterioare pentru deducerea maximului acestui parametru:

//functie pentru identificarea formei numarului de inmatriculare prin parcurgerea conturului

private static int determina_numarul_contururilor_copil(Contour<Point> contururi)

{

//se detecteaza liniile verticale de contur

Contour<Point> copil = contururi.VNext;

if (copil == null) return 0;

int contor = 0;

while (copil != null)

{

//se parcurge conturul pe liniile orizontale si se incrementeaza contorul

contor++;

copil = copil.HNext;

}

return contor;

}

Comparatia are loc la nivelul urmatorului pas iar restrictiile impuse realizeaza filtrarea concreta:

//daca nu contine nici un copil, atunci nu este o regiune de tip numar de inmatriculare

if (numar_copii == 0) continue;

//prima validare a ariei asociate regiunii candidate

if (contururi.Area > 400)

{

if (numar_copii < 3)

{

//daca un contur are mai putin de 3 copii nu este o regiune de tip numar de inmatriculare luand in calcul faptul ca un numar de inmatriculare are minim 3 caractere

//in aceasta situatie insa este important sa se examineze fiecare dintre copii pentru a detecta daca vreunul dintre ei defineste un numar de inmatriculare

gaseste_numar_inmatriculare(contururi.VNext, imagine_grayscale, imagine_canny, imagini_numere_inmatriculare, imagini_numere_inmatriculare_filtrate, regiuni_numere_inmatriculare, numere);

continue;

}

Extragerea regiunilor rectangulare corespunzatoare potentialelor placute de inmatriculare si filtrarea acestora prin metoda raportului intre latime si lungime

Funcția de extracție a unei regiuni rectangulare pe baza coordonatelor celor patru colțuri este integrată în biblioteca Emgu.CV și funcționează conform principiilor explicate în secțiunea anterioară:

MCvBox2D box = contururi.GetMinAreaRect();

Înainte de o comparație numerică pentru validarea dimensiunii regiunilor analizate, algoritmul realizează rotirea acestora pentru o percepție cât mai firească, în cazul în care zonele candidate apar în cadru la unghiuri mai mari de 45˚ și respectiv mai mici de -45˚:

//rotire box

if (box.angle < -45.0)

{

float tmp = box.size.Width;

box.size.Width = box.size.Height;

box.size.Height = tmp;

box.angle += 90.0f;

}

else if (box.angle > 45.0)

{

float tmp = box.size.Width;

box.size.Width = box.size.Height;

box.size.Height = tmp;

box.angle -= 90.0f;

}

În urma analizei experimentale s-a dedus că plajă raporturilor lățime / înălțime pentru majoritatea formatelor de numere de înmatriculare se situează între valorile 3.0 și 6.0:

double raport_latime_inaltime = (double)box.size.Width / box.size.Height;

if (!(3.0 < raport_latime_inaltime && raport_latime_inaltime < 6.0))

{

//se analizeaza dimensiunea numarului de inmatriculare

//daca raportul latime pe inaltime nu se regaseste intre anumite valori nu este vorba despre un numar de inmatriculare

//in aceasta situatie insa este important sa se examineze fiecare dintre copii pentru a detecta daca vreunul dintre ei defineste un numar de inmatriculare

Contour<Point> copil = contururi.VNext;

if (copil != null)

gaseste_numar_inmatriculare(copil, imagine_grayscale, imagine_canny, imagini_numere_inmatriculare, imagini_numere_inmatriculare_filtrate, regiuni_numere_inmatriculare, numere);

continue;

}

Faza de segmentare este tratată secvențial prin parcurgerea etapelor de conversie în grayscale, binarizare și extragere a contururilor. Este de menționat faptul că metodă Canny de extracție a contururilor lucrează conform principiului explicat, și anume prin verificarea alternanțelor liniare în imaginea binarizata:

using (Image<Gray, Byte> tmp1 = imagine_grayscale.Copy(box))

//redimensionare numar de inmatriculare pentru prelucrare optimala cu tesseract

using (Image<Gray, Byte> tmp2 = tmp1.Resize(240, 180, Emgu.CV.CvEnum.INTER.CV_INTER_CUBIC, true))

using (Image<Gray, Byte> masca_placuta = new Image<Gray, byte>(placuta.Size))

using (Image<Gray, Byte> canny_placuta = placuta.Canny(threshold_contur, threshold_unificare_contur))

Sunt parcurse apoi contururile obtinute in vederea extragerii zonelor rectangulare asociate fiecarui caracter din numarul de inmatriculare:

//parcurgere contururi orizontale

for (Contour<Point> contururi = canny_placuta.FindContours(Emgu.CV.CvEnum.CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_SIMPLE, Emgu.CV.CvEnum.RETR_TYPE.CV_RETR_EXTERNAL, stor); contururi != null; contururi = contururi.HNext)

{

Rectangle rect = contururi.BoundingRectangle;

}

Odata obtinute dreptunghiurile aferente caracterelor din cadrul numarului de inmatriculare se ruleaza motorul OCR al bibliotecii Emgu.CV, fondat pe celebrul algoritm Tesseract dezvoltat de HP in anii ’90 si perfectionat ulterior de multe alte companii de profil precum Google, Apache etc.

Tesseract.Charactor[] cuvinte;

StringBuilder strBuilder = new StringBuilder();

using (Image<Gray, Byte> tmp = placuta_filtrata.Clone())

{

tess.Recognize(tmp);

cuvinte = tess.GetCharactors();

if (cuvinte.Length == 0) continue;

for (int i = 0; i < cuvinte.Length; i++)

{

strBuilder.Append(cuvinte[i].Text);

}

}

numere.Add(strBuilder.ToString());

imagini_numere_inmatriculare.Add(placuta);

imagini_numere_inmatriculare_filtrate.Add(placuta_filtrata);

regiuni_numere_inmatriculare.Add(box);

Vectorul Tesseract.Charactor[] cuvinte include toate sabloanele pentru caractere integrate in biblioteca Emgu.CV. Prin metoda tess.GetCharactors() sunt comparate regiunile rectangulare asociate placutei de inmatriculare care contin caractere cu sabloanele existente. Fiecare caracter identificat in format masina (char) este adaugat in StringBuilder strBuilder care la sfarsit va contine sirul de caractere format din rezultatul analizei OCR.

Pentru testarea algoritmului și pentru ajustarea parametrilor în sensul optimizării procesului de identificare a plăcuței de înmatriculare și respectiv extragerea caracterelor alfanumerice a fost dezvoltat un stand de test la nivelul căruia robotul mobil a fost așezat în față unui monitor pe care a fost rulată o serie de imagini cu mașini cu plăcute de înmatriculare vizibile dar supuse mai multor condiții de iluminare, contrast, rotație etc (Figura 4.19).

Figura 4.19. Stand de test algoritm OCR

Pe monitorul conectat la un calculator desktop au fost rulate sub formă de slideshow (5 sec per imagine) aproximativ douăzeci de imagini cu autovehicule având numere de înmatriculare vizibile. Robotul a fost conectat wireless la un laptop prin aplicația dezvoltată conform algoritmului descris. Au fost comparate rezultatele furnizate de aplicație în raport cu realele combinații de caractere alfanumerice aferente plăcuțelor de înmatriculare din imagini. Raționamentul de comparație stabilit este relativ simplist. Considerând că numerele de înmatriculare convenționale conțin șapte caractere în total și două spații, deci nouă segmente, pentru fiecare fiecare segment s-au alocat 10 pct. În situația în care există match algoritmul primește 10 pct. per segment, iar în caz contrar sunt scăzute 10 pct. Astfel se calculează eroarea și este apoi transformată în procente. Totodată pentru fiecare caracter adăugat în mod fictiv, eronat, la lista reală de caractere detectate au fost substrase 10 pct. Procesul a fost reluat în mod repetitiv pentru mai multe angulații ale robotului în raport cu monitorul atât în plan vertical cât și orizontal, precum și pentru rotații în sensul/ împotriva sensului aceor de ceasornic între cele două entități.

Conform principiului de evaluare prezentat au fost calculate erori parțiale ale detectiei OCR (Tabelul 4.1):

4.2.4 Schema bloc software a aplicației PC

Figura 4.16. Schema bloc software a aplicatiei PC

4.3 Rezultate si ghid de utilizare

Prin asamblarea modulelor hardware si software a fost atins scopul stabilit, și anume realizarea unui sistem robot de tip “Platformă wireless robotizată pentru captură și analiză de imagine în timp real” (Figura 4.17).

Figura 4.17. Robot de tip “Platformă wireless robotizată pentru captură și analiză de imagine în timp real”

Funcționalitatea acestui sistem se rezumă la capacitatea sa de a transmite wireless imagini video în timp real din zone periculoase sau greu accesibile omului, fiind controlat de un operator avizat, prin intermediul unei interfețe grafice cu utilizatorul cât mai simplă.

Controlul poate fi exercitat atât asupra șasiului robotului pe direcțiile înainte, înapoi, la stânga, la dreapta, cât și la nivelul brațului mobil cu două grade de libertate pe care se regăsește montată camera video, pe direcțiile rotire la stânga, rotire la dreapta, rotire în sus, rotire în jos (Figura 4.18).

Figura 4.18. Capacitațile locomotorii ale șasiului robot și ale brațului mobil

Pe lângă facilitățile de control al robotului interfața grafică cu utilizatorul integrează și imaginea video provenită de la camera aferentă robotului, precum și informația de la senzorii de proximitate, redată într-o formă grafică (Figura 4.19).

Figura 4.19. Interfata grafica cu utilizatorul

Aplicația oferă și un mod full-screen caracterizat de o zonă mult mai mare asociată imaginii video pentru o experiență cât mai reală iar informația grafică de la senzori și elementele de control au fost redimensionate și repozitionate pentru exploatarea la maximim a rezoluției display-ului (Figura 4.20).

Figura 4.20. Modul Full-Screen al aplicației

Ghid de utilizare

Etape de bază pentru atingerea modului operational:

Pas 1: Conectarea modulului de emisie/recepție la PC prin intermediul USB (Fig. 4.21).

Pas 2: Conectarea dispozitivului de captură video la PC prin intermediul USB (Fig. 4.22)*

Figura 4.21. Conectarea modulului wireless la PC prin USB Figura 4.22. Conectarea disp.

captura

Pas 3: Interconectarea receptorului de semnal video și a dispozitivului de captură prin intermediul conectorului RCA (Figura 4.23).*

Pas 4: Alimentarea receptorului de semnal video de la rețeaua de energie electrică prin intermediul sursei de tensiune incluse 12V / 1A (Figura 4.24).

Figura 4.23. Interonectarea receptorului video și a disp. cap. Figura 4.24.Alimentare receptor semnal

Pas 5: Pornirea robotului și a transmițătorului video prin apăsarea celor două întrerupătoare ce se regasesc pe lateralele stâng/drept ale robotului (Figura 4.25).

Figura 4.25. Întrerupătoarele de pornire a robotului

Pas 6: Lansarea aplicației “RobotExplorer.exe”.

Pas 7: Setarea parametrilor corecți de comunicație serială și apăsarea butonului “Inițializează conexiunea”.

* Pașii 2 și 3 pot lipsi în situația în care nu se dorește redarea semnalului video pe PC ci pe un dispozitiv auxiliar (ex: TV). În acest caz conectarea mufelor RCA se va realiza direct cu dispozitivul auxiliar.

Odata atins modul operational, se pot distinge cu usurință cele patru module ale aplicației:

– modulul de control

– modulul video

– modulul aferent informației de la senzorii de proximitate

– modulul aferent functiilor de procesare de imagine

În cadrul modulului de control se regăsesc următoarele entități cu funționalități dedicate:

– butonul “Inainte” – la apăsarea sa robotul se va deplasa înainte

– butonul “Inapoi” – la apăsarea sa robotul se va deplasa înapoi

– butonul “Stânga” – la apăsarea sa robotul va executa viraj la stânga

– butonul “Dreapta” – la apăsarea sa robotul va executa viraj la dreapta

– butonul “Stop” – la apăsarea sa robotul va înceta orice mișcare la nivelul șasiului

– butonul “Auto” – la apăsarea sa robotul va intra în modul automat de explorare în care va adopta singur deciziile cu privire la mișcarea șasiului pe baza informației de la senzorii de proximitate

– butonul “Viteza +” – la apăsarea sa viteza de mișcare a robotului va fi incrementată 83

– butonul “Viteza -” – la apăsarea sa viteza de mișcare a robotului va fi decrementată

– butonul “Reset” – la apăsarea sa bratul mobil revine la poziția inițială

– textbox-ul “Viteza” – indică treapta de viteză curentă a robotului

– scroll-ul vertical – modifică orientarea camerei video de pe bratul mobil pe verticală

– scroll-ul orizontal – modifică orientarea camerei video de pe brațul mobil pe orizontală

În cadrul modulului video se regăsesc următoarele entități cu funționalități dedicate:

– combobox-ul “Sursa video” care conține toate dispozitivele de captură video disponibile pe respectivul PC

– butonul “Start” – la apăsarea sa se va începe redarea semnalului video recepționat prin intermediul dispozitivului selectat în prealabil din combobox-ul dedicat.

– butonul “Stop” – la apăsarea sa se va sista redarea semnalului video recepționat prin intermediul dispozitivului selectat în prealabil din combobox-ul dedicat.

– butonul “Refresh” – la apăsarea sa se va actualiza lista dispozitivelor de captură video conectate la respectivul PC.

– butonul de fotografiere (aparatul foto) – la apăsarea sa se va captura imaginea curentă surprinsă de camera video și se va salva în directorul “Captura” din “Rbtz_App 2.0/Bin/Debug”.

– chenarul aferent imaginii video – la executarea unui dublu-click pe suprafața acestuia se trece în modul full-screen din care se poate revenii prin aceeași comandă executată pe suprafata noului chenar.

În cadrul modulului de procesare de imagine, care se va activă numai după lansarea procesului de captura video prin apăsarea butonului “Start” din cadrul modulului video, se regăsesc următoarele entități cu funcționalități dedicate:

– tabcontrol-ul “Procesare imagine:” care include toate opțiunile de procesare de imagine sub formă unor tab-uri, fiecare dintre acestea dispunând de proprii parametri. La navigarea prin tab-uri se lansează automat procesele video asociate.

Tab-ul “Captura video”

– perechea trackbar + textbox “Luminozitate” – la modificarea poziției cursorului din trackbar se va modifică luminozitatea cadrelor capturate iar treaptă curentă a acestui parametru va fi afișată în textbox-ul asociat.

– perechea trackbar + textbox “Contrast” – la modificarea poziției cursorului din trackbar se va modifică contrastul cadrelor capturate iar treaptă curentă a acestui parametru va fi afișată în textbox-ul asociat.

– perechea trackbar + textbox “Claritate” – la modificarea poziției cursorului din trackbar se va modifică claritatea cadrelor capturate iar treaptă curentă a acestui parametru va fi afișată în textbox-ul asociat.

Tab-ul “Detectie faciala”

– perechea trackbar + textbox “Scala” – la modificarea poziției cursorului din trackbar se va modifică plajă de scalare pentru identificarea modelelor faciale iar treaptă curentă a acestui parametru va fi afișată în textbox-ul asociat (ex: dacă parametrul “Scala” ia valoarea minimă – 1 – se va aplică o filtrare ridicată a diemensiunii în procesul de detecție de fete astfel încât vor fi recunoscute numai fete cu aproximativ aceeași dimensiune).

– perechea trackbar + textbox “Nr. min. vecini” – la modificarea poziției cursorului din trackbar procesul de analiză a imaginii devine mai sensibil în vecinătatea unui model deja identificat iar treaptă curentă a acestui parametru va fi afișată în textbox-ul asociat (ex: dacă parametrul “Nr. min vecini” ia valoarea minimă – 1 – numărul de fete detectate va fi mai mare dacă scenariul este adecvat (există mai multe persoane expuse în cadru) sau rată erorilor crește dacă scenariul nu necesită analiză ridicată a vecinătății).

– perechea de radiobutton-uri “Fidelitate ridicata” și respectiv “Fidelitate scazuta” – la selectarea uneia dintre aceste două opțiuni, complexitatea procesului de detecție este modificată, eveniment care influențează performanțele CPU sau GPU după caz.

– textbox-ul cu rol informativ – afișează informații în timp real despre evoluția procesului de detecție facială.

Tab-ul “Detectie similaritati”

– butonul “Captureaza” – la apăsarea acestui buton este preluat cadul curent din fluxul video capturat pentru a deservi drept imagine de căutat (referință) iar procesul de analiză comparativă pentru detecție de similarități va fi lansat.

– perechea textbox + buton “Alegeti imaginea de gasit” – la apăsarea butonului “…” se lansează procesul de selecție a unui fișier de tip imagine care va deservi drept imagine de căutat (referință) în situația în care nu se optează pentru capturarea dinamică a acesteia detaliată în alineatul anterior. Procesul de analiză comparativă pentru detecție de similarități va fi lansat. Textbox-ul asociat va afișa path-ul imaginii selectate drept model.- chackbox-ul “Afiseaza puncte interes” – dacă este bifat acest checkbox se vor evidenția grafic elementele care constituie puncte de interes în imaginea de căutat (referință) și imaginea cadru.

– chackbox-ul “Afiseaza linii de similaritate” – dacă este bifat acest checkbox se vor evidenția grafic conexiunile între punctele de interes identificate cu un grad ridicat de importantă, prin intermediul unor linii de culoare albastră.

– perechea compobox + trackbar + textbox – la selectarea unuia dintre parametrii menționați în lista combobox-ului se vor actualiza în mod automat valoarea minimă, maximă și curentă (indicată de cursor) ale track-bar-ului și implicit valoarea curentă va fi afișată numeric în cadrul textbox-ului.

“Nr. vecini” – la modificarea poziției cursorului din trackbar procesul de analiză a imaginii devine mai sensibil în vecinătatea unui model deja identificat iar treaptă curentă a acestui parametru va fi afișată în textbox-ul asociat.

“Threshold unicitate” – cu cât acesta este mai mare cu atât sensibilitatea de detecție crește însă crește și rată erorii, motiv pentru care este indicat că acest threshold să fie bine stabilit după o analiză vizuală prealabilă (condiții de iluminare, mediu, nivel de detaliu).

“Increment de scala” – la modificarea poziției cursorului din trackbar se va modifică plajă de scalare pentru identificarea similarităților iar treaptă curentă a acestui parametru va fi afișată în textbox-ul asociat (ex: dacă parametrul “Increment de scala” ia valoarea minimă – 1,1 – se va aplică o filtrare ridicată a diemensiunii în procesul de detecție astfel încât vor fi recunoscute numai elemente cu aproximativ aceeași dimensiune).

“Segmente de rotatie” – acest parametru specifică sensibilitatea la rotație a algoritmului de detecție a similarităților. Cu cât este mai mare cu atât sensibilitatea la rotație crește.

– textbox-ul cu rol informativ – afiseaza informatii in timp real despre evolutia procesului de detectie de similaritati.

Tab-ul “Detecție siluete”

– graficul de prezența – este o formă de reprezentare grafică a numărului de siluete detectate la un anumit moment de timp. Graficul se scaleaza automat împreună cu informația temporală.

– textbox-ul cu rol informativ – afișează informații în timp real despre evoluția procesului de detecție de siluete.

Tab-ul “Detectie caractere”

– tabcontrol-ul “Detectie caractere” – care include cele doua optiuni de procesare de imagine cu detectie de caractere sub forma unor butoane “Dinamic” si “Static”. La navigarea prin tab-uri se lanseaza automat procesele video asociate.

– butonul “Dinamic” – la apăsarea acestui buton este selectat modul de procesare cu flux video continuu pentru extragerea numerelor de înmatriculare și returnarea șirului de caractere. Interfață tab-ului este configurată în consecință.

– perechea compobox + trackbar + textbox – la selectarea unuia dintre parametrii menționați în lista combobox-ului se vor actualiza în mod automat valoarea minimă, maximă și curentă (indicată de cursor) ale track-bar-ului și implicit valoarea curentă va fi afișată numeric în cadrul textbox-ului.

“Threshold binarizare” – la modificarea poziției cursorului din trackbar este afișată imaginea sursă binarizata pe baza nivelului selectat care are repercursiuni directe asupra procesului de extragere a plăcuțelor de înmatriculare din imagine. În urmă ajustării făcute trebuie că numerele de înmatriculare să iasă cât mai bine în evidență în condițiile de iluminare, mediu, detaliu existente.

“Threshold contur” – la modificarea poziției cursorului din trackbar sunt afișate contururile din imaginea sursă binarizata pe baza nivelului selectat care are repercursiuni directe asupra procesului de extragere a plăcuțelor de înmatriculare din imagine. În urmă ajustării făcute trebuie că numerele de înmatriculare să iasă cât mai bine în evidență în condițiile de iluminare, mediu, detaliu existente situație plauzibilă în cazul în care contururile elementelor sunt extrase cât mai corect.

“Threshold unificare contur” – la modificarea poziției cursorului din trackbar sunt afișate contururile din imaginea sursă rezultate în urmă unificării cu alte contururi. Parametrul poate fi asociat cu o formă de detaliere / simplificare a liniilor de contur extrase deja prin modificarea parametrului anterior menționat.

– butonul “Static” – la apăsarea acestui buton este selectat modul de procesare cu imagine statică. Interfață tab-ului este configurată în consecință.

*notă: în această situație textul va fi extras numai dacă apare pe fundal unicolor iar caracterele nu prezintă variațiuni majore de culoare. Acest proces necesită de cele mai multe ori o preformatare a imaginii sursă.

– perechea textbox + buton “Alegeti imaginea” – la apăsarea butonului “…” se lansează procesul de selecție a unui fișier de tip imagine care va deservi drept imagine sursă pentru extragerea de caractere.

– textbox-ul cu rol informativ – afișează informații în timp real despre evoluția procesului de detecție de caractere precum și strîng-urile extrase.

Cap. 5. Concluzii

Problematica proiectării și implementării unui sistem robot de tip “Platforma wireless robotizata pentru captura si analiza de imagine in timp real” se poate rezuma la respectarea câtorva principii esențiale care vizează atât structura hardware cât și cea software.

Dintre ideile de bază care au fost considerate în faza de proiectare și implementare hardware se pot menționa:

– arhitectură hardware compactă dimensionată strict pentru asigurarea funcțiilor de bază

– consum redus pentru menșinerea unei autonomii ridicate

– modul senzorial performant pentru o informație perimetrală cât mai precisă

– elemente de acționare ferme pentru un control optimal

– constucție robustă și ergonomică

La nivelul etapei de proiectare hardware, alegerea componentelor și subansamblelor a costituit un moment critic, întrucât s-a dorit respectarea uni raport optim între performanță, calitate, fiabilitate, dimensiuni, consum și preț. Totodată dimensionarea tuturor elementelor de acționare și a capacităților de procesare a presupus studiul și analiza unor proiecte asemănătoare în sensul dobândirii unor cunoștiințe esențiale pe baza cărora au putut fi efectuate simulări și calcule apriorice pentru atingerea obiectuvului propus. Implementarea hardware a constat atât în interconectarea modulelor electronice pentru care s-a optat în faza de proiectare cât și elaborarea unei soluții pentru structura fizică a robotului. Ținând cont de domeniul interdisciplinar necesar implementării unei asemenea aplicații, în această etapă au fost dobândite cunoștiințe substanțiale din domenii conexe.

Dintre caracteristicile principale luate în calcul pentru proiectarea și implementarea software se pot menționa:

– algoritmi rapizi și clari pentru o execuție precisă

– abordare pe stări a procesului de transmitere/recepție a datelor în sensul optimizării comunicației robot-PC

– complexitate software adecvată structurii hardware

– interfață simplă cu utilizatorul, cu elemente grafice multiple – intuitive

– modularitate și scalabilitate

– alocare dinamica a resurselor hardware de procesare video pe baza unor secvente de cod redundante

Proiectarea și implementarea software, structurate clar pentru cele două entitați robot și PC, nu a constituit problematici foarte dificile din perspectiva programării în sine. Dezvoltarea unor algoritmi optimali însă a impus o cunoaștere profundă a principiilor de funcționare hardware a diferitelor module (ex comunicația serială prin XBee, semnalele PW de la sonare).

Așadar, se poate afirma că, dezvoltarea hardware și software pentru un sistem robot de tip “Platforma wireless robotizata pentru captura si analiza de imagine in timp real” survine ca rezultat al unei evaluări realiste asupra funcționalităților și capacităților ce se doresc implementate, al unei analize detaliate în vederea elaborării unei soluții tehnice optimale și nu în ultimul rând al unui proces de simulare intensiv care reflecta comportamentul sistemului în circumstanțe diverse.

Cap. 6. Bibliografie

Nicolae Cupcea, Costin Ștefănescu, Adrian Surpățeanu

Elemente de Electronică Analogică – Dispozitive electronice, Amplificatoare electronice, Amplificatoare operaționale, Editura AGIR București 2008, ISBN 978-973-720-229-1

Prof. Tudorache Tudor

Construirea unui robot

Massimo Banzi:

Getting Started with Arduino,Editura O’Reilly, ISBN 978-0-596-15551-3

Tom Igoe:

Making Things Talk – Practical Methods for Connecting Physical Objects

Editura O’Reilly, ISBN 978-0-596-51051-0

Massimo Banzi, David Cuartielles, Tom Igoe, Gianluca Martino, and David Mellis:

Arduino Microcontroller Processing for Everyone!, Editura Morgan & Claypool, ISBN 978-1-608-45438-9

XBe e®/XBe e -PRO® ZB RF Modules User’s Guide

Digi International Inc.

Andrew King:

A Survey of Methods for Face Detection

Ole Helvig Jensen:

Implementing the Viola-Jones Face Detection Algorithm

Herbert Bay, Andreas Ess, Tinne Tuytelaars, and Luc Van Gool:

Speeded-Up Robust Features (SURF)

Navneet Dalal and Bill Triggs:

Histograms of Oriented Gradients for Human Detection

S.Kranthi, K.Pranathi, A.Srisaila:

Automatic Number Plate Recognition

Tudoran Mihai

http://prezi.com/aaekbf3o1tbz/c/

Limbajul de programare C++

http://modularcircuits.tantosonline.com/blog/articles/old-h-bridge-secrets/

Principiu funcționare punte H

http://arduino.cc/en/Tutorial/HomePage

Sursă de informații oficială Arduino cu privire la funcționarea platformei + forum online

http://www.instructables.com/tag/type-id/category-technology/channel-arduino/

Proiecte de roboti cu diverse functionalitati

http://forum.sparkfun.com/

Forum online cu profil tehnic

http://wikipeda.org

Enciclopedie online

http://docs.opencv.org/

Sursă de informații oficială OpenCV / EmguCV

http://www.scritub.com/stiinta/informatica/Microcontrolerul-PICF44210218.php

Structura internă microcontroler

Construcția unui robot mobil cu kit Arduino

http://www.math.uaic.ro/~mapetrii/fisiere/POO/Curs7.pdf

Introducere in Microsoft Visual Studio

Cap. 7. Anexe

7.1 Cod sursă program microcontroller – limbaj C

////////////////////////////////////////////////////////

//Application: Robot Explorer v2.0 uController Software

//Board: Arduino UNO R3

//Copyright Margescu Valentin Razvan

////////////////////////////////////////////////////////

#include <Servo.h>

//Variabile globale

//definire pini IO senzori ultrasonici

#define pingPin_sf 6

#define pingPin_df 9

#define pingPin_ss 10

#define pingPin_ds 11

//definire pini IO drivere motoare

#define motor_dr_pin 5

#define motor_st_pin 3

#define dir_dr_pin 4

#define dir_st_pin 2

//definire variabile distante senzori ultrasonici

long distanta_sf;

long distanta_df;

long distanta_ss;

long distanta_ds;

//definire variabile stari distante senzori ultrasonici

int sf_curent=0;

int sf_anterior=0;

int df_curent=0;

int df_anterior=0;

int ss_curent=0;

int ss_anterior=0;

int ds_curent=0;

int ds_anterior=0;

//cronometru

unsigned long timp_curent;

unsigned long timp_anterior;

//variabile servomotoare

Servo servo_vert;

Servo servo_oriz;

int pos_vert=90;

int pos_oriz=90;

//alte variabile interne

int x,viteza,factor;

//bucra setare (ruleaza o singura data la pornirea sistemului)

void setup()

{

//atasare numar pini servomotoare

servo_vert.attach(12);

servo_oriz.attach(13);

//definire pini directie motoare ca pini de iesire (comanda)

pinMode(dir_dr_pin, OUTPUT);

pinMode(dir_st_pin, OUTPUT);

initial();

//stabilire viteza initiala

viteza=50;

//initializare timp curent

timp_curent=0;

//pornire interfata seriala la 115200 baud

Serial.begin(115200);

}

//bucla repetativa (ruleaza la infinit cat timp sistemul este pornit)

void loop()

{

//pornire cronometru

timp_curent=millis();

//o data la 500 milisecunde

if(timp_curent-timp_anterior>500)

{

//citeste distantele de la senzori

distanta_sf=citeste_distanta_sf();

distanta_df=citeste_distanta_df();

distanta_ss=citeste_distanta_ss();

distanta_ds=citeste_distanta_ds();

timp_anterior=timp_curent;

if(distanta_sf<=60)

{

if(distanta_sf<=40)

{

if(distanta_sf<=20)

{

sf_curent=1;

}

else

{

sf_curent=2;

}

}

else

{

sf_curent=3;

}

}

else

{

sf_curent=0;

}

if(sf_curent!=sf_anterior)

{

switch(sf_curent)

{

case 3:

{

Serial.println("SF:3");

delay(10);

sf_anterior=sf_curent;

break;

}

case 2:

{

Serial.println("SF:2");

delay(10);

sf_anterior=sf_curent;

break;

}

case 1:

{

Serial.println("SF:1");

delay(10);

sf_anterior=sf_curent;

break;

}

case 0:

{

Serial.println("SF:0");

delay(10);

sf_anterior=sf_curent;

break;

}

default:

{

Serial.println("SF:0");

delay(10);

sf_anterior=sf_curent;

}

}

}

//prelucrare date senzor dreapta fata

if(distanta_df<=60)

{

if(distanta_df<=40)

{

if(distanta_df<=20)

{

df_curent=1;

}

else

{

df_curent=2;

}

}

else

{

df_curent=3;

}

}

else

{

df_curent=0;

}

if(df_curent!=df_anterior)

{

switch(df_curent)

{

case 3:

{

Serial.println("DF:3");

delay(10);

df_anterior=df_curent;

break;

}

case 2:

{

Serial.println("DF:2");

delay(10);

df_anterior=df_curent;

break;

}

case 1:

{

Serial.println("DF:1");

delay(10);

df_anterior=df_curent;

break;

}

case 0:

{

Serial.println("DF:0");

delay(10);

df_anterior=df_curent;

break;

}

default:

{

Serial.println("DF:0");

delay(10);

df_anterior=df_curent;

}

}

}

//prelucrare date senzor stanga spate

if(distanta_ss<=60)

{

if(distanta_ss<=40)

{

if(distanta_ss<=20)

{

ss_curent=1;

}

else

{

ss_curent=2;

}

}

else

{

ss_curent=3;

}

}

else

{

ss_curent=0;

}

if(ss_curent!=ss_anterior)

{

switch(ss_curent)

{

case 3:

{

Serial.println("SS:3");

delay(10);

ss_anterior=ss_curent;

break;

}

case 2:

{

Serial.println("SS:2");

delay(10);

ss_anterior=ss_curent;

break;

}

case 1:

{

Serial.println("SS:1");

delay(10);

ss_anterior=ss_curent;

break;

}

case 0:

{

Serial.println("SS:0");

delay(10);

ss_anterior=ss_curent;

break;

}

default:

{

Serial.println("SS:0");

delay(10);

ss_anterior=ss_curent;

}

}

}

//prelucrare date senzor dreapta spate

if(distanta_ds<=60)

{

if(distanta_ds<=40)

{

if(distanta_ds<=20)

{

ds_curent=1;

}

else

{

ds_curent=2;

}

}

else

{

ds_curent=3;

}

}

else

{

ds_curent=0;

}

if(ds_curent!=ds_anterior)

{

switch(ds_curent)

{

case 3:

{

Serial.println("DS:3");

delay(10);

ds_anterior=ds_curent;

break;

}

case 2:

{

Serial.println("DS:2");

delay(10);

ds_anterior=ds_curent;

break;

}

case 1:

{

Serial.println("DS:1");

delay(10);

ds_anterior=ds_curent;

break;

}

case 0:

{

Serial.println("DS:0");

delay(10);

ds_anterior=ds_curent;

break;

}

default:

{

Serial.println("DS:0");

delay(10);

ds_anterior=ds_curent;

}

}

}

}

//citire comenzi pe interfata seriala

if(Serial.available())

{

x=Serial.read();

}

switch(x)

{

case 119:

{

inainte(viteza);

break;

}

case 115:

{

inapoi(viteza);

break;

}

case 97:

{

intoarcere_st(viteza);

break;

}

case 100:

{

intoarcere_dr(viteza);

break;

}

case 46:

{

viteza=viteza+20;

x=0;

break;

}

case 44:

{

viteza=viteza-20;

x=0;

break;

}

case 114:

{

servo_vert.write(90);

servo_oriz.write(90);

delay(15);

pos_vert=90;

pos_oriz=90;

break;

}

case 105:

{

if(pos_vert>50)

{

pos_vert=pos_vert-10;

servo_vert.write(pos_vert);

delay(15);

x=0;

}

else

{

x=0;

}

break;

}

case 107:

{

if(pos_vert<130)

{

pos_vert=pos_vert+10;

servo_vert.write(pos_vert);

delay(15);

x=0;

}

else

{

x=0;

}

break;

}

case 108:

{

if(pos_oriz>50)

{

pos_oriz=pos_oriz-10;

servo_oriz.write(pos_oriz);

delay(15);

x=0;

}

else

{

x=0;

}

break;

}

case 106:

{

if(pos_oriz<130)

{

pos_oriz=pos_oriz+10;

servo_oriz.write(pos_oriz);

delay(15);

x=0;

}

else

{

x=0;

}

break;

}

case 103:

{

if((distanta_sf<=40)||(distanta_df<=40))

{

if((distanta_sf<=20)||(distanta_df<=20))

{

if(distanta_sf<distanta_df)

{

factor=distanta_df-distanta_sf;

inapoi(viteza);

delay(1000);

intoarcere_dr(viteza);

delay(1000/factor);

}

if(distanta_sf>distanta_df)

{

factor=distanta_sf-distanta_df;

inapoi(viteza);

delay(1000);

intoarcere_st(viteza);

delay(1000/factor);

}

}

else

{

if(distanta_sf<distanta_df)

{

factor=distanta_df-distanta_sf;

intoarcere_dr(viteza);

delay(1000/factor);

}

if(distanta_sf>distanta_df)

{

factor=distanta_sf-distanta_df;

intoarcere_st(viteza);

delay(1000/factor);

}

}

}

else

{

inainte(viteza);

}

break;

}

case 116:

{

servo_vert.write(180);

servo_oriz.write(170);

delay(15);

pos_vert=180;

pos_oriz=170;

break;

}

default:

{

oprire();

x=0;

}

}

viteza=constrain(viteza, 0, 200);

}

//sectiune functii

//functie rulara la pornirea robotului pentru setarea pozitiei initiale a camerei

void initial()

{

servo_vert.write(90);

servo_oriz.write(90);

delay(15);

}

//functie deplasare inainte

void inainte(int viteza)

{

digitalWrite(dir_dr_pin,HIGH);

digitalWrite(dir_st_pin,LOW);

analogWrite(motor_dr_pin, viteza);

analogWrite(motor_st_pin, viteza);

}

//functie deplasare inapoi

void inapoi(int viteza)

{

digitalWrite(dir_dr_pin,LOW);

digitalWrite(dir_st_pin,HIGH);

analogWrite(motor_dr_pin, viteza);

analogWrite(motor_st_pin, viteza);

}

//functie intoarcere la stanga

void intoarcere_st(int viteza)

{

int viteza_viraj;

if(viteza>70)

{

viteza_viraj=70;

}

else

{

viteza_viraj=viteza;

}

digitalWrite(dir_dr_pin,HIGH);

digitalWrite(dir_st_pin,HIGH);

analogWrite(motor_dr_pin, viteza_viraj);

analogWrite(motor_st_pin, viteza_viraj);

}

//functie intoarcere la dreapta

void intoarcere_dr(int viteza)

{

int viteza_viraj;

if(viteza>70)

{

viteza_viraj=70;

}

else

{

viteza_viraj=viteza;

}

digitalWrite(dir_dr_pin,LOW);

digitalWrite(dir_st_pin,LOW);

analogWrite(motor_dr_pin, viteza_viraj);

analogWrite(motor_st_pin, viteza_viraj);

}

//functie oprire

void oprire()

{

analogWrite(motor_dr_pin, 0);

analogWrite(motor_st_pin, 0);

}

//functie citire senzor ultrasonic stanga fata

long citeste_distanta_sf()

{

//calibrare

pinMode(pingPin_sf, OUTPUT);

digitalWrite(pingPin_sf, LOW);

delayMicroseconds(2);

digitalWrite(pingPin_sf, HIGH);

delayMicroseconds(2);

digitalWrite(pingPin_sf, LOW);

//citire

pinMode(pingPin_sf, INPUT);

long puls = pulseIn(pingPin_sf, HIGH);

long inchi = puls/147;

long cm = inchi * 2.54;

return(cm);

}

//functie citire senzor ultrasonic dreapta fata

long citeste_distanta_df()

{

//calibrare

pinMode(pingPin_df, OUTPUT);

digitalWrite(pingPin_df, LOW);

delayMicroseconds(2);

digitalWrite(pingPin_df, HIGH);

delayMicroseconds(2);

digitalWrite(pingPin_df, LOW);

//citire

pinMode(pingPin_df, INPUT);

long puls = pulseIn(pingPin_df, HIGH);

delay(10);

long inchi = puls/147;

long cm = inchi * 2.54;

return(cm);

}

//functie citire senzor ultrasonic stanga spate

long citeste_distanta_ss()

{

//calibrare

pinMode(pingPin_ss, OUTPUT);

digitalWrite(pingPin_ss, LOW);

delayMicroseconds(2);

digitalWrite(pingPin_ss, HIGH);

delayMicroseconds(2);

digitalWrite(pingPin_ss, LOW);

//citire

pinMode(pingPin_ss, INPUT);

long puls = pulseIn(pingPin_ss, HIGH);

delay(10);

long inchi = puls/147;

long cm = inchi * 2.54;

return(cm);

}

//functie citire senzor ultrasonic dreapta spate

long citeste_distanta_ds()

{

//calibrare

pinMode(pingPin_ds, OUTPUT);

digitalWrite(pingPin_ds, LOW);

delayMicroseconds(2);

digitalWrite(pingPin_ds, HIGH);

delayMicroseconds(2);

digitalWrite(pingPin_sf, LOW);

//citire

pinMode(pingPin_ds, INPUT);

long puls = pulseIn(pingPin_ds, HIGH);

delay(10);

long inchi = puls/147;

long cm = inchi * 2.54;

return(cm);

}

7.2 Cod sursă program aplicație PC (Windows) – limbaj C#

7.2.1 Cod sursă form configurare conexiune serială

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Linq;

using System.Text;

using System.Windows.Forms;

using System.IO.Ports;

namespace Rbtz_App

{

public partial class Setari : Form

{

public string[] ports = SerialPort.GetPortNames();

public SerialPort sp;

public Setari()

{

InitializeComponent();

populare_cb_port();

populare_cb_baud();

populare_cb_nrBiti();

}

private void populare_cb_port()

{

foreach (string port in ports)

{

cbPort.Items.Add(port);

}

}

private void populare_cb_baud()

{

cbBaud.Items.Add(4800);

cbBaud.Items.Add(7200);

cbBaud.Items.Add(9600);

cbBaud.Items.Add(14400);

cbBaud.Items.Add(19200);

cbBaud.Items.Add(38400);

cbBaud.Items.Add(57600);

cbBaud.Items.Add(115200);

cbBaud.Items.Add(128000);

}

private void populare_cb_nrBiti()

{

cbNrBiti.Items.Add(8);

cbNrBiti.Items.Add(16);

cbNrBiti.Items.Add(32);

cbNrBiti.Items.Add(64);

cbNrBiti.Items.Add(128);

}

private void lInitializareConexiune_Click(object sender, EventArgs e)

{

bool ok=false;

try

{

sp = new SerialPort(cbPort.Text, Convert.ToInt32(cbBaud.Text), Parity.None, Convert.ToInt32(cbNrBiti.Text));

ok = true;

}

catch (Exception)

{

MessageBox.Show("Selectati toti parametrii conexiunii din box-ul corespunzator!");

}

if (ok == true)

{

try

{

sp.Open();

if (sp.IsOpen)

{

MessageBox.Show("Conexiune stabilita cu succes!");

sp.Close();

Main a = new Main(cbPort.Text, Convert.ToInt32(cbBaud.Text), Convert.ToInt32(cbNrBiti.Text));

a.Show();

}

}

catch (Exception)

{

MessageBox.Show("Conexiune esuata! Verificati daca robotul este pornit!");

}

//this.Close();

}

}

}

}

7.2.2 Cod sursă form “Main”

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Linq;

using System.Text;

using System.Windows.Forms;

using System.IO.Ports;

using System.Threading;

using System.Threading.Tasks;

using Emgu.CV;

using Emgu.CV.CvEnum;

using Emgu.CV.Features2D;

using Emgu.CV.Structure;

using Emgu.CV.Util;

using Emgu.CV.GPU;

using Emgu.CV.OCR;

using DirectShowLib;

namespace Rbtz_App

{

public partial class Main : Form

{

public SerialPort sp;

public String Port;

public Int32 Baud;

public Int32 NrBiti;

public String indata;

private delegate void set_delegat();

int viteza=3;

public int poz_anterioara_vert = 40;

public int poz_anterioara_oriz = 40;

public char[] buff = new char[1];

public bool esteFullScreen = false;

public int latime_gbVideo;

public int inaltime_gbVideo;

public Point locatie_gbVideo;

public double factor_scalare_fullscreen_gbVideo;

public int latime_gbControl;

public int inaltime_gbControl;

public Point locatie_gbControl;

public double factor_scalare_fullscreen_gbControl;

public int latime_gbSenzori;

public int inaltime_gbSenzori;

public Point locatie_gbSenzori;

public double factor_scalare_fullscreen_gbSenzori;

public int latime_ctProcesareImagine;

public int inaltime_ctProcesareImagine;

public Point locatie_ctProcesareImagine;

public double factor_scalare_fullscreen_ctProcesareImagine;

public int latime_pbRELogo;

public int inaltime_pbRELogo;

public Point locatie_pbRELogo;

public double factor_scalare_fullscreen_pbRELogo;

//variabile captura

public Capture captura; //preia cadre de la dispozitivul de captura

public bool captura_in_progres; //verifica daca are loc procesul de captura

//variabile scalare form

public int latime_curenta;

public int inaltime_curenta;

public int latime_noua;

public int inaltime_noua;

//variabile setari captura

public int luminozitate;

public int contrast;

public int claritate;

//variabile detectie faciala

private Emgu.CV.HaarCascade haar;

public double scala_df;

public int treshold_nr_minim_vecini_df;

public Emgu.CV.CvEnum.HAAR_DETECTION_TYPE tip_detectie_df;

public List<int> numar_fete_partial = new List<int>();

public List<bool> numar_similaritati_partial = new List<bool>();

public List<int> numar_siluete_partial = new List<int>();

//variabile detectie similaritati

private Image<Bgr, Byte> imagine_cadru = null;

private Image<Bgr, Byte> imagine_de_cautat = null;

private Image<Bgr, Byte> imagine_de_cautat_cu_contur = null;

private Image<Bgr, Byte> imagine_rezultat = null;

private Bgr culoare_puncte_interes = new Bgr(Color.Blue);

private Bgr culoare_linii_similaritate = new Bgr(Color.Green);

private Bgr culoare_chenar_imagine_gasita = new Bgr(Color.Red);

private int numar_vecini_ds;

private double threshold_unicitate_ds;

private double increment_scala_ds;

private int segmente_rotatie_ds;

//variabile detectie similaritati

private int nr_siluete_detectate;

//variabile detectie caractere

private Tesseract tess;

private Image<Bgr, Byte> imagine_OCR = null;

private DetectorNumereInmatriculare detector;

private List<Image<Gray, Byte>> imagini_numere_inmatriculare;

private List<Image<Gray, Byte>> imagini_numere_inmatriculare_filtrate;

private List<MCvBox2D> regiuni_numere_inmatriculare;

private List<string> cuvinte_numere_inmatriculare;

private List<Image<Gray, Byte>> imagini_numere_inmatriculare_partial;

private List<Image<Gray, Byte>> imagini_numere_inmatriculare_filtrate_partial;

private List<MCvBox2D> regiuni_numere_inmatriculare_partial;

private List<string> cuvinte_numere_inmatriculare_partial;

public Main(String port, Int32 baud, Int32 nrBiti)

{

Port = port;

Baud = baud;

NrBiti = nrBiti;

InitializeComponent();

sp = new SerialPort(port, baud, Parity.None, nrBiti, StopBits.One);

sp.Handshake = Handshake.XOnXOff;

sp.ReadTimeout = 500;

sp.WriteTimeout = 500;

tbViteza.Text = viteza.ToString();

sp.Open();

if (sp.IsOpen)

{

afiseaza_info_conexiune();

}

else

{

sp.Close();

}

sp.DataReceived += new SerialDataReceivedEventHandler(receptieDate);

//––––––––––––––––––––––––––

vSBcameraVert.Value = 40;

hSBcameraOriz.Value = 40;

poz_anterioara_vert = 40;

poz_anterioara_oriz = 40;

buff[0] = 'r';

sp.Write(buff, 0, 1);

//––––––––––––––––––––––––––

populare_surse_video();

//––––––––––––––––––––––––––

//setare latime si inaltime curenta

latime_curenta = 1440;

inaltime_curenta = 900;

latime_noua = 1440;

inaltime_noua = 900;

//––––––––––––––––––––––––––

//initializare variabile prelucrare video

cron.Interval = 2000;

scala_df = 1 + (Convert.ToDouble(tbScala.Value) / 10);

treshold_nr_minim_vecini_df = Convert.ToInt32(tbNrMinVecini.Value);

tip_detectie_df = Emgu.CV.CvEnum.HAAR_DETECTION_TYPE.DO_CANNY_PRUNING;

numar_vecini_ds = 2;

threshold_unicitate_ds = 0.5;

increment_scala_ds = 1.1;

segmente_rotatie_ds = 20;

nr_siluete_detectate = 0;

try

{

tess = new Tesseract("tessdata", "eng", Tesseract.OcrEngineMode.OEM_DEFAULT);

}

catch (Exception e)

{

MessageBox.Show("Nu a putut fi instantiata variabila 'tess' pentru detectie caractere!");

tpDetectieCaractere.Enabled = false;

}

detector = new DetectorNumereInmatriculare();

detector.threshold_binarizare = 100;

detector.threshold_contur = 150;

detector.threshold_unificare_contur = 200;

imagini_numere_inmatriculare_partial = new List<Image<Gray, byte>>();

imagini_numere_inmatriculare_filtrate_partial = new List<Image<Gray, byte>>();

regiuni_numere_inmatriculare_partial = new List<MCvBox2D>();

cuvinte_numere_inmatriculare_partial = new List<string>();

//––––––––––––––––––––––––––

//setare elemente grafice prelucrare video

tbValoareLuminozitate.Text = tbLuminozitate.Value.ToString();

tbValoareContrast.Text = tbContrast.Value.ToString();

tbValoareClaritate.Text = tbClaritate.Value.ToString();

tbValoareScala.Text = tbScala.Value.ToString();

tbValoareNrMinVecini.Text = tbNrMinVecini.Value.ToString();

cbDetectieSimilaritati.Items.Add("Numar vecini");

cbDetectieSimilaritati.Items.Add("Threshold unicitate");

cbDetectieSimilaritati.Items.Add("Increment scala");

cbDetectieSimilaritati.Items.Add("Segmente rotatie");

cbDetectieSimilaritati.SelectedIndex = cbDetectieSimilaritati.Items.IndexOf("Numar vecini");

tbDetectieSimilaritati.Minimum = 2;

tbDetectieSimilaritati.Maximum = 10;

tbDetectieSimilaritati.Value = numar_vecini_ds;

tbValoareDetectieSimilaritati.Text = tbDetectieSimilaritati.Value.ToString();

cbDetectieCaractere.Items.Add("Threshold binarizare");

cbDetectieCaractere.Items.Add("Threshold contur");

cbDetectieCaractere.Items.Add("Threshold unificare contur");

cbDetectieCaractere.SelectedIndex = cbDetectieCaractere.Items.IndexOf("Threshold binarizare");

tbDetectieCaractere.Minimum = 70;

tbDetectieCaractere.Maximum = 130;

tbDetectieCaractere.Value = detector.threshold_binarizare;

tbValoareDetectieCaractere.Text = tbDetectieCaractere.Value.ToString();

}

public void receptieDate(object sender, SerialDataReceivedEventArgs e)

{

sp = (SerialPort)sender;

try

{

indata = sp.ReadLine();

}

catch (Exception)

{

}

try

{

if (indata == "SF:1" + indata[4])

{

this.BeginInvoke(new set_delegat(SF1), new object[] { });

}

if (indata == "SF:2" + indata[4])

{

this.BeginInvoke(new set_delegat(SF2), new object[] { });

}

if (indata == "SF:3" + indata[4])

{

this.BeginInvoke(new set_delegat(SF3), new object[] { });

}

if (indata == "SF:0" + indata[4])

{

this.BeginInvoke(new set_delegat(SF0), new object[] { });

}

if (indata == "DF:1" + indata[4])

{

this.BeginInvoke(new set_delegat(DF1), new object[] { });

}

if (indata == "DF:2" + indata[4])

{

this.BeginInvoke(new set_delegat(DF2), new object[] { });

}

if (indata == "DF:3" + indata[4])

{

this.BeginInvoke(new set_delegat(DF3), new object[] { });

}

if (indata == "DF:0" + indata[4])

{

this.BeginInvoke(new set_delegat(DF0), new object[] { });

}

if (indata == "SS:1" + indata[4])

{

this.BeginInvoke(new set_delegat(SS1), new object[] { });

}

if (indata == "SS:2" + indata[4])

{

this.BeginInvoke(new set_delegat(SS2), new object[] { });

}

if (indata == "SS:3" + indata[4])

{

this.BeginInvoke(new set_delegat(SS3), new object[] { });

}

if (indata == "SS:0" + indata[4])

{

this.BeginInvoke(new set_delegat(SS0), new object[] { });

}

if (indata == "DS:1" + indata[4])

{

this.BeginInvoke(new set_delegat(DS1), new object[] { });

}

if (indata == "DS:2" + indata[4])

{

this.BeginInvoke(new set_delegat(DS2), new object[] { });

}

if (indata == "DS:3" + indata[4])

{

this.BeginInvoke(new set_delegat(DS3), new object[] { });

}

if (indata == "DS:0" + indata[4])

{

this.BeginInvoke(new set_delegat(DS0), new object[] { });

}

}

catch (Exception)

{

//nu se intampla nimic

}

}

public void SF1()

{

pStangaF1.Visible = true;

pStangaF2.Visible = false;

pStangaF3.Visible = false;

pbSemafor.BackgroundImage = global::Rbtz_App.Properties.Resources.semafor_rosu;

}

public void SF2()

{

pStangaF1.Visible = false;

pStangaF2.Visible = true;

pStangaF3.Visible = false;

pbSemafor.BackgroundImage = global::Rbtz_App.Properties.Resources.semafor_verde;

}

public void SF3()

{

pStangaF1.Visible = false;

pStangaF2.Visible = false;

pStangaF3.Visible = true;

pbSemafor.BackgroundImage = global::Rbtz_App.Properties.Resources.semafor_verde;

}

public void SF0()

{

pStangaF1.Visible = false;

pStangaF2.Visible = false;

pStangaF3.Visible = false;

pbSemafor.BackgroundImage = global::Rbtz_App.Properties.Resources.semafor_verde;

}

public void DF1()

{

pDreaptaF1.Visible = true;

pDreaptaF2.Visible = false;

pDreaptaF3.Visible = false;

pbSemafor.BackgroundImage = global::Rbtz_App.Properties.Resources.semafor_rosu;

}

public void DF2()

{

pDreaptaF1.Visible = false;

pDreaptaF2.Visible = true;

pDreaptaF3.Visible = false;

pbSemafor.BackgroundImage = global::Rbtz_App.Properties.Resources.semafor_verde;

}

public void DF3()

{

pDreaptaF1.Visible = false;

pDreaptaF2.Visible = false;

pDreaptaF3.Visible = true;

pbSemafor.BackgroundImage = global::Rbtz_App.Properties.Resources.semafor_verde;

}

public void DF0()

{

pDreaptaF1.Visible = false;

pDreaptaF2.Visible = false;

pDreaptaF3.Visible = false;

pbSemafor.BackgroundImage = global::Rbtz_App.Properties.Resources.semafor_verde;

}

public void SS1()

{

pStangaS1.Visible = true;

pStangaS2.Visible = false;

pStangaS3.Visible = false;

}

public void SS2()

{

pStangaS1.Visible = false;

pStangaS2.Visible = true;

pStangaS3.Visible = false;

}

public void SS3()

{

pStangaS1.Visible = false;

pStangaS2.Visible = false;

pStangaS3.Visible = true;

}

public void SS0()

{

pStangaS1.Visible = false;

pStangaS2.Visible = false;

pStangaS3.Visible = false;

}

public void DS1()

{

pDreaptaS1.Visible = true;

pDreaptaS2.Visible = false;

pDreaptaS3.Visible = false;

}

public void DS2()

{

pDreaptaS1.Visible = false;

pDreaptaS2.Visible = true;

pDreaptaS3.Visible = false;

}

public void DS3()

{

pDreaptaS1.Visible = false;

pDreaptaS2.Visible = false;

pDreaptaS3.Visible = true;

}

public void DS0()

{

pDreaptaS1.Visible = false;

pDreaptaS2.Visible = false;

pDreaptaS3.Visible = false;

}

//––––––––––––––––––––––––––

public void afiseaza_info_conexiune()

{

cbPort.Text = Port;

cbBaud.Text = Baud.ToString();

cbNrBiti.Text = NrBiti.ToString();

}

private void btn_inainte_Click(object sender, EventArgs e)

{

try

{

buff[0] = 'w';

sp.Write(buff, 0, 1);

btn_inainte.BackColor = Color.Gray;

btn_inapoi.BackColor = Color.Transparent;

btn_stanga.BackColor = Color.Transparent;

btn_dreapta.BackColor = Color.Transparent;

btn_stop.BackColor = Color.Transparent;

bAuto.BackColor = Color.Transparent;

}

catch (Exception ex)

{

MessageBox.Show(ex.ToString());

}

}

private void btn_inapoi_Click(object sender, EventArgs e)

{

try

{

buff[0] = 's';

sp.Write(buff, 0, 1);

btn_inainte.BackColor = Color.Transparent;

btn_inapoi.BackColor = Color.Gray;

btn_stanga.BackColor = Color.Transparent;

btn_dreapta.BackColor = Color.Transparent;

btn_stop.BackColor = Color.Transparent;

bAuto.BackColor = Color.Transparent;

}

catch (Exception ex)

{

MessageBox.Show(ex.ToString());

}

}

private void btn_stanga_Click(object sender, EventArgs e)

{

try

{

buff[0] = 'a';

sp.Write(buff, 0, 1);

btn_inainte.BackColor = Color.Transparent;

btn_inapoi.BackColor = Color.Transparent;

btn_stanga.BackColor = Color.Gray;

btn_dreapta.BackColor = Color.Transparent;

btn_stop.BackColor = Color.Transparent;

bAuto.BackColor = Color.Transparent;

}

catch (Exception ex)

{

MessageBox.Show(ex.ToString());

}

}

private void btn_dreapta_Click(object sender, EventArgs e)

{

try

{

buff[0] = 'd';

sp.Write(buff, 0, 1);

btn_inainte.BackColor = Color.Transparent;

btn_inapoi.BackColor = Color.Transparent;

btn_stanga.BackColor = Color.Transparent;

btn_dreapta.BackColor = Color.Gray;

btn_stop.BackColor = Color.Transparent;

bAuto.BackColor = Color.Transparent;

}

catch (Exception ex)

{

MessageBox.Show(ex.ToString());

}

}

private void btn_stop_Click(object sender, EventArgs e)

{

try

{

buff[0] = 'z';

sp.Write(buff, 0, 1);

btn_inainte.BackColor = Color.Transparent;

btn_inapoi.BackColor = Color.Transparent;

btn_stanga.BackColor = Color.Transparent;

btn_dreapta.BackColor = Color.Transparent;

btn_stop.BackColor = Color.Gray;

bAuto.BackColor = Color.Transparent;

}

catch (Exception ex)

{

MessageBox.Show(ex.ToString());

}

}

private void Main_FormClosing(object sender, FormClosingEventArgs e)

{

if (sp.IsOpen)

{

sp.Close();

}

}

private void vSBcameraVert_ValueChanged(object sender, EventArgs e)

{

int poz_curenta=vSBcameraVert.Value;

if (poz_curenta > poz_anterioara_vert)

{

buff[0] = 'k';

sp.Write(buff, 0, 1);

poz_anterioara_vert = poz_curenta;

}

else

{

buff[0] = 'i';

sp.Write(buff, 0, 1);

poz_anterioara_vert = poz_curenta;

}

}

private void hSBcameraOriz_ValueChanged(object sender, EventArgs e)

{

int poz_curenta = hSBcameraOriz.Value;

if (poz_curenta > poz_anterioara_oriz)

{

buff[0] = 'l';

sp.Write(buff, 0, 1);

poz_anterioara_oriz = poz_curenta;

}

else

{

buff[0] = 'j';

sp.Write(buff, 0, 1);

poz_anterioara_oriz = poz_curenta;

}

}

private void bReset_Click(object sender, EventArgs e)

{

vSBcameraVert.Value = 40;

hSBcameraOriz.Value = 40;

poz_anterioara_vert = 40;

poz_anterioara_oriz = 40;

buff[0] = 'r';

sp.Write(buff, 0, 1);

}

private void bVitUp_Click(object sender, EventArgs e)

{

buff[0] = '.';

sp.Write(buff, 0, 1);

if (viteza < 10)

{

viteza = viteza + 1;

tbViteza.Text = viteza.ToString();

}

}

private void bVitDown_Click(object sender, EventArgs e)

{

buff[0] = ',';

sp.Write(buff, 0, 1);

if (viteza > 0)

{

viteza = viteza – 1;

tbViteza.Text = viteza.ToString();

}

}

private void Main_KeyPress(object sender, KeyPressEventArgs e)

{

switch (e.KeyChar)

{

case 'w':

btn_inainte_Click(sender, e);

break;

case 'd':

btn_dreapta_Click(sender, e);

break;

case 's':

btn_inapoi_Click(sender, e);

break;

case 'a':

btn_stanga_Click(sender, e);

break;

case 'g':

bAuto_Click(sender, e);

break;

case 'k':

if (vSBcameraVert.Value <= 80)

{

vSBcameraVert.Value = vSBcameraVert.Value + 10;

}

break;

case 'i':

if (vSBcameraVert.Value >= 10)

{

vSBcameraVert.Value = vSBcameraVert.Value – 10;

}

break;

case 'l':

if (hSBcameraOriz.Value <= 80)

{

hSBcameraOriz.Value = hSBcameraOriz.Value + 10;

}

break;

case 'j':

if (hSBcameraOriz.Value >= 10)

{

hSBcameraOriz.Value = hSBcameraOriz.Value – 10;

}

break;

case ',':

bVitDown_Click(sender, e);

break;

case '.':

bVitUp_Click(sender, e);

break;

case 'r':

bReset_Click(sender, e);

break;

default:

btn_stop_Click(sender, e);

break;

}

}

private void bAuto_Click(object sender, EventArgs e)

{

try

{

buff[0] = 'g';

sp.Write(buff, 0, 1);

btn_inainte.BackColor = Color.Transparent;

btn_inapoi.BackColor = Color.Transparent;

btn_stanga.BackColor = Color.Transparent;

btn_dreapta.BackColor = Color.Transparent;

btn_stop.BackColor = Color.Transparent;

bAuto.BackColor = Color.Gray;

}

catch (Exception ex)

{

MessageBox.Show(ex.ToString());

}

}

private void pbOff_Click(object sender, EventArgs e)

{

try

{

buff[0] = 't';

sp.Write(buff, 0, 1);

}

catch (Exception ex)

{

MessageBox.Show(ex.ToString());

}

if (captura != null)

{

captura.Dispose();

}

sp.Close();

this.Close();

}

private void pbOff_MouseEnter(object sender, EventArgs e)

{

this.pbOff.BackgroundImage = global::Rbtz_App.Properties.Resources.PowerButton;

}

private void pbOff_MouseLeave(object sender, EventArgs e)

{

this.pbOff.BackgroundImage = global::Rbtz_App.Properties.Resources.PowerButton_Transparent1;

}

//funtie pentru popularea surselor video

public void populare_surse_video()

{

//populare combo box

DsDevice[] elemente_captura_disponibile = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);

for (int i = 0; i < elemente_captura_disponibile.Length; i++)

{

cbSursa_video.Items.Add(elemente_captura_disponibile[i].Name.ToString());

}

//daca exita surse video disponibile

if (cbSursa_video.Items.Count > 0)

{

cbSursa_video.Enabled = true;

cbSursa_video.SelectedIndex = 0;

bVideo.Enabled = true;

}

//daca nu exista surse video disponibile

else

{

cbSursa_video.Enabled = false;

bVideo.Enabled = false;

}

}

private void bRefresh_Click(object sender, EventArgs e)

{

populare_surse_video();

}

//eveniment declansat la apasarea butonului start

private void bVideo_Click(object sender, EventArgs e)

{

//daca nu a fost instantiata captura

if (captura == null)

{

try

{

captura = new Capture();

}

catch (NullReferenceException excpt)

{

MessageBox.Show(excpt.Message);

}

}

//daca a fost instantiata captura

if (captura != null)

{

//verificare daca procesul de captura are loc

if (captura_in_progres)

{

//daca procesul de captura are loc, procesul se va opri iar textul butonului va redeveni "Start"

bVideo.Text = "Start";

Application.Idle -= proceseaza_cadru;

Application.Idle -= detecteaza_fete;

Application.Idle -= detecteaza_similaritati;

Application.Idle -= proceseaza_cadru_detecteaza_similaritati;

Application.Idle -= detecteaza_siluete;

cron.Stop();

pbVideo.Image = null;

if (esteFullScreen == true)

{

pCopyright.Visible = false;

}

else

{

pCopyright.Visible = true;

}

lProcesareImagine.Visible = false;

ctProcesareImagine.Visible = false;

}

else

{

//daca procesul de captura nu are loc, se porneste procesul de captura iar textul butonului va deveni "Stop"

bVideo.Text = "Stop";

Application.Idle += proceseaza_cadru;

setari_initiale_captura();

pCopyright.Visible = false;

ctProcesareImagine.Visible = true;

if (esteFullScreen == true)

{

lProcesareImagine.Visible = false;

}

else

{

lProcesareImagine.Visible = true;

}

ctProcesareImagine.SelectedTab = ctProcesareImagine.TabPages[0];

}

captura_in_progres = !captura_in_progres;

}

}

//functie pentru obtinerea setarilor initiale ale capturii

public void setari_initiale_captura()

{

luminozitate = (int)captura.GetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_BRIGHTNESS);

contrast = (int)captura.GetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_CONTRAST);

claritate = (int)captura.GetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_SHARPNESS);

}

//eveniment declansat la apasarea butonului de captura frame

private void pbPhoto_Click(object sender, EventArgs e)

{

System.Media.SoundPlayer myPlayer = new System.Media.SoundPlayer(Properties.Resources.camera1);

myPlayer.Play();

try

{

Image<Bgr, Byte> cadru_image_box = captura.QueryFrame();

cadru_image_box.Save(@"Captura " + DateTime.Now.ToString());

}

catch (Exception)

{

MessageBox.Show("Lansati procesul de redare mai intai!");

}

}

private void pbPhoto_MouseEnter(object sender, EventArgs e)

{

this.pbPhoto.BackgroundImage = global::Rbtz_App.Properties.Resources.camera_on;

}

private void pbPhoto_MouseLeave(object sender, EventArgs e)

{

this.pbPhoto.BackgroundImage = global::Rbtz_App.Properties.Resources.camera_off;

}

private void pbPhoto_Mare_Click(object sender, EventArgs e)

{

System.Media.SoundPlayer myPlayer = new System.Media.SoundPlayer(Properties.Resources.camera1);

myPlayer.Play();

}

//functie pentru preluarea unui cadru de la elementul de captura si transpunerea lui in ImageBox

private void proceseaza_cadru(object sender, EventArgs arg)

{

Image<Bgr, Byte> cadru_image_box_primar = captura.QueryFrame();

if (cadru_image_box_primar != null)

{

Image<Bgr, Byte> cadru_image_box = cadru_image_box_primar.Resize(pbVideo.Width, pbVideo.Height, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR);

pbVideo.Image = cadru_image_box.ToBitmap();

}

}

//functie pentru detectie faciala

private void detecteaza_fete(object sender, EventArgs arg)

{

//procesul de detectie faciala

Image<Bgr, Byte> cadru_image_box_primar = captura.QueryFrame();

if (cadru_image_box_primar != null)

{

Image<Bgr, Byte> cadru_image_box = cadru_image_box_primar.Resize(pbVideo.Width, pbVideo.Height, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR);

//se converteste imaginea in grayscale

Image<Gray, byte> cadru_sursa_grayscale = cadru_image_box.Convert<Gray, byte>();

//se detecteaza fete si stocheaza intr-un vector var

var fete = cadru_sursa_grayscale.DetectHaarCascade(haar, scala_df, treshold_nr_minim_vecini_df, tip_detectie_df, new Size(25, 25))[0];

//stocheaza numarul de fete pentru analiza

numar_fete_partial.Add(fete.Length);

//se deseneaza un contur verde care incadreaza fiecare fata

foreach (var fata in fete)

{

cadru_image_box.Draw(fata.rect, new Bgr(Color.Green), 2);

}

pbVideo.Image = cadru_image_box.ToBitmap();

}

}

//functie pentru detectie similaritati

private void detecteaza_similaritati(object sender, EventArgs arg)

{

//procesul de detectie similaritati

Image<Bgr, Byte> imagine_cadru_primar = captura.QueryFrame();

if (imagine_cadru_primar != null && imagine_de_cautat != null)

{

imagine_cadru = imagine_cadru_primar.Resize(pbVideo.Width, pbVideo.Height, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR);

SURFDetector surf_detector = new SURFDetector(500, false); //instantiere surf detector cu specificarea thresholdului

Image<Gray, Byte> imagine_cadru_gri = null; //imagine cadru in tonuri de gri

Image<Gray, Byte> imagine_de_cautat_gri = null; //imagine de cautat in tonuri de gri

VectorOfKeyPoint vpc_imagine_cadru; //vector de puncte cheie in imaginea cadru

VectorOfKeyPoint vpc_imagine_de_cautat; //vector de puncte cheie in imaginea de cautat

Matrix<Single> md_imagine_cadru; //matricea de descriptori in imaginea cadru

Matrix<Single> md_imagine_de_cautat; //matricea de descriptori in imaginea de cautat

Matrix<int> m_indicii; //matricea de indicii a descriptorilor (rezultata din descriptorii invatati)

Matrix<Single> m_distante; //matricea de valori ale distantelor (rezultata din descriptorii invatati)

Matrix<Byte> m_masca; //indica ce rand este valid pentru match

BruteForceMatcher<Single> brute_force_matcher; //pentru fiecare desciptor dintr-un anumit set, acest matcher identifica cel mai apropiat descriptor dintr-un alt set prin comparatie cu fiecare

HomographyMatrix matrice_homografie = null; //utilizata pentru functia de localizare a imaginii de cautat in imaginea cadru

int nr_elemente_nenule; //contor elemente nenule in m_masca

double threshold_reproiectare = 2.0;

Rectangle dreptunghi_imagine_de_cautat; //dreptunghiul care contureaza imaginea de cautat

PointF[] puncte_float; //cele 4 puncte care determina conturul imaginii de cautat in imaginea cadru (float)

Point[] puncte_int; //cele 4 puncte care determina conturul imaginii de cautat in imaginea cadru (int)

imagine_cadru_gri = imagine_cadru.Convert<Gray, Byte>(); //conversie imagine cadru in grayscale

imagine_de_cautat_gri = imagine_de_cautat.Convert<Gray, Byte>(); //conversie imagine de cautat in grayscale

vpc_imagine_cadru = surf_detector.DetectKeyPointsRaw(imagine_cadru_gri, null); //detecteaza punctele cheie in imaginea cadru, parametrul secund este masca

md_imagine_cadru = surf_detector.ComputeDescriptorsRaw(imagine_cadru_gri, null, vpc_imagine_cadru); //calculeaza descriptorul imaginii cadru

vpc_imagine_de_cautat = surf_detector.DetectKeyPointsRaw(imagine_de_cautat_gri, null); //detecteaza punctele cheie in imaginea de cautat, parametrul secund este masca

md_imagine_de_cautat = surf_detector.ComputeDescriptorsRaw(imagine_de_cautat_gri, null, vpc_imagine_de_cautat); //calculeaza descriptorul imaginea de cautat

brute_force_matcher = new BruteForceMatcher<Single>(DistanceType.L2); //instantierea obiectului bfm cu param: distanta patratica euclidiana

brute_force_matcher.Add(md_imagine_de_cautat); //adaugare matrice descriptori imagine de cautat

m_indicii = new Matrix<int>(md_imagine_cadru.Rows, numar_vecini_ds); //instantiere matrice indicii

m_distante = new Matrix<Single>(md_imagine_cadru.Rows, numar_vecini_ds); //instantiere matrice distante

brute_force_matcher.KnnMatch(md_imagine_cadru, m_indicii, m_distante, numar_vecini_ds, null); //detecteaza a k-a cea mai apropiata similaritate (match), unde k este dat de numar_vecini

m_masca = new Matrix<byte>(m_distante.Rows, 1); //instantiaza matricea masca

m_masca.SetValue(255); //setare toate valorile la 255

Features2DToolbox.VoteForUniqueness(m_distante, threshold_unicitate_ds, m_masca); //filtreaza similaritatile dupa unicitate: daca o similaritete nu este unica este rejectata

nr_elemente_nenule = CvInvoke.cvCountNonZero(m_masca); //contorizare nr. elemente nenule din matricea masca

if (nr_elemente_nenule >= 4) //daca sunt minim 4 elemente nenule

{

nr_elemente_nenule = Features2DToolbox.VoteForSizeAndOrientation(vpc_imagine_de_cautat, vpc_imagine_cadru, m_indicii, m_masca, increment_scala_ds, segmente_rotatie_ds); //eliminare similaritati care nu corespund ca scala si ca rotatie cu tendinta majora de scala si rotatie

if (nr_elemente_nenule >= 4) //daca inca sunt 4 elemente nenule

{

matrice_homografie = Features2DToolbox.GetHomographyMatrixFromMatchedFeatures(vpc_imagine_de_cautat, vpc_imagine_cadru, m_indicii, m_masca, threshold_reproiectare);

}

}

imagine_de_cautat_cu_contur = imagine_de_cautat.Copy(); //generare copie a imaginii de cautat pentru prelucrari ulterioare

imagine_de_cautat_cu_contur.Draw(new Rectangle(1, 1, imagine_de_cautat_cu_contur.Width – 3, imagine_de_cautat_cu_contur.Height – 3), culoare_chenar_imagine_gasita, 2);

if (cbPuncteInteres.Checked == true && cbLiniiSimilaritate.Checked == true)

{

imagine_rezultat = Features2DToolbox.DrawMatches(imagine_de_cautat_cu_contur, vpc_imagine_de_cautat, imagine_cadru, vpc_imagine_cadru, m_indicii, culoare_linii_similaritate, culoare_puncte_interes, m_masca, Features2DToolbox.KeypointDrawType.DEFAULT);

}

if (cbPuncteInteres.Checked == true && cbLiniiSimilaritate.Checked == false)

{

imagine_rezultat = Features2DToolbox.DrawKeypoints(imagine_cadru, vpc_imagine_cadru, culoare_puncte_interes, Features2DToolbox.KeypointDrawType.DEFAULT);

imagine_de_cautat_cu_contur = Features2DToolbox.DrawKeypoints(imagine_de_cautat_cu_contur, vpc_imagine_de_cautat, culoare_puncte_interes, Features2DToolbox.KeypointDrawType.DEFAULT);

imagine_rezultat = imagine_rezultat.ConcateHorizontal(imagine_de_cautat_cu_contur);

cbLiniiSimilaritate.Enabled = true;

}

if (cbPuncteInteres.Checked == false && cbLiniiSimilaritate.Checked == false)

{

imagine_rezultat = imagine_cadru;

imagine_rezultat = imagine_rezultat.ConcateHorizontal(imagine_de_cautat_cu_contur);

cbLiniiSimilaritate.Enabled = false;

}

if (cbPuncteInteres.Checked == false && cbLiniiSimilaritate.Checked == true)

{

cbLiniiSimilaritate.Checked = false;

}

//desenare chenar in jurul imaginii de cautat regasita in imaginea cadru

if (matrice_homografie != null) //daca matricea de homografie este nenula

{

numar_similaritati_partial.Add(true);

dreptunghi_imagine_de_cautat = new Rectangle(); //declarare dreptunghi imagine de cautat si stabilire valori initiale pentru constructie

dreptunghi_imagine_de_cautat.X = 0;

dreptunghi_imagine_de_cautat.Y = 0;

dreptunghi_imagine_de_cautat.Width = imagine_de_cautat_gri.Width;

dreptunghi_imagine_de_cautat.Height = imagine_de_cautat_gri.Height;

//initializare vector puncte dreptunghi

puncte_float = new PointF[] { new PointF(dreptunghi_imagine_de_cautat.Left, dreptunghi_imagine_de_cautat.Top), new PointF(dreptunghi_imagine_de_cautat.Right, dreptunghi_imagine_de_cautat.Top), new PointF(dreptunghi_imagine_de_cautat.Right, dreptunghi_imagine_de_cautat.Bottom), new PointF(dreptunghi_imagine_de_cautat.Left, dreptunghi_imagine_de_cautat.Bottom) };

matrice_homografie.ProjectPoints(puncte_float);

puncte_int = new Point[] { Point.Round(puncte_float[0]), Point.Round(puncte_float[1]), Point.Round(puncte_float[2]), Point.Round(puncte_float[3]) };

imagine_rezultat.DrawPolyline(puncte_int, true, culoare_chenar_imagine_gasita, 2);

}

else

{

numar_similaritati_partial.Add(false);

}

imagine_rezultat = imagine_rezultat.Resize(pbVideo.Width, pbVideo.Height, INTER.CV_INTER_CUBIC, true);

pbVideo.Image = imagine_rezultat.ToBitmap();

}

}

//functie pentru preluarea unui cadru de la elementul de captura si transpunerea lui in ImageBox

private void proceseaza_cadru_detecteaza_similaritati(object sender, EventArgs arg)

{

Image<Bgr, Byte> cadru_image_box_primar = captura.QueryFrame();

if (cadru_image_box_primar != null)

{

Image<Bgr, Byte> cadru_image_box = cadru_image_box_primar.Resize(pbVideo.Width, pbVideo.Height, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR);

Bitmap img = cadru_image_box.ToBitmap();

//Pen pen = new Pen(Color.LightSalmon, 2);

Graphics graf = Graphics.FromImage(img);

Rectangle rect = new Rectangle(0, 0, pbVideo.Width, Convert.ToInt32(pbVideo.Height / 11));

StringFormat sf = new StringFormat();

sf.Alignment = StringAlignment.Center;

graf.FillRectangle(new SolidBrush(Color.LightSalmon), rect);

graf.DrawString("Pentru capturarea elementului grafic de cautat prin intermediul camerei atasate robotului plasati elementul in spectrul vizibil al aceseia si apasati butonul 'Captureaza'", new Font("Century Gothic", pbVideo.Height / 40, FontStyle.Regular), Brushes.DimGray, rect, sf);

pbVideo.Image = img;

}

}

//functie pentru detectie siluete

private void detecteaza_siluete(object sender, EventArgs arg)

{

//procesul de detectie siluete

Image<Bgr, Byte> cadru_image_box_primar = captura.QueryFrame();

if (cadru_image_box_primar != null)

{

Image<Bgr, Byte> cadru_image_box = cadru_image_box_primar.Resize(pbVideo.Width, pbVideo.Height, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR);

Rectangle[] siluete;

//verifica daca exista procesor grafic (GPU) care sa fie compatibil cu procesul de detectie siluete

if (GpuInvoke.HasCuda)

{

//versiunea GPU

using (GpuHOGDescriptor des = new GpuHOGDescriptor())

{

des.SetSVMDetector(GpuHOGDescriptor.GetDefaultPeopleDetector());

using (GpuImage<Bgr, Byte> gpuImg = new GpuImage<Bgr, byte>(cadru_image_box))

using (GpuImage<Bgra, Byte> gpuBgra = gpuImg.Convert<Bgra, Byte>())

{

siluete = des.DetectMultiScale(gpuBgra);

}

}

}

else

{

//versiunea CPU

using (HOGDescriptor des = new HOGDescriptor())

{

des.SetSVMDetector(HOGDescriptor.GetDefaultPeopleDetector());

siluete = des.DetectMultiScale(cadru_image_box);

}

}

//stocheaza numarul de siluete pentru analiza

numar_siluete_partial.Add(siluete.Length);

foreach (Rectangle silueta in siluete)

{

cadru_image_box.Draw(silueta, new Bgr(Color.Red), 2);

}

pbVideo.Image = cadru_image_box.ToBitmap();

}

}

//functie pentru detectie caractere

private void detecteaza_caractere(Image<Bgr, Byte> imagine_sursa)

{

if (imagine_sursa != null)

{

//Image<Bgr, Byte> cadru_image_box = imagine_sursa.Resize(pbVideo.Width, pbVideo.Height, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR);

pbVideo.BackColor = Color.White;

pbVideo.BackgroundImage = null;

pbVideo.Image = imagine_sursa.ToBitmap();

tess.Recognize(imagine_sursa);

tbMesajDetectieCaractere.BackColor = Color.LightGreen;

tbMesajDetectieCaractere.Text = tess.GetText();

pbVideo.Image = imagine_sursa.ToBitmap();

}

}

private void detecteaza_numere_inmatriculare(object sender, EventArgs arg)

{

//procesul de detectie siluete

Image<Bgr, Byte> cadru_image_box_primar = captura.QueryFrame();

if (cadru_image_box_primar != null)

{

Image<Bgr, Byte> cadru_image_box = cadru_image_box_primar.Resize(pbVideo.Width, pbVideo.Height, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR);

imagini_numere_inmatriculare = new List<Image<Gray, byte>>();

imagini_numere_inmatriculare_filtrate = new List<Image<Gray, byte>>();

regiuni_numere_inmatriculare = new List<MCvBox2D>();

cuvinte_numere_inmatriculare = detector.detecteaza_numar_inmatriculare(cadru_image_box, imagini_numere_inmatriculare, imagini_numere_inmatriculare_filtrate, regiuni_numere_inmatriculare);

imagini_numere_inmatriculare_partial.AddRange(imagini_numere_inmatriculare);

imagini_numere_inmatriculare_filtrate_partial.AddRange(imagini_numere_inmatriculare_filtrate);

regiuni_numere_inmatriculare_partial.AddRange(regiuni_numere_inmatriculare);

cuvinte_numere_inmatriculare_partial.AddRange(cuvinte_numere_inmatriculare);

//for (int i = 0; i < cuvinte_numere_inmatriculare.Count; i++)

//{

// cadru_image_box.Draw(regiuni_numere_inmatriculare[i], new Bgr(Color.Red), 2);

//}

pbVideo.Image = cadru_image_box.ToBitmap();

}

}

//scalare form si controale asociate

private void scaleaza_form(float raport_latime, float raport_inaltime)

{

foreach (Control c in this.Controls)

{

c.Width = Convert.ToInt32(c.Width * raport_latime);

c.Height = Convert.ToInt32(c.Height * raport_inaltime);

c.Left = Convert.ToInt32(c.Left * raport_latime);

c.Top = Convert.ToInt32(c.Top * raport_inaltime);

}

foreach (Control c in gbSetari.Controls)

{

c.Width = Convert.ToInt32(c.Width * raport_latime);

c.Height = Convert.ToInt32(c.Height * raport_inaltime);

c.Left = Convert.ToInt32(c.Left * raport_latime);

c.Top = Convert.ToInt32(c.Top * raport_inaltime);

}

foreach (Control c in gbControl.Controls)

{

c.Width = Convert.ToInt32(c.Width * raport_latime);

c.Height = Convert.ToInt32(c.Height * raport_inaltime);

c.Left = Convert.ToInt32(c.Left * raport_latime);

c.Top = Convert.ToInt32(c.Top * raport_inaltime);

}

foreach (Control c in gbVideo.Controls)

{

c.Width = Convert.ToInt32(c.Width * raport_latime);

c.Height = Convert.ToInt32(c.Height * raport_inaltime);

c.Left = Convert.ToInt32(c.Left * raport_latime);

c.Top = Convert.ToInt32(c.Top * raport_inaltime);

}

foreach (Control c in gbSetariVideo.Controls)

{

c.Width = Convert.ToInt32(c.Width * raport_latime);

c.Height = Convert.ToInt32(c.Height * raport_inaltime);

c.Left = Convert.ToInt32(c.Left * raport_latime);

c.Top = Convert.ToInt32(c.Top * raport_inaltime);

}

foreach (Control c in gbSenzori.Controls)

{

c.Width = Convert.ToInt32(c.Width * raport_latime);

c.Height = Convert.ToInt32(c.Height * raport_inaltime);

c.Left = Convert.ToInt32(c.Left * raport_latime);

c.Top = Convert.ToInt32(c.Top * raport_inaltime);

}

foreach (Control c in pInfoSenzori.Controls)

{

c.Width = Convert.ToInt32(c.Width * raport_latime);

c.Height = Convert.ToInt32(c.Height * raport_inaltime);

c.Left = Convert.ToInt32(c.Left * raport_latime);

c.Top = Convert.ToInt32(c.Top * raport_inaltime);

}

foreach (Control c in ctProcesareImagine.Controls)

{

c.Width = Convert.ToInt32(c.Width * raport_latime);

c.Height = Convert.ToInt32(c.Height * raport_inaltime);

c.Left = Convert.ToInt32(c.Left * raport_latime);

c.Top = Convert.ToInt32(c.Top * raport_inaltime);

}

foreach (TabPage tp in ctProcesareImagine.TabPages)

{

foreach (Control c in tp.Controls)

{

c.Width = Convert.ToInt32(c.Width * raport_latime);

c.Height = Convert.ToInt32(c.Height * raport_inaltime);

c.Left = Convert.ToInt32(c.Left * raport_latime);

c.Top = Convert.ToInt32(c.Top * raport_inaltime);

}

}

foreach (TabPage tp in ctDetectieCaractere.TabPages)

{

foreach (Control c in tp.Controls)

{

c.Width = Convert.ToInt32(c.Width * raport_latime);

c.Height = Convert.ToInt32(c.Height * raport_inaltime);

c.Left = Convert.ToInt32(c.Left * raport_latime);

c.Top = Convert.ToInt32(c.Top * raport_inaltime);

}

}

}

//eveniment decalnsat la modificarea dimensiunii formului

private void Main_SizeChanged(object sender, EventArgs e)

{

latime_noua = this.Width;

inaltime_noua = this.Height;

float w = (float)latime_noua / latime_curenta;

float h = (float)inaltime_noua / inaltime_curenta;

scaleaza_form(w, h);

latime_curenta = latime_noua;

inaltime_curenta = inaltime_noua;

}

public static Image ScalareImagine(Image image, int maxWidth, int maxHeight)

{

var ratioX = (double)maxWidth / image.Width;

var ratioY = (double)maxHeight / image.Height;

var ratio = Math.Min(ratioX, ratioY);

var newWidth = (int)(image.Width * ratio);

var newHeight = (int)(image.Height * ratio);

var newImage = new Bitmap(newWidth, newHeight);

Graphics.FromImage(newImage).DrawImage(image, 0, 0, newWidth, newHeight);

return newImage;

}

//––––––––––––––––––––––––––-

//proceseaza cadru

//eveniment declansat la modificarea tbLuminozitate

private void tbLuminozitate_Scroll(object sender, EventArgs e)

{

tbValoareLuminozitate.Text = tbLuminozitate.Value.ToString();

if (captura != null)

{

captura.SetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_BRIGHTNESS, luminozitate + (tbLuminozitate.Value * 20));

}

}

//eveniment declansat la modificarea tbContrast

private void tbContrast_Scroll(object sender, EventArgs e)

{

tbValoareContrast.Text = tbContrast.Value.ToString();

if (captura != null)

{

captura.SetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_CONTRAST, contrast + tbContrast.Value);

}

}

//eveniment declansat la modificarea tbClaritate

private void tbClaritate_Scroll(object sender, EventArgs e)

{

tbValoareClaritate.Text = tbClaritate.Value.ToString();

if (captura != null)

{

captura.SetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_SHARPNESS, claritate + tbClaritate.Value);

}

}

//––––––––––––––––––––––––––-

//detectie faciala

//eveniment declansat la modificarea tbScala

private void tbScala_Scroll(object sender, EventArgs e)

{

tbValoareScala.Text = tbScala.Value.ToString();

if (captura != null)

{

Application.Idle -= detecteaza_fete;

scala_df = 1 + (Convert.ToDouble(tbScala.Value) / 10);

Application.Idle += detecteaza_fete;

}

}

//eveniment declansat la modificarea tbNrMinVecini

private void tbNrMinVecini_Scroll(object sender, EventArgs e)

{

tbValoareNrMinVecini.Text = tbNrMinVecini.Value.ToString();

if (captura != null)

{

Application.Idle -= detecteaza_fete;

treshold_nr_minim_vecini_df = Convert.ToInt32(tbNrMinVecini.Value);

Application.Idle += detecteaza_fete;

}

}

//eveniment declansat la selectarea rbFidelitateRidicata

private void rbFidelitateRidicata_CheckedChanged(object sender, EventArgs e)

{

if (rbFidelitateRidicata.Checked == true)

{

Application.Idle -= detecteaza_fete;

tip_detectie_df = Emgu.CV.CvEnum.HAAR_DETECTION_TYPE.DO_CANNY_PRUNING;

Application.Idle += detecteaza_fete;

}

}

//eveniment declansat la selectarea rbFidelitateScazuta

private void rbFidelitateScazuta_CheckedChanged(object sender, EventArgs e)

{

if (rbFidelitateScazuta.Checked == true)

{

Application.Idle -= detecteaza_fete;

tip_detectie_df = 0;

Application.Idle += detecteaza_fete;

}

}

//––––––––––––––––––––––––––-

//cronometru

//eveniment declansat o data la 2 secunde – cronometru

private void cron_Tick(object sender, EventArgs e)

{

if (ctProcesareImagine.SelectedIndex == 1)

{

var query = (from val in numar_fete_partial group val by val into g orderby g.Count() descending select g.Key).First();

numar_fete_partial.Clear();

if (Convert.ToInt32(query) != 0)

{

tbMesajDetectieFaciala.BackColor = Color.LightGreen;

tbMesajDetectieFaciala.Text = "Numar de fete detectate: " + query.ToString();

}

else

{

tbMesajDetectieFaciala.BackColor = Color.Gold;

tbMesajDetectieFaciala.Text = "Nu au fost detectate fete!";

}

}

if (ctProcesareImagine.SelectedIndex == 2 && imagine_de_cautat!=null)

{

var query = (from val in numar_similaritati_partial group val by val into g orderby g.Count() descending select g.Key).First();

numar_similaritati_partial.Clear();

if (Convert.ToBoolean(query) == true)

{

tbMesajDetectieSimilaritati.BackColor = Color.LightGreen;

tbMesajDetectieSimilaritati.Text = "Elemente similare detectate!";

}

else

{

tbMesajDetectieSimilaritati.BackColor = Color.Gold;

tbMesajDetectieSimilaritati.Text = "Nu au fost detectate elemente similare!";

}

}

if (ctProcesareImagine.SelectedIndex == 3)

{

var query = (from val in numar_siluete_partial group val by val into g orderby g.Count() descending select g.Key).First();

numar_siluete_partial.Clear();

if (Convert.ToInt32(query) != 0)

{

tbMesajDetectieSiluete.BackColor = Color.LightGreen;

tbMesajDetectieSiluete.Text = "Numar de siluete detectate: " + query.ToString();

chDetectieSiluete.Series["Numar siluete"].Points.AddXY(DateTime.Now.ToLongTimeString(), query);

}

else

{

tbMesajDetectieSiluete.BackColor = Color.Gold;

tbMesajDetectieSiluete.Text = "Nu au fost detectate siluete!";

chDetectieSiluete.Series["Numar siluete"].Points.AddXY(DateTime.Now.ToLongTimeString(), 0);

}

}

if (ctProcesareImagine.SelectedIndex == 4)

{

try

{

var query = (from val in cuvinte_numere_inmatriculare_partial group val by val into g orderby g.Count() descending select g.Key).First();

int index = cuvinte_numere_inmatriculare_partial.IndexOf(query);

if (query != null)

{

tbMesajDetectieCaractere.BackColor = Color.LightGreen;

tbMesajDetectieCaractere.Text = query.ToString();

pbDCD.Image = imagini_numere_inmatriculare_partial[index].ConcateVertical(imagini_numere_inmatriculare_filtrate_partial[index]).ToBitmap();

}

imagini_numere_inmatriculare_partial.Clear();

imagini_numere_inmatriculare_filtrate_partial.Clear();

regiuni_numere_inmatriculare_partial.Clear();

cuvinte_numere_inmatriculare_partial.Clear();

}

catch (Exception ex)

{

//nu face nimic

}

}

}

//––––––––––––––––––––––––––-

//detectie similaritati

//eveniment declansat la apasarea butonului captureaza

private void bCaptureazaDetectieSimilaritati_Click(object sender, EventArgs e)

{

if (imagine_de_cautat == null)

{

Image<Bgr, Byte> cadru_image_box_primar = captura.QueryFrame();

if (cadru_image_box_primar != null)

{

//schimba text buton

bCaptureazaDetectieSimilaritati.Text = "Actualizati imaginea de cautat";

//mesaj

tbMesajDetectieSimilaritati.BackColor = Color.LightSalmon;

tbMesajDetectieSimilaritati.Text = "Se analizeaza fluxul video…";

cbPuncteInteres.Enabled = true;

cbLiniiSimilaritate.Enabled = true;

cbDetectieSimilaritati.Enabled = true;

tbDetectieSimilaritati.Enabled = true;

//captureaza imagine de cautat din fluxul video

imagine_de_cautat = cadru_image_box_primar.Resize(pbVideo.Width, pbVideo.Height, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR);

//modifica layout

pbVideo.BackgroundImage = null;

pbVideo.BackColor = Color.Black;

Application.Idle -= proceseaza_cadru_detecteaza_similaritati;

Application.Idle += detecteaza_similaritati;

}

}

else

{

Application.Idle -= detecteaza_similaritati;

Application.Idle += proceseaza_cadru_detecteaza_similaritati;

imagine_de_cautat = null;

bCaptureazaDetectieSimilaritati.Text = "Captureaza";

tbDSImDeGasit.Text = "";

//mesaj

tbMesajDetectieSimilaritati.BackColor = Color.LightSalmon;

tbMesajDetectieSimilaritati.Text = "Selectati imaginea de cautat!";

cbPuncteInteres.Enabled = false;

cbLiniiSimilaritate.Enabled = false;

cbDetectieSimilaritati.Enabled = false;

tbDetectieSimilaritati.Enabled = false;

}

}

//eveniment declansat la modificarea indexului din combobox detectie similaritati

private void cbDetectieSimilaritati_SelectedIndexChanged(object sender, EventArgs e)

{

if (cbDetectieSimilaritati.SelectedIndex == cbDetectieSimilaritati.Items.IndexOf("Numar vecini"))

{

tbDetectieSimilaritati.Minimum = 2;

tbDetectieSimilaritati.Maximum = 10;

tbDetectieSimilaritati.Value = numar_vecini_ds;

tbValoareDetectieSimilaritati.Text = numar_vecini_ds.ToString();

tbDetectieSimilaritati.Focus();

}

if (cbDetectieSimilaritati.SelectedIndex == cbDetectieSimilaritati.Items.IndexOf("Threshold unicitate"))

{

tbDetectieSimilaritati.Minimum = 0;

tbDetectieSimilaritati.Maximum = 10;

tbDetectieSimilaritati.Value = Convert.ToInt32(threshold_unicitate_ds * 10);

tbValoareDetectieSimilaritati.Text = threshold_unicitate_ds.ToString();

tbDetectieSimilaritati.Focus();

}

if (cbDetectieSimilaritati.SelectedIndex == cbDetectieSimilaritati.Items.IndexOf("Increment scala"))

{

tbDetectieSimilaritati.Minimum = 1;

tbDetectieSimilaritati.Maximum = 10;

tbDetectieSimilaritati.Value = Convert.ToInt32((increment_scala_ds – 1) * 10);

tbValoareDetectieSimilaritati.Text = increment_scala_ds.ToString();

tbDetectieSimilaritati.Focus();

}

if (cbDetectieSimilaritati.SelectedIndex == cbDetectieSimilaritati.Items.IndexOf("Segmente rotatie"))

{

tbDetectieSimilaritati.Minimum = 1;

tbDetectieSimilaritati.Maximum = 5;

tbDetectieSimilaritati.Value = segmente_rotatie_ds / 10;

tbValoareDetectieSimilaritati.Text = segmente_rotatie_ds.ToString();

tbDetectieSimilaritati.Focus();

}

}

//eveniment declansat la modificarea tbDetectieSimilaritati

private void tbDetectieSimilaritati_Scroll(object sender, EventArgs e)

{

if (cbDetectieSimilaritati.SelectedIndex == cbDetectieSimilaritati.Items.IndexOf("Numar vecini"))

{

if (captura != null)

{

Application.Idle -= detecteaza_similaritati;

numar_vecini_ds = tbDetectieSimilaritati.Value;

tbValoareDetectieSimilaritati.Text = numar_vecini_ds.ToString();

Application.Idle += detecteaza_similaritati;

}

}

if (cbDetectieSimilaritati.SelectedIndex == cbDetectieSimilaritati.Items.IndexOf("Threshold unicitate"))

{

if (captura != null)

{

Application.Idle -= detecteaza_similaritati;

threshold_unicitate_ds = (double)tbDetectieSimilaritati.Value / 10;

tbValoareDetectieSimilaritati.Text = threshold_unicitate_ds.ToString();

Application.Idle += detecteaza_similaritati;

}

}

if (cbDetectieSimilaritati.SelectedIndex == cbDetectieSimilaritati.Items.IndexOf("Increment scala"))

{

if (captura != null)

{

Application.Idle -= detecteaza_similaritati;

increment_scala_ds = ((double)tbDetectieSimilaritati.Value / 10)+1;

tbValoareDetectieSimilaritati.Text = increment_scala_ds.ToString();

Application.Idle += detecteaza_similaritati;

}

}

if (cbDetectieSimilaritati.SelectedIndex == cbDetectieSimilaritati.Items.IndexOf("Segmente rotatie"))

{

if (captura != null)

{

Application.Idle -= detecteaza_similaritati;

segmente_rotatie_ds = tbDetectieSimilaritati.Value * 10;

tbValoareDetectieSimilaritati.Text = segmente_rotatie_ds.ToString();

Application.Idle += detecteaza_similaritati;

}

}

}

//eveniment declansat la apasarea butonului bImDeGasit

private void bImDeGasit_Click(object sender, EventArgs e)

{

if (imagine_de_cautat == null)

{

DialogResult dr = ofdDSImagineDeCautat.ShowDialog();

if (dr == DialogResult.OK || dr == DialogResult.Yes)

{

tbDSImDeGasit.Text = ofdDSImagineDeCautat.FileName;

}

else

{

return;

}

try

{

imagine_de_cautat = new Image<Bgr, Byte>(tbDSImDeGasit.Text);

}

catch

{

MessageBox.Show("Incarcarea nu a avut loc cu succes. Reincercati!");

imagine_de_cautat = null;

return;

}

if (imagine_de_cautat != null)

{

//schimba text buton

bCaptureazaDetectieSimilaritati.Text = "Actualizati imaginea de cautat";

//mesaj

tbMesajDetectieSimilaritati.BackColor = Color.LightSalmon;

tbMesajDetectieSimilaritati.Text = "Se analizeaza fluxul video…";

cbPuncteInteres.Enabled = true;

cbLiniiSimilaritate.Enabled = true;

cbDetectieSimilaritati.Enabled = true;

tbDetectieSimilaritati.Enabled = true;

//modifica layout

pbVideo.BackgroundImage = null;

pbVideo.BackColor = Color.Black;

Application.Idle -= proceseaza_cadru_detecteaza_similaritati;

Application.Idle += detecteaza_similaritati;

}

}

else

{

imagine_de_cautat = null;

Application.Idle -= detecteaza_similaritati;

Application.Idle += proceseaza_cadru_detecteaza_similaritati;

DialogResult dr = ofdDSImagineDeCautat.ShowDialog();

if (dr == DialogResult.OK || dr == DialogResult.Yes)

{

tbDSImDeGasit.Text = ofdDSImagineDeCautat.FileName;

}

else

{

return;

}

try

{

imagine_de_cautat = new Image<Bgr, Byte>(tbDSImDeGasit.Text);

}

catch

{

MessageBox.Show("Incarcarea nu a avut loc cu succes. Reincercati!");

imagine_de_cautat = null;

return;

}

if (imagine_de_cautat != null)

{

//schimba text buton

bCaptureazaDetectieSimilaritati.Text = "Actualizati imaginea de cautat";

//mesaj

tbMesajDetectieSimilaritati.BackColor = Color.LightSalmon;

tbMesajDetectieSimilaritati.Text = "Se analizeaza fluxul video…";

cbPuncteInteres.Enabled = true;

cbLiniiSimilaritate.Enabled = true;

cbDetectieSimilaritati.Enabled = true;

tbDetectieSimilaritati.Enabled = true;

//modifica layout

pbVideo.BackgroundImage = null;

pbVideo.BackColor = Color.Black;

Application.Idle -= proceseaza_cadru_detecteaza_similaritati;

Application.Idle += detecteaza_similaritati;

}

}

}

//––––––––––––––––––––––––––-

//detectie caractere

//eveniment declansat la apasarea butonului bDCSAlegetiImaginea

private void bDCSAlegetiImaginea_Click(object sender, EventArgs e)

{

DialogResult dr = ofdDCSAlegetiImaginea.ShowDialog();

if (dr == DialogResult.OK || dr == DialogResult.Yes)

{

tbDCSAlegetiImaginea.Text = ofdDCSAlegetiImaginea.FileName;

}

else

{

return;

}

try

{

imagine_OCR = new Image<Bgr, Byte>(tbDCSAlegetiImaginea.Text);

}

catch

{

MessageBox.Show("Incarcarea nu a avut loc cu succes. Reincercati!");

imagine_OCR = null;

return;

}

if (imagine_OCR != null)

{

detecteaza_caractere(imagine_OCR);

}

}

//eveniment declansat la navigarea prin taburile ctDetectieCaractere

private void ctDetectieCaractere_SelectedIndexChanged(object sender, EventArgs e)

{

//daca este selectat primul tab – Dinamic

if (ctDetectieCaractere.SelectedIndex == 0)

{

tbMesajDetectieCaractere.BackColor = Color.LightSalmon;

tbMesajDetectieCaractere.Text = "Se analizeaza fluxul video…";

Application.Idle += detecteaza_numere_inmatriculare;

cron.Start();

}

//daca este selectat primul tab – Static

if (ctDetectieCaractere.SelectedIndex == 1)

{

Application.Idle -= detecteaza_numere_inmatriculare;

cron.Stop();

tbMesajDetectieCaractere.BackColor = Color.LightSalmon;

tbMesajDetectieCaractere.Text = "Selectati imaginea sursa!";

}

}

//eveniment declansat la modificarea indexului din combobox detectie caractere-dinamic

private void cbDetectieCaractere_SelectedIndexChanged(object sender, EventArgs e)

{

if (cbDetectieCaractere.SelectedIndex == cbDetectieCaractere.Items.IndexOf("Threshold binarizare"))

{

tbDetectieCaractere.Minimum = 70;

tbDetectieCaractere.Maximum = 130;

tbDetectieCaractere.Value = detector.threshold_binarizare;

tbValoareDetectieCaractere.Text = detector.threshold_binarizare.ToString();

tbDetectieCaractere.Focus();

}

if (cbDetectieCaractere.SelectedIndex == cbDetectieCaractere.Items.IndexOf("Threshold contur"))

{

tbDetectieCaractere.Minimum = 100;

tbDetectieCaractere.Maximum = 200;

tbDetectieCaractere.Value = detector.threshold_contur;

tbValoareDetectieCaractere.Text = detector.threshold_contur.ToString();

tbDetectieCaractere.Focus();

}

if (cbDetectieCaractere.SelectedIndex == cbDetectieCaractere.Items.IndexOf("Threshold unificare contur"))

{

tbDetectieCaractere.Minimum = 150;

tbDetectieCaractere.Maximum = 250;

tbDetectieCaractere.Value = detector.threshold_unificare_contur;

tbValoareDetectieCaractere.Text = detector.threshold_unificare_contur.ToString();

tbDetectieCaractere.Focus();

}

}

//eveniment declansat la modificarea tbDetectieCaractere

private void tbDetectieCaractere_Scroll(object sender, EventArgs e)

{

if (cbDetectieCaractere.SelectedIndex == cbDetectieCaractere.Items.IndexOf("Threshold binarizare"))

{

if (captura != null)

{

Application.Idle -= detecteaza_numere_inmatriculare;

Application.Idle -= preview_threshold_binarizare;

detector.threshold_binarizare = tbDetectieCaractere.Value;

tbValoareDetectieCaractere.Text = detector.threshold_binarizare.ToString();

Application.Idle += preview_threshold_binarizare;

}

}

if (cbDetectieCaractere.SelectedIndex == cbDetectieCaractere.Items.IndexOf("Threshold contur"))

{

if (captura != null)

{

Application.Idle -= detecteaza_numere_inmatriculare;

Application.Idle -= preview_threshold_contur;

detector.threshold_contur = tbDetectieCaractere.Value;

tbValoareDetectieCaractere.Text = detector.threshold_contur.ToString();

Application.Idle += preview_threshold_contur;

}

}

if (cbDetectieCaractere.SelectedIndex == cbDetectieCaractere.Items.IndexOf("Threshold unificare contur"))

{

if (captura != null)

{

Application.Idle -= detecteaza_numere_inmatriculare;

Application.Idle -= preview_threshold_contur;

detector.threshold_unificare_contur = tbDetectieCaractere.Value;

tbValoareDetectieCaractere.Text = detector.threshold_unificare_contur.ToString();

Application.Idle += preview_threshold_contur;

}

}

}

//functie pentru preview modificari imagine la modificarea parametrului "Threshold binarizare"

private void preview_threshold_binarizare(object sender, EventArgs arg)

{

Image<Bgr, Byte> cadru_image_box_primar = captura.QueryFrame();

if (cadru_image_box_primar != null)

{

Image<Bgr, Byte> cadru_image_box = cadru_image_box_primar.Resize(pbVideo.Width, pbVideo.Height, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR);

Image<Gray, Byte> final = cadru_image_box.Convert<Gray, Byte>().ThresholdBinaryInv(new Gray(detector.threshold_binarizare), new Gray(255));

pbVideo.Image = final.ToBitmap();

}

}

//functie pentru preview modificari imagine la modificarea parametrului "Threshold contur" si "Threshold unificare contur"

private void preview_threshold_contur(object sender, EventArgs arg)

{

Image<Bgr, Byte> cadru_image_box_primar = captura.QueryFrame();

if (cadru_image_box_primar != null)

{

Image<Bgr, Byte> cadru_image_box = cadru_image_box_primar.Resize(pbVideo.Width, pbVideo.Height, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR);

Image<Gray, Byte> final = cadru_image_box.Canny(detector.threshold_contur, detector.threshold_unificare_contur);

pbVideo.Image = final.ToBitmap();

}

}

//eveniment declansat la eliberarea butoanelor mouse-ului

private void tbDetectieCaractere_MouseUp(object sender, MouseEventArgs e)

{

Application.Idle -= preview_threshold_binarizare;

Application.Idle -= preview_threshold_contur;

Application.Idle += detecteaza_numere_inmatriculare;

}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//functie pentru preluarea unui cadru de la elementul de captura si transpunerea lui in ImageBox

private void test(object sender, EventArgs arg)

{

}

private void bTest_Click(object sender, EventArgs e)

{

Application.Idle -= proceseaza_cadru;

Application.Idle -= detecteaza_fete;

Application.Idle -= detecteaza_similaritati;

Application.Idle -= proceseaza_cadru_detecteaza_similaritati;

Application.Idle -= detecteaza_siluete;

Application.Idle += test;

}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//functie full screen

private void pbVideo_DoubleClick(object sender, EventArgs e)

{

if (esteFullScreen == false)

{

//modificare flag

esteFullScreen = true;

//setare proprietate invizibil pentru toate controalele

foreach (Control ctrl in this.Controls)

{

ctrl.Visible = false;

}

//–––––––––––––––––––––––––––––

//gbVideo

//calculare raport scalare gbVideo

double raport_scalare_full_screen_orizontal_gbVideo = (double)this.Width / gbVideo.Width;

double raport_scalare_full_screen_vertical_gbVideo = (double)this.Height / gbVideo.Height;

factor_scalare_fullscreen_gbVideo = Math.Min(raport_scalare_full_screen_orizontal_gbVideo, raport_scalare_full_screen_vertical_gbVideo);

//salvare date initiale gbVideo

locatie_gbVideo = gbVideo.Location;

latime_gbVideo = gbVideo.Width;

inaltime_gbVideo = gbVideo.Height;

gbVideo.Visible = true;

//modificare date gbVideo

gbVideo.Location = new Point(0, 0);

gbVideo.Width = Convert.ToInt32(gbVideo.Width * factor_scalare_fullscreen_gbVideo);

gbVideo.Height = Convert.ToInt32(gbVideo.Height * factor_scalare_fullscreen_gbVideo);

//modificare date pbVideo

pbVideo.Width = Convert.ToInt32(pbVideo.Width * factor_scalare_fullscreen_gbVideo);

pbVideo.Height = Convert.ToInt32(pbVideo.Height * factor_scalare_fullscreen_gbVideo);

//modificare pozitie controale in gbVideo

foreach (Control c in gbVideo.Controls)

{

if (c != pbVideo)

{

c.Top = Convert.ToInt32(c.Top * factor_scalare_fullscreen_gbVideo);

}

}

//–––––––––––––––––––––––––––––

//gbControl

factor_scalare_fullscreen_gbControl = (double)((double)(this.Width – gbVideo.Width) / (double)gbControl.Width);

//salvare date initiale gbControl

locatie_gbControl = gbControl.Location;

latime_gbControl = gbControl.Width;

inaltime_gbControl = gbControl.Height;

gbControl.Visible = true;

//modificare date gbControl

gbControl.Location = new Point(gbVideo.Width, 0);

gbControl.Width = Convert.ToInt32(gbControl.Width * factor_scalare_fullscreen_gbControl);

gbControl.Height = Convert.ToInt32(gbControl.Height * factor_scalare_fullscreen_gbControl);

//modificare pozitie controale in gbControl

foreach (Control c in gbControl.Controls)

{

c.Width = Convert.ToInt32(c.Width * factor_scalare_fullscreen_gbControl);

c.Height = Convert.ToInt32(c.Height * factor_scalare_fullscreen_gbControl);

c.Left = Convert.ToInt32(c.Left * factor_scalare_fullscreen_gbControl);

c.Top = Convert.ToInt32(c.Top * factor_scalare_fullscreen_gbControl);

}

//–––––––––––––––––––––––––––––

//gbSenzori

factor_scalare_fullscreen_gbSenzori = (double)((double)(this.Width – gbVideo.Width) / (double)gbSenzori.Width);

//salvare date initiale gbSenzori

locatie_gbSenzori = gbSenzori.Location;

latime_gbSenzori = gbSenzori.Width;

inaltime_gbSenzori = gbSenzori.Height;

gbSenzori.Visible = true;

//modificare date gbSenzori

gbSenzori.Location = new Point(gbVideo.Width, gbControl.Height);

gbSenzori.Width = Convert.ToInt32(gbSenzori.Width * factor_scalare_fullscreen_gbSenzori);

gbSenzori.Height = Convert.ToInt32(gbSenzori.Height * factor_scalare_fullscreen_gbSenzori);

foreach (Control c in gbSenzori.Controls)

{

c.Width = Convert.ToInt32(c.Width * factor_scalare_fullscreen_gbSenzori);

c.Height = Convert.ToInt32(c.Height * factor_scalare_fullscreen_gbSenzori);

c.Left = Convert.ToInt32(c.Left * factor_scalare_fullscreen_gbSenzori);

c.Top = Convert.ToInt32(c.Top * factor_scalare_fullscreen_gbSenzori);

}

foreach (Control c in pInfoSenzori.Controls)

{

c.Width = Convert.ToInt32(c.Width * factor_scalare_fullscreen_gbSenzori);

c.Height = Convert.ToInt32(c.Height * factor_scalare_fullscreen_gbSenzori);

c.Left = Convert.ToInt32(c.Left * factor_scalare_fullscreen_gbSenzori);

c.Top = Convert.ToInt32(c.Top * factor_scalare_fullscreen_gbSenzori);

}

//–––––––––––––––––––––––––––––

//ctProcesareImagine

factor_scalare_fullscreen_ctProcesareImagine = (double)((double)(this.Width – gbVideo.Width) / (double)ctProcesareImagine.Width);

//salvare date initiale ctProcesareImagine

locatie_ctProcesareImagine = ctProcesareImagine.Location;

latime_ctProcesareImagine = ctProcesareImagine.Width;

inaltime_ctProcesareImagine = ctProcesareImagine.Height;

ctProcesareImagine.Visible = true;

//modificare date ctProcesareImagine

ctProcesareImagine.Location = new Point(gbVideo.Width, gbControl.Height+gbSenzori.Height);

ctProcesareImagine.Width = Convert.ToInt32(ctProcesareImagine.Width * factor_scalare_fullscreen_ctProcesareImagine);

ctProcesareImagine.Height = Convert.ToInt32(ctProcesareImagine.Height * factor_scalare_fullscreen_ctProcesareImagine);

//modificare pozitie controale in ctProcesareImagine

foreach (Control c in ctProcesareImagine.Controls)

{

c.Width = Convert.ToInt32(c.Width * factor_scalare_fullscreen_ctProcesareImagine);

c.Height = Convert.ToInt32(c.Height * factor_scalare_fullscreen_ctProcesareImagine);

c.Left = Convert.ToInt32(c.Left * factor_scalare_fullscreen_ctProcesareImagine);

c.Top = Convert.ToInt32(c.Top * factor_scalare_fullscreen_ctProcesareImagine);

}

foreach (TabPage tp in ctProcesareImagine.TabPages)

{

foreach (Control c in tp.Controls)

{

c.Width = Convert.ToInt32(c.Width * factor_scalare_fullscreen_ctProcesareImagine);

c.Height = Convert.ToInt32(c.Height * factor_scalare_fullscreen_ctProcesareImagine);

c.Left = Convert.ToInt32(c.Left * factor_scalare_fullscreen_ctProcesareImagine);

c.Top = Convert.ToInt32(c.Top * factor_scalare_fullscreen_ctProcesareImagine);

}

}

foreach (TabPage tp in ctDetectieCaractere.TabPages)

{

foreach (Control c in tp.Controls)

{

c.Width = Convert.ToInt32(c.Width * factor_scalare_fullscreen_ctProcesareImagine);

c.Height = Convert.ToInt32(c.Height * factor_scalare_fullscreen_ctProcesareImagine);

c.Left = Convert.ToInt32(c.Left * factor_scalare_fullscreen_ctProcesareImagine);

c.Top = Convert.ToInt32(c.Top * factor_scalare_fullscreen_ctProcesareImagine);

}

}

//–––––––––––––––––––––––––––––

//pbRELogo

factor_scalare_fullscreen_pbRELogo = (double)((double)(this.Width – gbVideo.Width) / (double)pbRELogo.Width);

//salvare date initiale gbSenzori

locatie_pbRELogo = pbRELogo.Location;

latime_pbRELogo = pbRELogo.Width;

inaltime_pbRELogo = pbRELogo.Height;

pbRELogo.Visible = true;

//modificare date gbSenzori

pbRELogo.Location = new Point((gbVideo.Width + (this.Width – gbVideo.Width – Convert.ToInt32(pbRELogo.Width * factor_scalare_fullscreen_pbRELogo)) / 2), pbPhoto.Location.Y);

pbRELogo.Width = Convert.ToInt32(pbRELogo.Width * factor_scalare_fullscreen_pbRELogo);

pbRELogo.Height = Convert.ToInt32(pbRELogo.Height * factor_scalare_fullscreen_pbRELogo);

}

else

{

esteFullScreen = false;

foreach (Control ctrl in this.Controls)

{

ctrl.Visible = true;

}

if (captura_in_progres)

{

lProcesareImagine.Visible = true;

ctProcesareImagine.Visible = true;

}

else

{

lProcesareImagine.Visible = false;

ctProcesareImagine.Visible = false;

}

//–––––––––––––––––––––––––––––

//gbVideo

gbVideo.Location = locatie_gbVideo;

gbVideo.Width = latime_gbVideo;

gbVideo.Height = inaltime_gbVideo;

pbVideo.Width = Convert.ToInt32(pbVideo.Width / factor_scalare_fullscreen_gbVideo);

pbVideo.Height = Convert.ToInt32(pbVideo.Height / factor_scalare_fullscreen_gbVideo);

foreach (Control c in gbVideo.Controls)

{

if (c != pbVideo)

{

c.Top = Convert.ToInt32(c.Top / factor_scalare_fullscreen_gbVideo);

}

}

//–––––––––––––––––––––––––––––

//gbControl

gbControl.Location = locatie_gbControl;

gbControl.Width = latime_gbControl;

gbControl.Height = inaltime_gbControl;

foreach (Control c in gbControl.Controls)

{

c.Width = Convert.ToInt32(c.Width / factor_scalare_fullscreen_gbControl);

c.Height = Convert.ToInt32(c.Height / factor_scalare_fullscreen_gbControl);

c.Left = Convert.ToInt32(c.Left / factor_scalare_fullscreen_gbControl);

c.Top = Convert.ToInt32(c.Top / factor_scalare_fullscreen_gbControl);

}

//–––––––––––––––––––––––––––––

//gbSenzori

gbSenzori.Location = locatie_gbSenzori;

gbSenzori.Width = latime_gbSenzori;

gbSenzori.Height = inaltime_gbSenzori;

foreach (Control c in gbSenzori.Controls)

{

c.Width = Convert.ToInt32(c.Width / factor_scalare_fullscreen_gbSenzori);

c.Height = Convert.ToInt32(c.Height / factor_scalare_fullscreen_gbSenzori);

c.Left = Convert.ToInt32(c.Left / factor_scalare_fullscreen_gbSenzori);

c.Top = Convert.ToInt32(c.Top / factor_scalare_fullscreen_gbSenzori);

}

foreach (Control c in pInfoSenzori.Controls)

{

c.Width = Convert.ToInt32(c.Width / factor_scalare_fullscreen_gbSenzori);

c.Height = Convert.ToInt32(c.Height / factor_scalare_fullscreen_gbSenzori);

c.Left = Convert.ToInt32(c.Left / factor_scalare_fullscreen_gbSenzori);

c.Top = Convert.ToInt32(c.Top / factor_scalare_fullscreen_gbSenzori);

}

//–––––––––––––––––––––––––––––

//ctProcesareImagine

ctProcesareImagine.Location = locatie_ctProcesareImagine;

ctProcesareImagine.Width = latime_ctProcesareImagine;

ctProcesareImagine.Height = inaltime_ctProcesareImagine;

foreach (Control c in ctProcesareImagine.Controls)

{

c.Width = Convert.ToInt32(c.Width / factor_scalare_fullscreen_ctProcesareImagine);

c.Height = Convert.ToInt32(c.Height / factor_scalare_fullscreen_ctProcesareImagine);

c.Left = Convert.ToInt32(c.Left / factor_scalare_fullscreen_ctProcesareImagine);

c.Top = Convert.ToInt32(c.Top / factor_scalare_fullscreen_ctProcesareImagine);

}

foreach (TabPage tp in ctProcesareImagine.TabPages)

{

foreach (Control c in tp.Controls)

{

c.Width = Convert.ToInt32(c.Width / factor_scalare_fullscreen_ctProcesareImagine);

c.Height = Convert.ToInt32(c.Height / factor_scalare_fullscreen_ctProcesareImagine);

c.Left = Convert.ToInt32(c.Left / factor_scalare_fullscreen_ctProcesareImagine);

c.Top = Convert.ToInt32(c.Top / factor_scalare_fullscreen_ctProcesareImagine);

}

}

foreach (TabPage tp in ctDetectieCaractere.TabPages)

{

foreach (Control c in tp.Controls)

{

c.Width = Convert.ToInt32(c.Width / factor_scalare_fullscreen_ctProcesareImagine);

c.Height = Convert.ToInt32(c.Height / factor_scalare_fullscreen_ctProcesareImagine);

c.Left = Convert.ToInt32(c.Left / factor_scalare_fullscreen_ctProcesareImagine);

c.Top = Convert.ToInt32(c.Top / factor_scalare_fullscreen_ctProcesareImagine);

}

}

//–––––––––––––––––––––––––––––

//pbRELogo

pbRELogo.Visible = false;

pbRELogo.Location = locatie_pbRELogo;

pbRELogo.Width = latime_pbRELogo;

pbRELogo.Height = inaltime_pbRELogo;

}

}

//eveniment declansat la navigarea prin taburile ctProcesareImagine

private void ctProcesareImagine_SelectedIndexChanged(object sender, EventArgs e)

{

//daca este selectat primul tab – Captura Video

if (ctProcesareImagine.SelectedIndex == 0)

{

Application.Idle -= detecteaza_fete;

Application.Idle -= detecteaza_similaritati;

Application.Idle -= proceseaza_cadru_detecteaza_similaritati;

Application.Idle -= detecteaza_siluete;

Application.Idle -= detecteaza_numere_inmatriculare;

cron.Stop();

imagine_de_cautat = null;

imagine_OCR = null;

Application.Idle += proceseaza_cadru;

}

//daca este selectat al doilea tab – Detectie faciala

if (ctProcesareImagine.SelectedIndex == 1)

{

Application.Idle -= proceseaza_cadru;

Application.Idle -= detecteaza_similaritati;

Application.Idle -= proceseaza_cadru_detecteaza_similaritati;

Application.Idle -= detecteaza_siluete;

Application.Idle -= detecteaza_numere_inmatriculare;

haar = new Emgu.CV.HaarCascade("haarcascade_frontalface_default.xml");

//mesaj

tbMesajDetectieFaciala.BackColor = Color.LightSalmon;

tbMesajDetectieFaciala.Text = "Se analizeaza fluxul video…";

Application.Idle += detecteaza_fete;

cron.Stop();

imagine_de_cautat = null;

imagine_OCR = null;

cron.Start();

}

//daca este selectat al treilea tab – Detectie similaritati

if (ctProcesareImagine.SelectedIndex == 2)

{

Application.Idle -= proceseaza_cadru;

Application.Idle -= detecteaza_fete;

Application.Idle -= detecteaza_siluete;

Application.Idle -= detecteaza_numere_inmatriculare;

cron.Stop();

tbDSImDeGasit.Text = "";

imagine_OCR = null;

cron.Start();

//mesaj

tbMesajDetectieSimilaritati.BackColor = Color.LightSalmon;

tbMesajDetectieSimilaritati.Text = "Selectati imaginea de cautat!";

//continuare streaming video pentru capturarea imaginii de cautat

Application.Idle += proceseaza_cadru_detecteaza_similaritati;

}

//daca este selectat al patrulea tab – Detectie siluete

if (ctProcesareImagine.SelectedIndex == 3)

{

Application.Idle -= proceseaza_cadru;

Application.Idle -= detecteaza_fete;

Application.Idle -= detecteaza_similaritati;

Application.Idle -= proceseaza_cadru_detecteaza_similaritati;

Application.Idle -= detecteaza_numere_inmatriculare;

cron.Stop();

imagine_de_cautat = null;

imagine_OCR = null;

chDetectieSiluete.Series["Numar siluete"].Points.AddXY(DateTime.Now.ToLongTimeString(), 0);

cron.Start();

Application.Idle += detecteaza_siluete;

}

//daca este selectat al cincilea tab – Detectie caractere

if (ctProcesareImagine.SelectedIndex == 4)

{

Application.Idle -= proceseaza_cadru;

Application.Idle -= detecteaza_fete;

Application.Idle -= detecteaza_similaritati;

Application.Idle -= proceseaza_cadru_detecteaza_similaritati;

Application.Idle -= detecteaza_siluete;

cron.Stop();

imagine_de_cautat = null;

//daca este selectat modul dinamic

if (ctDetectieCaractere.SelectedIndex == 0)

{

tbMesajDetectieCaractere.BackColor = Color.LightSalmon;

tbMesajDetectieCaractere.Text = "Se analizeaza fluxul video…";

Application.Idle += detecteaza_numere_inmatriculare;

cron.Start();

}

//daca este selectat modul static

if (ctDetectieCaractere.SelectedIndex == 1)

{

Application.Idle -= detecteaza_numere_inmatriculare;

cron.Stop();

tbMesajDetectieCaractere.BackColor = Color.LightSalmon;

tbMesajDetectieCaractere.Text = "Selectati imaginea sursa!";

}

}

}

}

}

Cap. 6. Bibliografie

Nicolae Cupcea, Costin Ștefănescu, Adrian Surpățeanu

Elemente de Electronică Analogică – Dispozitive electronice, Amplificatoare electronice, Amplificatoare operaționale, Editura AGIR București 2008, ISBN 978-973-720-229-1

Prof. Tudorache Tudor

Construirea unui robot

Massimo Banzi:

Getting Started with Arduino,Editura O’Reilly, ISBN 978-0-596-15551-3

Tom Igoe:

Making Things Talk – Practical Methods for Connecting Physical Objects

Editura O’Reilly, ISBN 978-0-596-51051-0

Massimo Banzi, David Cuartielles, Tom Igoe, Gianluca Martino, and David Mellis:

Arduino Microcontroller Processing for Everyone!, Editura Morgan & Claypool, ISBN 978-1-608-45438-9

XBe e®/XBe e -PRO® ZB RF Modules User’s Guide

Digi International Inc.

Andrew King:

A Survey of Methods for Face Detection

Ole Helvig Jensen:

Implementing the Viola-Jones Face Detection Algorithm

Herbert Bay, Andreas Ess, Tinne Tuytelaars, and Luc Van Gool:

Speeded-Up Robust Features (SURF)

Navneet Dalal and Bill Triggs:

Histograms of Oriented Gradients for Human Detection

S.Kranthi, K.Pranathi, A.Srisaila:

Automatic Number Plate Recognition

Tudoran Mihai

http://prezi.com/aaekbf3o1tbz/c/

Limbajul de programare C++

http://modularcircuits.tantosonline.com/blog/articles/old-h-bridge-secrets/

Principiu funcționare punte H

http://arduino.cc/en/Tutorial/HomePage

Sursă de informații oficială Arduino cu privire la funcționarea platformei + forum online

http://www.instructables.com/tag/type-id/category-technology/channel-arduino/

Proiecte de roboti cu diverse functionalitati

http://forum.sparkfun.com/

Forum online cu profil tehnic

http://wikipeda.org

Enciclopedie online

http://docs.opencv.org/

Sursă de informații oficială OpenCV / EmguCV

http://www.scritub.com/stiinta/informatica/Microcontrolerul-PICF44210218.php

Structura internă microcontroler

Construcția unui robot mobil cu kit Arduino

http://www.math.uaic.ro/~mapetrii/fisiere/POO/Curs7.pdf

Introducere in Microsoft Visual Studio

Cap. 7. Anexe

7.1 Cod sursă program microcontroller – limbaj C

////////////////////////////////////////////////////////

//Application: Robot Explorer v2.0 uController Software

//Board: Arduino UNO R3

//Copyright Margescu Valentin Razvan

////////////////////////////////////////////////////////

#include <Servo.h>

//Variabile globale

//definire pini IO senzori ultrasonici

#define pingPin_sf 6

#define pingPin_df 9

#define pingPin_ss 10

#define pingPin_ds 11

//definire pini IO drivere motoare

#define motor_dr_pin 5

#define motor_st_pin 3

#define dir_dr_pin 4

#define dir_st_pin 2

//definire variabile distante senzori ultrasonici

long distanta_sf;

long distanta_df;

long distanta_ss;

long distanta_ds;

//definire variabile stari distante senzori ultrasonici

int sf_curent=0;

int sf_anterior=0;

int df_curent=0;

int df_anterior=0;

int ss_curent=0;

int ss_anterior=0;

int ds_curent=0;

int ds_anterior=0;

//cronometru

unsigned long timp_curent;

unsigned long timp_anterior;

//variabile servomotoare

Servo servo_vert;

Servo servo_oriz;

int pos_vert=90;

int pos_oriz=90;

//alte variabile interne

int x,viteza,factor;

//bucra setare (ruleaza o singura data la pornirea sistemului)

void setup()

{

//atasare numar pini servomotoare

servo_vert.attach(12);

servo_oriz.attach(13);

//definire pini directie motoare ca pini de iesire (comanda)

pinMode(dir_dr_pin, OUTPUT);

pinMode(dir_st_pin, OUTPUT);

initial();

//stabilire viteza initiala

viteza=50;

//initializare timp curent

timp_curent=0;

//pornire interfata seriala la 115200 baud

Serial.begin(115200);

}

//bucla repetativa (ruleaza la infinit cat timp sistemul este pornit)

void loop()

{

//pornire cronometru

timp_curent=millis();

//o data la 500 milisecunde

if(timp_curent-timp_anterior>500)

{

//citeste distantele de la senzori

distanta_sf=citeste_distanta_sf();

distanta_df=citeste_distanta_df();

distanta_ss=citeste_distanta_ss();

distanta_ds=citeste_distanta_ds();

timp_anterior=timp_curent;

if(distanta_sf<=60)

{

if(distanta_sf<=40)

{

if(distanta_sf<=20)

{

sf_curent=1;

}

else

{

sf_curent=2;

}

}

else

{

sf_curent=3;

}

}

else

{

sf_curent=0;

}

if(sf_curent!=sf_anterior)

{

switch(sf_curent)

{

case 3:

{

Serial.println("SF:3");

delay(10);

sf_anterior=sf_curent;

break;

}

case 2:

{

Serial.println("SF:2");

delay(10);

sf_anterior=sf_curent;

break;

}

case 1:

{

Serial.println("SF:1");

delay(10);

sf_anterior=sf_curent;

break;

}

case 0:

{

Serial.println("SF:0");

delay(10);

sf_anterior=sf_curent;

break;

}

default:

{

Serial.println("SF:0");

delay(10);

sf_anterior=sf_curent;

}

}

}

//prelucrare date senzor dreapta fata

if(distanta_df<=60)

{

if(distanta_df<=40)

{

if(distanta_df<=20)

{

df_curent=1;

}

else

{

df_curent=2;

}

}

else

{

df_curent=3;

}

}

else

{

df_curent=0;

}

if(df_curent!=df_anterior)

{

switch(df_curent)

{

case 3:

{

Serial.println("DF:3");

delay(10);

df_anterior=df_curent;

break;

}

case 2:

{

Serial.println("DF:2");

delay(10);

df_anterior=df_curent;

break;

}

case 1:

{

Serial.println("DF:1");

delay(10);

df_anterior=df_curent;

break;

}

case 0:

{

Serial.println("DF:0");

delay(10);

df_anterior=df_curent;

break;

}

default:

{

Serial.println("DF:0");

delay(10);

df_anterior=df_curent;

}

}

}

//prelucrare date senzor stanga spate

if(distanta_ss<=60)

{

if(distanta_ss<=40)

{

if(distanta_ss<=20)

{

ss_curent=1;

}

else

{

ss_curent=2;

}

}

else

{

ss_curent=3;

}

}

else

{

ss_curent=0;

}

if(ss_curent!=ss_anterior)

{

switch(ss_curent)

{

case 3:

{

Serial.println("SS:3");

delay(10);

ss_anterior=ss_curent;

break;

}

case 2:

{

Serial.println("SS:2");

delay(10);

ss_anterior=ss_curent;

break;

}

case 1:

{

Serial.println("SS:1");

delay(10);

ss_anterior=ss_curent;

break;

}

case 0:

{

Serial.println("SS:0");

delay(10);

ss_anterior=ss_curent;

break;

}

default:

{

Serial.println("SS:0");

delay(10);

ss_anterior=ss_curent;

}

}

}

//prelucrare date senzor dreapta spate

if(distanta_ds<=60)

{

if(distanta_ds<=40)

{

if(distanta_ds<=20)

{

ds_curent=1;

}

else

{

ds_curent=2;

}

}

else

{

ds_curent=3;

}

}

else

{

ds_curent=0;

}

if(ds_curent!=ds_anterior)

{

switch(ds_curent)

{

case 3:

{

Serial.println("DS:3");

delay(10);

ds_anterior=ds_curent;

break;

}

case 2:

{

Serial.println("DS:2");

delay(10);

ds_anterior=ds_curent;

break;

}

case 1:

{

Serial.println("DS:1");

delay(10);

ds_anterior=ds_curent;

break;

}

case 0:

{

Serial.println("DS:0");

delay(10);

ds_anterior=ds_curent;

break;

}

default:

{

Serial.println("DS:0");

delay(10);

ds_anterior=ds_curent;

}

}

}

}

//citire comenzi pe interfata seriala

if(Serial.available())

{

x=Serial.read();

}

switch(x)

{

case 119:

{

inainte(viteza);

break;

}

case 115:

{

inapoi(viteza);

break;

}

case 97:

{

intoarcere_st(viteza);

break;

}

case 100:

{

intoarcere_dr(viteza);

break;

}

case 46:

{

viteza=viteza+20;

x=0;

break;

}

case 44:

{

viteza=viteza-20;

x=0;

break;

}

case 114:

{

servo_vert.write(90);

servo_oriz.write(90);

delay(15);

pos_vert=90;

pos_oriz=90;

break;

}

case 105:

{

if(pos_vert>50)

{

pos_vert=pos_vert-10;

servo_vert.write(pos_vert);

delay(15);

x=0;

}

else

{

x=0;

}

break;

}

case 107:

{

if(pos_vert<130)

{

pos_vert=pos_vert+10;

servo_vert.write(pos_vert);

delay(15);

x=0;

}

else

{

x=0;

}

break;

}

case 108:

{

if(pos_oriz>50)

{

pos_oriz=pos_oriz-10;

servo_oriz.write(pos_oriz);

delay(15);

x=0;

}

else

{

x=0;

}

break;

}

case 106:

{

if(pos_oriz<130)

{

pos_oriz=pos_oriz+10;

servo_oriz.write(pos_oriz);

delay(15);

x=0;

}

else

{

x=0;

}

break;

}

case 103:

{

if((distanta_sf<=40)||(distanta_df<=40))

{

if((distanta_sf<=20)||(distanta_df<=20))

{

if(distanta_sf<distanta_df)

{

factor=distanta_df-distanta_sf;

inapoi(viteza);

delay(1000);

intoarcere_dr(viteza);

delay(1000/factor);

}

if(distanta_sf>distanta_df)

{

factor=distanta_sf-distanta_df;

inapoi(viteza);

delay(1000);

intoarcere_st(viteza);

delay(1000/factor);

}

}

else

{

if(distanta_sf<distanta_df)

{

factor=distanta_df-distanta_sf;

intoarcere_dr(viteza);

delay(1000/factor);

}

if(distanta_sf>distanta_df)

{

factor=distanta_sf-distanta_df;

intoarcere_st(viteza);

delay(1000/factor);

}

}

}

else

{

inainte(viteza);

}

break;

}

case 116:

{

servo_vert.write(180);

servo_oriz.write(170);

delay(15);

pos_vert=180;

pos_oriz=170;

break;

}

default:

{

oprire();

x=0;

}

}

viteza=constrain(viteza, 0, 200);

}

//sectiune functii

//functie rulara la pornirea robotului pentru setarea pozitiei initiale a camerei

void initial()

{

servo_vert.write(90);

servo_oriz.write(90);

delay(15);

}

//functie deplasare inainte

void inainte(int viteza)

{

digitalWrite(dir_dr_pin,HIGH);

digitalWrite(dir_st_pin,LOW);

analogWrite(motor_dr_pin, viteza);

analogWrite(motor_st_pin, viteza);

}

//functie deplasare inapoi

void inapoi(int viteza)

{

digitalWrite(dir_dr_pin,LOW);

digitalWrite(dir_st_pin,HIGH);

analogWrite(motor_dr_pin, viteza);

analogWrite(motor_st_pin, viteza);

}

//functie intoarcere la stanga

void intoarcere_st(int viteza)

{

int viteza_viraj;

if(viteza>70)

{

viteza_viraj=70;

}

else

{

viteza_viraj=viteza;

}

digitalWrite(dir_dr_pin,HIGH);

digitalWrite(dir_st_pin,HIGH);

analogWrite(motor_dr_pin, viteza_viraj);

analogWrite(motor_st_pin, viteza_viraj);

}

//functie intoarcere la dreapta

void intoarcere_dr(int viteza)

{

int viteza_viraj;

if(viteza>70)

{

viteza_viraj=70;

}

else

{

viteza_viraj=viteza;

}

digitalWrite(dir_dr_pin,LOW);

digitalWrite(dir_st_pin,LOW);

analogWrite(motor_dr_pin, viteza_viraj);

analogWrite(motor_st_pin, viteza_viraj);

}

//functie oprire

void oprire()

{

analogWrite(motor_dr_pin, 0);

analogWrite(motor_st_pin, 0);

}

//functie citire senzor ultrasonic stanga fata

long citeste_distanta_sf()

{

//calibrare

pinMode(pingPin_sf, OUTPUT);

digitalWrite(pingPin_sf, LOW);

delayMicroseconds(2);

digitalWrite(pingPin_sf, HIGH);

delayMicroseconds(2);

digitalWrite(pingPin_sf, LOW);

//citire

pinMode(pingPin_sf, INPUT);

long puls = pulseIn(pingPin_sf, HIGH);

long inchi = puls/147;

long cm = inchi * 2.54;

return(cm);

}

//functie citire senzor ultrasonic dreapta fata

long citeste_distanta_df()

{

//calibrare

pinMode(pingPin_df, OUTPUT);

digitalWrite(pingPin_df, LOW);

delayMicroseconds(2);

digitalWrite(pingPin_df, HIGH);

delayMicroseconds(2);

digitalWrite(pingPin_df, LOW);

//citire

pinMode(pingPin_df, INPUT);

long puls = pulseIn(pingPin_df, HIGH);

delay(10);

long inchi = puls/147;

long cm = inchi * 2.54;

return(cm);

}

//functie citire senzor ultrasonic stanga spate

long citeste_distanta_ss()

{

//calibrare

pinMode(pingPin_ss, OUTPUT);

digitalWrite(pingPin_ss, LOW);

delayMicroseconds(2);

digitalWrite(pingPin_ss, HIGH);

delayMicroseconds(2);

digitalWrite(pingPin_ss, LOW);

//citire

pinMode(pingPin_ss, INPUT);

long puls = pulseIn(pingPin_ss, HIGH);

delay(10);

long inchi = puls/147;

long cm = inchi * 2.54;

return(cm);

}

//functie citire senzor ultrasonic dreapta spate

long citeste_distanta_ds()

{

//calibrare

pinMode(pingPin_ds, OUTPUT);

digitalWrite(pingPin_ds, LOW);

delayMicroseconds(2);

digitalWrite(pingPin_ds, HIGH);

delayMicroseconds(2);

digitalWrite(pingPin_sf, LOW);

//citire

pinMode(pingPin_ds, INPUT);

long puls = pulseIn(pingPin_ds, HIGH);

delay(10);

long inchi = puls/147;

long cm = inchi * 2.54;

return(cm);

}

7.2 Cod sursă program aplicație PC (Windows) – limbaj C#

7.2.1 Cod sursă form configurare conexiune serială

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Linq;

using System.Text;

using System.Windows.Forms;

using System.IO.Ports;

namespace Rbtz_App

{

public partial class Setari : Form

{

public string[] ports = SerialPort.GetPortNames();

public SerialPort sp;

public Setari()

{

InitializeComponent();

populare_cb_port();

populare_cb_baud();

populare_cb_nrBiti();

}

private void populare_cb_port()

{

foreach (string port in ports)

{

cbPort.Items.Add(port);

}

}

private void populare_cb_baud()

{

cbBaud.Items.Add(4800);

cbBaud.Items.Add(7200);

cbBaud.Items.Add(9600);

cbBaud.Items.Add(14400);

cbBaud.Items.Add(19200);

cbBaud.Items.Add(38400);

cbBaud.Items.Add(57600);

cbBaud.Items.Add(115200);

cbBaud.Items.Add(128000);

}

private void populare_cb_nrBiti()

{

cbNrBiti.Items.Add(8);

cbNrBiti.Items.Add(16);

cbNrBiti.Items.Add(32);

cbNrBiti.Items.Add(64);

cbNrBiti.Items.Add(128);

}

private void lInitializareConexiune_Click(object sender, EventArgs e)

{

bool ok=false;

try

{

sp = new SerialPort(cbPort.Text, Convert.ToInt32(cbBaud.Text), Parity.None, Convert.ToInt32(cbNrBiti.Text));

ok = true;

}

catch (Exception)

{

MessageBox.Show("Selectati toti parametrii conexiunii din box-ul corespunzator!");

}

if (ok == true)

{

try

{

sp.Open();

if (sp.IsOpen)

{

MessageBox.Show("Conexiune stabilita cu succes!");

sp.Close();

Main a = new Main(cbPort.Text, Convert.ToInt32(cbBaud.Text), Convert.ToInt32(cbNrBiti.Text));

a.Show();

}

}

catch (Exception)

{

MessageBox.Show("Conexiune esuata! Verificati daca robotul este pornit!");

}

//this.Close();

}

}

}

}

7.2.2 Cod sursă form “Main”

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Linq;

using System.Text;

using System.Windows.Forms;

using System.IO.Ports;

using System.Threading;

using System.Threading.Tasks;

using Emgu.CV;

using Emgu.CV.CvEnum;

using Emgu.CV.Features2D;

using Emgu.CV.Structure;

using Emgu.CV.Util;

using Emgu.CV.GPU;

using Emgu.CV.OCR;

using DirectShowLib;

namespace Rbtz_App

{

public partial class Main : Form

{

public SerialPort sp;

public String Port;

public Int32 Baud;

public Int32 NrBiti;

public String indata;

private delegate void set_delegat();

int viteza=3;

public int poz_anterioara_vert = 40;

public int poz_anterioara_oriz = 40;

public char[] buff = new char[1];

public bool esteFullScreen = false;

public int latime_gbVideo;

public int inaltime_gbVideo;

public Point locatie_gbVideo;

public double factor_scalare_fullscreen_gbVideo;

public int latime_gbControl;

public int inaltime_gbControl;

public Point locatie_gbControl;

public double factor_scalare_fullscreen_gbControl;

public int latime_gbSenzori;

public int inaltime_gbSenzori;

public Point locatie_gbSenzori;

public double factor_scalare_fullscreen_gbSenzori;

public int latime_ctProcesareImagine;

public int inaltime_ctProcesareImagine;

public Point locatie_ctProcesareImagine;

public double factor_scalare_fullscreen_ctProcesareImagine;

public int latime_pbRELogo;

public int inaltime_pbRELogo;

public Point locatie_pbRELogo;

public double factor_scalare_fullscreen_pbRELogo;

//variabile captura

public Capture captura; //preia cadre de la dispozitivul de captura

public bool captura_in_progres; //verifica daca are loc procesul de captura

//variabile scalare form

public int latime_curenta;

public int inaltime_curenta;

public int latime_noua;

public int inaltime_noua;

//variabile setari captura

public int luminozitate;

public int contrast;

public int claritate;

//variabile detectie faciala

private Emgu.CV.HaarCascade haar;

public double scala_df;

public int treshold_nr_minim_vecini_df;

public Emgu.CV.CvEnum.HAAR_DETECTION_TYPE tip_detectie_df;

public List<int> numar_fete_partial = new List<int>();

public List<bool> numar_similaritati_partial = new List<bool>();

public List<int> numar_siluete_partial = new List<int>();

//variabile detectie similaritati

private Image<Bgr, Byte> imagine_cadru = null;

private Image<Bgr, Byte> imagine_de_cautat = null;

private Image<Bgr, Byte> imagine_de_cautat_cu_contur = null;

private Image<Bgr, Byte> imagine_rezultat = null;

private Bgr culoare_puncte_interes = new Bgr(Color.Blue);

private Bgr culoare_linii_similaritate = new Bgr(Color.Green);

private Bgr culoare_chenar_imagine_gasita = new Bgr(Color.Red);

private int numar_vecini_ds;

private double threshold_unicitate_ds;

private double increment_scala_ds;

private int segmente_rotatie_ds;

//variabile detectie similaritati

private int nr_siluete_detectate;

//variabile detectie caractere

private Tesseract tess;

private Image<Bgr, Byte> imagine_OCR = null;

private DetectorNumereInmatriculare detector;

private List<Image<Gray, Byte>> imagini_numere_inmatriculare;

private List<Image<Gray, Byte>> imagini_numere_inmatriculare_filtrate;

private List<MCvBox2D> regiuni_numere_inmatriculare;

private List<string> cuvinte_numere_inmatriculare;

private List<Image<Gray, Byte>> imagini_numere_inmatriculare_partial;

private List<Image<Gray, Byte>> imagini_numere_inmatriculare_filtrate_partial;

private List<MCvBox2D> regiuni_numere_inmatriculare_partial;

private List<string> cuvinte_numere_inmatriculare_partial;

public Main(String port, Int32 baud, Int32 nrBiti)

{

Port = port;

Baud = baud;

NrBiti = nrBiti;

InitializeComponent();

sp = new SerialPort(port, baud, Parity.None, nrBiti, StopBits.One);

sp.Handshake = Handshake.XOnXOff;

sp.ReadTimeout = 500;

sp.WriteTimeout = 500;

tbViteza.Text = viteza.ToString();

sp.Open();

if (sp.IsOpen)

{

afiseaza_info_conexiune();

}

else

{

sp.Close();

}

sp.DataReceived += new SerialDataReceivedEventHandler(receptieDate);

//––––––––––––––––––––––––––

vSBcameraVert.Value = 40;

hSBcameraOriz.Value = 40;

poz_anterioara_vert = 40;

poz_anterioara_oriz = 40;

buff[0] = 'r';

sp.Write(buff, 0, 1);

//––––––––––––––––––––––––––

populare_surse_video();

//––––––––––––––––––––––––––

//setare latime si inaltime curenta

latime_curenta = 1440;

inaltime_curenta = 900;

latime_noua = 1440;

inaltime_noua = 900;

//––––––––––––––––––––––––––

//initializare variabile prelucrare video

cron.Interval = 2000;

scala_df = 1 + (Convert.ToDouble(tbScala.Value) / 10);

treshold_nr_minim_vecini_df = Convert.ToInt32(tbNrMinVecini.Value);

tip_detectie_df = Emgu.CV.CvEnum.HAAR_DETECTION_TYPE.DO_CANNY_PRUNING;

numar_vecini_ds = 2;

threshold_unicitate_ds = 0.5;

increment_scala_ds = 1.1;

segmente_rotatie_ds = 20;

nr_siluete_detectate = 0;

try

{

tess = new Tesseract("tessdata", "eng", Tesseract.OcrEngineMode.OEM_DEFAULT);

}

catch (Exception e)

{

MessageBox.Show("Nu a putut fi instantiata variabila 'tess' pentru detectie caractere!");

tpDetectieCaractere.Enabled = false;

}

detector = new DetectorNumereInmatriculare();

detector.threshold_binarizare = 100;

detector.threshold_contur = 150;

detector.threshold_unificare_contur = 200;

imagini_numere_inmatriculare_partial = new List<Image<Gray, byte>>();

imagini_numere_inmatriculare_filtrate_partial = new List<Image<Gray, byte>>();

regiuni_numere_inmatriculare_partial = new List<MCvBox2D>();

cuvinte_numere_inmatriculare_partial = new List<string>();

//––––––––––––––––––––––––––

//setare elemente grafice prelucrare video

tbValoareLuminozitate.Text = tbLuminozitate.Value.ToString();

tbValoareContrast.Text = tbContrast.Value.ToString();

tbValoareClaritate.Text = tbClaritate.Value.ToString();

tbValoareScala.Text = tbScala.Value.ToString();

tbValoareNrMinVecini.Text = tbNrMinVecini.Value.ToString();

cbDetectieSimilaritati.Items.Add("Numar vecini");

cbDetectieSimilaritati.Items.Add("Threshold unicitate");

cbDetectieSimilaritati.Items.Add("Increment scala");

cbDetectieSimilaritati.Items.Add("Segmente rotatie");

cbDetectieSimilaritati.SelectedIndex = cbDetectieSimilaritati.Items.IndexOf("Numar vecini");

tbDetectieSimilaritati.Minimum = 2;

tbDetectieSimilaritati.Maximum = 10;

tbDetectieSimilaritati.Value = numar_vecini_ds;

tbValoareDetectieSimilaritati.Text = tbDetectieSimilaritati.Value.ToString();

cbDetectieCaractere.Items.Add("Threshold binarizare");

cbDetectieCaractere.Items.Add("Threshold contur");

cbDetectieCaractere.Items.Add("Threshold unificare contur");

cbDetectieCaractere.SelectedIndex = cbDetectieCaractere.Items.IndexOf("Threshold binarizare");

tbDetectieCaractere.Minimum = 70;

tbDetectieCaractere.Maximum = 130;

tbDetectieCaractere.Value = detector.threshold_binarizare;

tbValoareDetectieCaractere.Text = tbDetectieCaractere.Value.ToString();

}

public void receptieDate(object sender, SerialDataReceivedEventArgs e)

{

sp = (SerialPort)sender;

try

{

indata = sp.ReadLine();

}

catch (Exception)

{

}

try

{

if (indata == "SF:1" + indata[4])

{

this.BeginInvoke(new set_delegat(SF1), new object[] { });

}

if (indata == "SF:2" + indata[4])

{

this.BeginInvoke(new set_delegat(SF2), new object[] { });

}

if (indata == "SF:3" + indata[4])

{

this.BeginInvoke(new set_delegat(SF3), new object[] { });

}

if (indata == "SF:0" + indata[4])

{

this.BeginInvoke(new set_delegat(SF0), new object[] { });

}

if (indata == "DF:1" + indata[4])

{

this.BeginInvoke(new set_delegat(DF1), new object[] { });

}

if (indata == "DF:2" + indata[4])

{

this.BeginInvoke(new set_delegat(DF2), new object[] { });

}

if (indata == "DF:3" + indata[4])

{

this.BeginInvoke(new set_delegat(DF3), new object[] { });

}

if (indata == "DF:0" + indata[4])

{

this.BeginInvoke(new set_delegat(DF0), new object[] { });

}

if (indata == "SS:1" + indata[4])

{

this.BeginInvoke(new set_delegat(SS1), new object[] { });

}

if (indata == "SS:2" + indata[4])

{

this.BeginInvoke(new set_delegat(SS2), new object[] { });

}

if (indata == "SS:3" + indata[4])

{

this.BeginInvoke(new set_delegat(SS3), new object[] { });

}

if (indata == "SS:0" + indata[4])

{

this.BeginInvoke(new set_delegat(SS0), new object[] { });

}

if (indata == "DS:1" + indata[4])

{

this.BeginInvoke(new set_delegat(DS1), new object[] { });

}

if (indata == "DS:2" + indata[4])

{

this.BeginInvoke(new set_delegat(DS2), new object[] { });

}

if (indata == "DS:3" + indata[4])

{

this.BeginInvoke(new set_delegat(DS3), new object[] { });

}

if (indata == "DS:0" + indata[4])

{

this.BeginInvoke(new set_delegat(DS0), new object[] { });

}

}

catch (Exception)

{

//nu se intampla nimic

}

}

public void SF1()

{

pStangaF1.Visible = true;

pStangaF2.Visible = false;

pStangaF3.Visible = false;

pbSemafor.BackgroundImage = global::Rbtz_App.Properties.Resources.semafor_rosu;

}

public void SF2()

{

pStangaF1.Visible = false;

pStangaF2.Visible = true;

pStangaF3.Visible = false;

pbSemafor.BackgroundImage = global::Rbtz_App.Properties.Resources.semafor_verde;

}

public void SF3()

{

pStangaF1.Visible = false;

pStangaF2.Visible = false;

pStangaF3.Visible = true;

pbSemafor.BackgroundImage = global::Rbtz_App.Properties.Resources.semafor_verde;

}

public void SF0()

{

pStangaF1.Visible = false;

pStangaF2.Visible = false;

pStangaF3.Visible = false;

pbSemafor.BackgroundImage = global::Rbtz_App.Properties.Resources.semafor_verde;

}

public void DF1()

{

pDreaptaF1.Visible = true;

pDreaptaF2.Visible = false;

pDreaptaF3.Visible = false;

pbSemafor.BackgroundImage = global::Rbtz_App.Properties.Resources.semafor_rosu;

}

public void DF2()

{

pDreaptaF1.Visible = false;

pDreaptaF2.Visible = true;

pDreaptaF3.Visible = false;

pbSemafor.BackgroundImage = global::Rbtz_App.Properties.Resources.semafor_verde;

}

public void DF3()

{

pDreaptaF1.Visible = false;

pDreaptaF2.Visible = false;

pDreaptaF3.Visible = true;

pbSemafor.BackgroundImage = global::Rbtz_App.Properties.Resources.semafor_verde;

}

public void DF0()

{

pDreaptaF1.Visible = false;

pDreaptaF2.Visible = false;

pDreaptaF3.Visible = false;

pbSemafor.BackgroundImage = global::Rbtz_App.Properties.Resources.semafor_verde;

}

public void SS1()

{

pStangaS1.Visible = true;

pStangaS2.Visible = false;

pStangaS3.Visible = false;

}

public void SS2()

{

pStangaS1.Visible = false;

pStangaS2.Visible = true;

pStangaS3.Visible = false;

}

public void SS3()

{

pStangaS1.Visible = false;

pStangaS2.Visible = false;

pStangaS3.Visible = true;

}

public void SS0()

{

pStangaS1.Visible = false;

pStangaS2.Visible = false;

pStangaS3.Visible = false;

}

public void DS1()

{

pDreaptaS1.Visible = true;

pDreaptaS2.Visible = false;

pDreaptaS3.Visible = false;

}

public void DS2()

{

pDreaptaS1.Visible = false;

pDreaptaS2.Visible = true;

pDreaptaS3.Visible = false;

}

public void DS3()

{

pDreaptaS1.Visible = false;

pDreaptaS2.Visible = false;

pDreaptaS3.Visible = true;

}

public void DS0()

{

pDreaptaS1.Visible = false;

pDreaptaS2.Visible = false;

pDreaptaS3.Visible = false;

}

//––––––––––––––––––––––––––

public void afiseaza_info_conexiune()

{

cbPort.Text = Port;

cbBaud.Text = Baud.ToString();

cbNrBiti.Text = NrBiti.ToString();

}

private void btn_inainte_Click(object sender, EventArgs e)

{

try

{

buff[0] = 'w';

sp.Write(buff, 0, 1);

btn_inainte.BackColor = Color.Gray;

btn_inapoi.BackColor = Color.Transparent;

btn_stanga.BackColor = Color.Transparent;

btn_dreapta.BackColor = Color.Transparent;

btn_stop.BackColor = Color.Transparent;

bAuto.BackColor = Color.Transparent;

}

catch (Exception ex)

{

MessageBox.Show(ex.ToString());

}

}

private void btn_inapoi_Click(object sender, EventArgs e)

{

try

{

buff[0] = 's';

sp.Write(buff, 0, 1);

btn_inainte.BackColor = Color.Transparent;

btn_inapoi.BackColor = Color.Gray;

btn_stanga.BackColor = Color.Transparent;

btn_dreapta.BackColor = Color.Transparent;

btn_stop.BackColor = Color.Transparent;

bAuto.BackColor = Color.Transparent;

}

catch (Exception ex)

{

MessageBox.Show(ex.ToString());

}

}

private void btn_stanga_Click(object sender, EventArgs e)

{

try

{

buff[0] = 'a';

sp.Write(buff, 0, 1);

btn_inainte.BackColor = Color.Transparent;

btn_inapoi.BackColor = Color.Transparent;

btn_stanga.BackColor = Color.Gray;

btn_dreapta.BackColor = Color.Transparent;

btn_stop.BackColor = Color.Transparent;

bAuto.BackColor = Color.Transparent;

}

catch (Exception ex)

{

MessageBox.Show(ex.ToString());

}

}

private void btn_dreapta_Click(object sender, EventArgs e)

{

try

{

buff[0] = 'd';

sp.Write(buff, 0, 1);

btn_inainte.BackColor = Color.Transparent;

btn_inapoi.BackColor = Color.Transparent;

btn_stanga.BackColor = Color.Transparent;

btn_dreapta.BackColor = Color.Gray;

btn_stop.BackColor = Color.Transparent;

bAuto.BackColor = Color.Transparent;

}

catch (Exception ex)

{

MessageBox.Show(ex.ToString());

}

}

private void btn_stop_Click(object sender, EventArgs e)

{

try

{

buff[0] = 'z';

sp.Write(buff, 0, 1);

btn_inainte.BackColor = Color.Transparent;

btn_inapoi.BackColor = Color.Transparent;

btn_stanga.BackColor = Color.Transparent;

btn_dreapta.BackColor = Color.Transparent;

btn_stop.BackColor = Color.Gray;

bAuto.BackColor = Color.Transparent;

}

catch (Exception ex)

{

MessageBox.Show(ex.ToString());

}

}

private void Main_FormClosing(object sender, FormClosingEventArgs e)

{

if (sp.IsOpen)

{

sp.Close();

}

}

private void vSBcameraVert_ValueChanged(object sender, EventArgs e)

{

int poz_curenta=vSBcameraVert.Value;

if (poz_curenta > poz_anterioara_vert)

{

buff[0] = 'k';

sp.Write(buff, 0, 1);

poz_anterioara_vert = poz_curenta;

}

else

{

buff[0] = 'i';

sp.Write(buff, 0, 1);

poz_anterioara_vert = poz_curenta;

}

}

private void hSBcameraOriz_ValueChanged(object sender, EventArgs e)

{

int poz_curenta = hSBcameraOriz.Value;

if (poz_curenta > poz_anterioara_oriz)

{

buff[0] = 'l';

sp.Write(buff, 0, 1);

poz_anterioara_oriz = poz_curenta;

}

else

{

buff[0] = 'j';

sp.Write(buff, 0, 1);

poz_anterioara_oriz = poz_curenta;

}

}

private void bReset_Click(object sender, EventArgs e)

{

vSBcameraVert.Value = 40;

hSBcameraOriz.Value = 40;

poz_anterioara_vert = 40;

poz_anterioara_oriz = 40;

buff[0] = 'r';

sp.Write(buff, 0, 1);

}

private void bVitUp_Click(object sender, EventArgs e)

{

buff[0] = '.';

sp.Write(buff, 0, 1);

if (viteza < 10)

{

viteza = viteza + 1;

tbViteza.Text = viteza.ToString();

}

}

private void bVitDown_Click(object sender, EventArgs e)

{

buff[0] = ',';

sp.Write(buff, 0, 1);

if (viteza > 0)

{

viteza = viteza – 1;

tbViteza.Text = viteza.ToString();

}

}

private void Main_KeyPress(object sender, KeyPressEventArgs e)

{

switch (e.KeyChar)

{

case 'w':

btn_inainte_Click(sender, e);

break;

case 'd':

btn_dreapta_Click(sender, e);

break;

case 's':

btn_inapoi_Click(sender, e);

break;

case 'a':

btn_stanga_Click(sender, e);

break;

case 'g':

bAuto_Click(sender, e);

break;

case 'k':

if (vSBcameraVert.Value <= 80)

{

vSBcameraVert.Value = vSBcameraVert.Value + 10;

}

break;

case 'i':

if (vSBcameraVert.Value >= 10)

{

vSBcameraVert.Value = vSBcameraVert.Value – 10;

}

break;

case 'l':

if (hSBcameraOriz.Value <= 80)

{

hSBcameraOriz.Value = hSBcameraOriz.Value + 10;

}

break;

case 'j':

if (hSBcameraOriz.Value >= 10)

{

hSBcameraOriz.Value = hSBcameraOriz.Value – 10;

}

break;

case ',':

bVitDown_Click(sender, e);

break;

case '.':

bVitUp_Click(sender, e);

break;

case 'r':

bReset_Click(sender, e);

break;

default:

btn_stop_Click(sender, e);

break;

}

}

private void bAuto_Click(object sender, EventArgs e)

{

try

{

buff[0] = 'g';

sp.Write(buff, 0, 1);

btn_inainte.BackColor = Color.Transparent;

btn_inapoi.BackColor = Color.Transparent;

btn_stanga.BackColor = Color.Transparent;

btn_dreapta.BackColor = Color.Transparent;

btn_stop.BackColor = Color.Transparent;

bAuto.BackColor = Color.Gray;

}

catch (Exception ex)

{

MessageBox.Show(ex.ToString());

}

}

private void pbOff_Click(object sender, EventArgs e)

{

try

{

buff[0] = 't';

sp.Write(buff, 0, 1);

}

catch (Exception ex)

{

MessageBox.Show(ex.ToString());

}

if (captura != null)

{

captura.Dispose();

}

sp.Close();

this.Close();

}

private void pbOff_MouseEnter(object sender, EventArgs e)

{

this.pbOff.BackgroundImage = global::Rbtz_App.Properties.Resources.PowerButton;

}

private void pbOff_MouseLeave(object sender, EventArgs e)

{

this.pbOff.BackgroundImage = global::Rbtz_App.Properties.Resources.PowerButton_Transparent1;

}

//funtie pentru popularea surselor video

public void populare_surse_video()

{

//populare combo box

DsDevice[] elemente_captura_disponibile = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);

for (int i = 0; i < elemente_captura_disponibile.Length; i++)

{

cbSursa_video.Items.Add(elemente_captura_disponibile[i].Name.ToString());

}

//daca exita surse video disponibile

if (cbSursa_video.Items.Count > 0)

{

cbSursa_video.Enabled = true;

cbSursa_video.SelectedIndex = 0;

bVideo.Enabled = true;

}

//daca nu exista surse video disponibile

else

{

cbSursa_video.Enabled = false;

bVideo.Enabled = false;

}

}

private void bRefresh_Click(object sender, EventArgs e)

{

populare_surse_video();

}

//eveniment declansat la apasarea butonului start

private void bVideo_Click(object sender, EventArgs e)

{

//daca nu a fost instantiata captura

if (captura == null)

{

try

{

captura = new Capture();

}

catch (NullReferenceException excpt)

{

MessageBox.Show(excpt.Message);

}

}

//daca a fost instantiata captura

if (captura != null)

{

//verificare daca procesul de captura are loc

if (captura_in_progres)

{

//daca procesul de captura are loc, procesul se va opri iar textul butonului va redeveni "Start"

bVideo.Text = "Start";

Application.Idle -= proceseaza_cadru;

Application.Idle -= detecteaza_fete;

Application.Idle -= detecteaza_similaritati;

Application.Idle -= proceseaza_cadru_detecteaza_similaritati;

Application.Idle -= detecteaza_siluete;

cron.Stop();

pbVideo.Image = null;

if (esteFullScreen == true)

{

pCopyright.Visible = false;

}

else

{

pCopyright.Visible = true;

}

lProcesareImagine.Visible = false;

ctProcesareImagine.Visible = false;

}

else

{

//daca procesul de captura nu are loc, se porneste procesul de captura iar textul butonului va deveni "Stop"

bVideo.Text = "Stop";

Application.Idle += proceseaza_cadru;

setari_initiale_captura();

pCopyright.Visible = false;

ctProcesareImagine.Visible = true;

if (esteFullScreen == true)

{

lProcesareImagine.Visible = false;

}

else

{

lProcesareImagine.Visible = true;

}

ctProcesareImagine.SelectedTab = ctProcesareImagine.TabPages[0];

}

captura_in_progres = !captura_in_progres;

}

}

//functie pentru obtinerea setarilor initiale ale capturii

public void setari_initiale_captura()

{

luminozitate = (int)captura.GetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_BRIGHTNESS);

contrast = (int)captura.GetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_CONTRAST);

claritate = (int)captura.GetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_SHARPNESS);

}

//eveniment declansat la apasarea butonului de captura frame

private void pbPhoto_Click(object sender, EventArgs e)

{

System.Media.SoundPlayer myPlayer = new System.Media.SoundPlayer(Properties.Resources.camera1);

myPlayer.Play();

try

{

Image<Bgr, Byte> cadru_image_box = captura.QueryFrame();

cadru_image_box.Save(@"Captura " + DateTime.Now.ToString());

}

catch (Exception)

{

MessageBox.Show("Lansati procesul de redare mai intai!");

}

}

private void pbPhoto_MouseEnter(object sender, EventArgs e)

{

this.pbPhoto.BackgroundImage = global::Rbtz_App.Properties.Resources.camera_on;

}

private void pbPhoto_MouseLeave(object sender, EventArgs e)

{

this.pbPhoto.BackgroundImage = global::Rbtz_App.Properties.Resources.camera_off;

}

private void pbPhoto_Mare_Click(object sender, EventArgs e)

{

System.Media.SoundPlayer myPlayer = new System.Media.SoundPlayer(Properties.Resources.camera1);

myPlayer.Play();

}

//functie pentru preluarea unui cadru de la elementul de captura si transpunerea lui in ImageBox

private void proceseaza_cadru(object sender, EventArgs arg)

{

Image<Bgr, Byte> cadru_image_box_primar = captura.QueryFrame();

if (cadru_image_box_primar != null)

{

Image<Bgr, Byte> cadru_image_box = cadru_image_box_primar.Resize(pbVideo.Width, pbVideo.Height, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR);

pbVideo.Image = cadru_image_box.ToBitmap();

}

}

//functie pentru detectie faciala

private void detecteaza_fete(object sender, EventArgs arg)

{

//procesul de detectie faciala

Image<Bgr, Byte> cadru_image_box_primar = captura.QueryFrame();

if (cadru_image_box_primar != null)

{

Image<Bgr, Byte> cadru_image_box = cadru_image_box_primar.Resize(pbVideo.Width, pbVideo.Height, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR);

//se converteste imaginea in grayscale

Image<Gray, byte> cadru_sursa_grayscale = cadru_image_box.Convert<Gray, byte>();

//se detecteaza fete si stocheaza intr-un vector var

var fete = cadru_sursa_grayscale.DetectHaarCascade(haar, scala_df, treshold_nr_minim_vecini_df, tip_detectie_df, new Size(25, 25))[0];

//stocheaza numarul de fete pentru analiza

numar_fete_partial.Add(fete.Length);

//se deseneaza un contur verde care incadreaza fiecare fata

foreach (var fata in fete)

{

cadru_image_box.Draw(fata.rect, new Bgr(Color.Green), 2);

}

pbVideo.Image = cadru_image_box.ToBitmap();

}

}

//functie pentru detectie similaritati

private void detecteaza_similaritati(object sender, EventArgs arg)

{

//procesul de detectie similaritati

Image<Bgr, Byte> imagine_cadru_primar = captura.QueryFrame();

if (imagine_cadru_primar != null && imagine_de_cautat != null)

{

imagine_cadru = imagine_cadru_primar.Resize(pbVideo.Width, pbVideo.Height, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR);

SURFDetector surf_detector = new SURFDetector(500, false); //instantiere surf detector cu specificarea thresholdului

Image<Gray, Byte> imagine_cadru_gri = null; //imagine cadru in tonuri de gri

Image<Gray, Byte> imagine_de_cautat_gri = null; //imagine de cautat in tonuri de gri

VectorOfKeyPoint vpc_imagine_cadru; //vector de puncte cheie in imaginea cadru

VectorOfKeyPoint vpc_imagine_de_cautat; //vector de puncte cheie in imaginea de cautat

Matrix<Single> md_imagine_cadru; //matricea de descriptori in imaginea cadru

Matrix<Single> md_imagine_de_cautat; //matricea de descriptori in imaginea de cautat

Matrix<int> m_indicii; //matricea de indicii a descriptorilor (rezultata din descriptorii invatati)

Matrix<Single> m_distante; //matricea de valori ale distantelor (rezultata din descriptorii invatati)

Matrix<Byte> m_masca; //indica ce rand este valid pentru match

BruteForceMatcher<Single> brute_force_matcher; //pentru fiecare desciptor dintr-un anumit set, acest matcher identifica cel mai apropiat descriptor dintr-un alt set prin comparatie cu fiecare

HomographyMatrix matrice_homografie = null; //utilizata pentru functia de localizare a imaginii de cautat in imaginea cadru

int nr_elemente_nenule; //contor elemente nenule in m_masca

double threshold_reproiectare = 2.0;

Rectangle dreptunghi_imagine_de_cautat; //dreptunghiul care contureaza imaginea de cautat

PointF[] puncte_float; //cele 4 puncte care determina conturul imaginii de cautat in imaginea cadru (float)

Point[] puncte_int; //cele 4 puncte care determina conturul imaginii de cautat in imaginea cadru (int)

imagine_cadru_gri = imagine_cadru.Convert<Gray, Byte>(); //conversie imagine cadru in grayscale

imagine_de_cautat_gri = imagine_de_cautat.Convert<Gray, Byte>(); //conversie imagine de cautat in grayscale

vpc_imagine_cadru = surf_detector.DetectKeyPointsRaw(imagine_cadru_gri, null); //detecteaza punctele cheie in imaginea cadru, parametrul secund este masca

md_imagine_cadru = surf_detector.ComputeDescriptorsRaw(imagine_cadru_gri, null, vpc_imagine_cadru); //calculeaza descriptorul imaginii cadru

vpc_imagine_de_cautat = surf_detector.DetectKeyPointsRaw(imagine_de_cautat_gri, null); //detecteaza punctele cheie in imaginea de cautat, parametrul secund este masca

md_imagine_de_cautat = surf_detector.ComputeDescriptorsRaw(imagine_de_cautat_gri, null, vpc_imagine_de_cautat); //calculeaza descriptorul imaginea de cautat

brute_force_matcher = new BruteForceMatcher<Single>(DistanceType.L2); //instantierea obiectului bfm cu param: distanta patratica euclidiana

brute_force_matcher.Add(md_imagine_de_cautat); //adaugare matrice descriptori imagine de cautat

m_indicii = new Matrix<int>(md_imagine_cadru.Rows, numar_vecini_ds); //instantiere matrice indicii

m_distante = new Matrix<Single>(md_imagine_cadru.Rows, numar_vecini_ds); //instantiere matrice distante

brute_force_matcher.KnnMatch(md_imagine_cadru, m_indicii, m_distante, numar_vecini_ds, null); //detecteaza a k-a cea mai apropiata similaritate (match), unde k este dat de numar_vecini

m_masca = new Matrix<byte>(m_distante.Rows, 1); //instantiaza matricea masca

m_masca.SetValue(255); //setare toate valorile la 255

Features2DToolbox.VoteForUniqueness(m_distante, threshold_unicitate_ds, m_masca); //filtreaza similaritatile dupa unicitate: daca o similaritete nu este unica este rejectata

nr_elemente_nenule = CvInvoke.cvCountNonZero(m_masca); //contorizare nr. elemente nenule din matricea masca

if (nr_elemente_nenule >= 4) //daca sunt minim 4 elemente nenule

{

nr_elemente_nenule = Features2DToolbox.VoteForSizeAndOrientation(vpc_imagine_de_cautat, vpc_imagine_cadru, m_indicii, m_masca, increment_scala_ds, segmente_rotatie_ds); //eliminare similaritati care nu corespund ca scala si ca rotatie cu tendinta majora de scala si rotatie

if (nr_elemente_nenule >= 4) //daca inca sunt 4 elemente nenule

{

matrice_homografie = Features2DToolbox.GetHomographyMatrixFromMatchedFeatures(vpc_imagine_de_cautat, vpc_imagine_cadru, m_indicii, m_masca, threshold_reproiectare);

}

}

imagine_de_cautat_cu_contur = imagine_de_cautat.Copy(); //generare copie a imaginii de cautat pentru prelucrari ulterioare

imagine_de_cautat_cu_contur.Draw(new Rectangle(1, 1, imagine_de_cautat_cu_contur.Width – 3, imagine_de_cautat_cu_contur.Height – 3), culoare_chenar_imagine_gasita, 2);

if (cbPuncteInteres.Checked == true && cbLiniiSimilaritate.Checked == true)

{

imagine_rezultat = Features2DToolbox.DrawMatches(imagine_de_cautat_cu_contur, vpc_imagine_de_cautat, imagine_cadru, vpc_imagine_cadru, m_indicii, culoare_linii_similaritate, culoare_puncte_interes, m_masca, Features2DToolbox.KeypointDrawType.DEFAULT);

}

if (cbPuncteInteres.Checked == true && cbLiniiSimilaritate.Checked == false)

{

imagine_rezultat = Features2DToolbox.DrawKeypoints(imagine_cadru, vpc_imagine_cadru, culoare_puncte_interes, Features2DToolbox.KeypointDrawType.DEFAULT);

imagine_de_cautat_cu_contur = Features2DToolbox.DrawKeypoints(imagine_de_cautat_cu_contur, vpc_imagine_de_cautat, culoare_puncte_interes, Features2DToolbox.KeypointDrawType.DEFAULT);

imagine_rezultat = imagine_rezultat.ConcateHorizontal(imagine_de_cautat_cu_contur);

cbLiniiSimilaritate.Enabled = true;

}

if (cbPuncteInteres.Checked == false && cbLiniiSimilaritate.Checked == false)

{

imagine_rezultat = imagine_cadru;

imagine_rezultat = imagine_rezultat.ConcateHorizontal(imagine_de_cautat_cu_contur);

cbLiniiSimilaritate.Enabled = false;

}

if (cbPuncteInteres.Checked == false && cbLiniiSimilaritate.Checked == true)

{

cbLiniiSimilaritate.Checked = false;

}

//desenare chenar in jurul imaginii de cautat regasita in imaginea cadru

if (matrice_homografie != null) //daca matricea de homografie este nenula

{

numar_similaritati_partial.Add(true);

dreptunghi_imagine_de_cautat = new Rectangle(); //declarare dreptunghi imagine de cautat si stabilire valori initiale pentru constructie

dreptunghi_imagine_de_cautat.X = 0;

dreptunghi_imagine_de_cautat.Y = 0;

dreptunghi_imagine_de_cautat.Width = imagine_de_cautat_gri.Width;

dreptunghi_imagine_de_cautat.Height = imagine_de_cautat_gri.Height;

//initializare vector puncte dreptunghi

puncte_float = new PointF[] { new PointF(dreptunghi_imagine_de_cautat.Left, dreptunghi_imagine_de_cautat.Top), new PointF(dreptunghi_imagine_de_cautat.Right, dreptunghi_imagine_de_cautat.Top), new PointF(dreptunghi_imagine_de_cautat.Right, dreptunghi_imagine_de_cautat.Bottom), new PointF(dreptunghi_imagine_de_cautat.Left, dreptunghi_imagine_de_cautat.Bottom) };

matrice_homografie.ProjectPoints(puncte_float);

puncte_int = new Point[] { Point.Round(puncte_float[0]), Point.Round(puncte_float[1]), Point.Round(puncte_float[2]), Point.Round(puncte_float[3]) };

imagine_rezultat.DrawPolyline(puncte_int, true, culoare_chenar_imagine_gasita, 2);

}

else

{

numar_similaritati_partial.Add(false);

}

imagine_rezultat = imagine_rezultat.Resize(pbVideo.Width, pbVideo.Height, INTER.CV_INTER_CUBIC, true);

pbVideo.Image = imagine_rezultat.ToBitmap();

}

}

//functie pentru preluarea unui cadru de la elementul de captura si transpunerea lui in ImageBox

private void proceseaza_cadru_detecteaza_similaritati(object sender, EventArgs arg)

{

Image<Bgr, Byte> cadru_image_box_primar = captura.QueryFrame();

if (cadru_image_box_primar != null)

{

Image<Bgr, Byte> cadru_image_box = cadru_image_box_primar.Resize(pbVideo.Width, pbVideo.Height, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR);

Bitmap img = cadru_image_box.ToBitmap();

//Pen pen = new Pen(Color.LightSalmon, 2);

Graphics graf = Graphics.FromImage(img);

Rectangle rect = new Rectangle(0, 0, pbVideo.Width, Convert.ToInt32(pbVideo.Height / 11));

StringFormat sf = new StringFormat();

sf.Alignment = StringAlignment.Center;

graf.FillRectangle(new SolidBrush(Color.LightSalmon), rect);

graf.DrawString("Pentru capturarea elementului grafic de cautat prin intermediul camerei atasate robotului plasati elementul in spectrul vizibil al aceseia si apasati butonul 'Captureaza'", new Font("Century Gothic", pbVideo.Height / 40, FontStyle.Regular), Brushes.DimGray, rect, sf);

pbVideo.Image = img;

}

}

//functie pentru detectie siluete

private void detecteaza_siluete(object sender, EventArgs arg)

{

//procesul de detectie siluete

Image<Bgr, Byte> cadru_image_box_primar = captura.QueryFrame();

if (cadru_image_box_primar != null)

{

Image<Bgr, Byte> cadru_image_box = cadru_image_box_primar.Resize(pbVideo.Width, pbVideo.Height, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR);

Rectangle[] siluete;

//verifica daca exista procesor grafic (GPU) care sa fie compatibil cu procesul de detectie siluete

if (GpuInvoke.HasCuda)

{

//versiunea GPU

using (GpuHOGDescriptor des = new GpuHOGDescriptor())

{

des.SetSVMDetector(GpuHOGDescriptor.GetDefaultPeopleDetector());

using (GpuImage<Bgr, Byte> gpuImg = new GpuImage<Bgr, byte>(cadru_image_box))

using (GpuImage<Bgra, Byte> gpuBgra = gpuImg.Convert<Bgra, Byte>())

{

siluete = des.DetectMultiScale(gpuBgra);

}

}

}

else

{

//versiunea CPU

using (HOGDescriptor des = new HOGDescriptor())

{

des.SetSVMDetector(HOGDescriptor.GetDefaultPeopleDetector());

siluete = des.DetectMultiScale(cadru_image_box);

}

}

//stocheaza numarul de siluete pentru analiza

numar_siluete_partial.Add(siluete.Length);

foreach (Rectangle silueta in siluete)

{

cadru_image_box.Draw(silueta, new Bgr(Color.Red), 2);

}

pbVideo.Image = cadru_image_box.ToBitmap();

}

}

//functie pentru detectie caractere

private void detecteaza_caractere(Image<Bgr, Byte> imagine_sursa)

{

if (imagine_sursa != null)

{

//Image<Bgr, Byte> cadru_image_box = imagine_sursa.Resize(pbVideo.Width, pbVideo.Height, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR);

pbVideo.BackColor = Color.White;

pbVideo.BackgroundImage = null;

pbVideo.Image = imagine_sursa.ToBitmap();

tess.Recognize(imagine_sursa);

tbMesajDetectieCaractere.BackColor = Color.LightGreen;

tbMesajDetectieCaractere.Text = tess.GetText();

pbVideo.Image = imagine_sursa.ToBitmap();

}

}

private void detecteaza_numere_inmatriculare(object sender, EventArgs arg)

{

//procesul de detectie siluete

Image<Bgr, Byte> cadru_image_box_primar = captura.QueryFrame();

if (cadru_image_box_primar != null)

{

Image<Bgr, Byte> cadru_image_box = cadru_image_box_primar.Resize(pbVideo.Width, pbVideo.Height, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR);

imagini_numere_inmatriculare = new List<Image<Gray, byte>>();

imagini_numere_inmatriculare_filtrate = new List<Image<Gray, byte>>();

regiuni_numere_inmatriculare = new List<MCvBox2D>();

cuvinte_numere_inmatriculare = detector.detecteaza_numar_inmatriculare(cadru_image_box, imagini_numere_inmatriculare, imagini_numere_inmatriculare_filtrate, regiuni_numere_inmatriculare);

imagini_numere_inmatriculare_partial.AddRange(imagini_numere_inmatriculare);

imagini_numere_inmatriculare_filtrate_partial.AddRange(imagini_numere_inmatriculare_filtrate);

regiuni_numere_inmatriculare_partial.AddRange(regiuni_numere_inmatriculare);

cuvinte_numere_inmatriculare_partial.AddRange(cuvinte_numere_inmatriculare);

//for (int i = 0; i < cuvinte_numere_inmatriculare.Count; i++)

//{

// cadru_image_box.Draw(regiuni_numere_inmatriculare[i], new Bgr(Color.Red), 2);

//}

pbVideo.Image = cadru_image_box.ToBitmap();

}

}

//scalare form si controale asociate

private void scaleaza_form(float raport_latime, float raport_inaltime)

{

foreach (Control c in this.Controls)

{

c.Width = Convert.ToInt32(c.Width * raport_latime);

c.Height = Convert.ToInt32(c.Height * raport_inaltime);

c.Left = Convert.ToInt32(c.Left * raport_latime);

c.Top = Convert.ToInt32(c.Top * raport_inaltime);

}

foreach (Control c in gbSetari.Controls)

{

c.Width = Convert.ToInt32(c.Width * raport_latime);

c.Height = Convert.ToInt32(c.Height * raport_inaltime);

c.Left = Convert.ToInt32(c.Left * raport_latime);

c.Top = Convert.ToInt32(c.Top * raport_inaltime);

}

foreach (Control c in gbControl.Controls)

{

c.Width = Convert.ToInt32(c.Width * raport_latime);

c.Height = Convert.ToInt32(c.Height * raport_inaltime);

c.Left = Convert.ToInt32(c.Left * raport_latime);

c.Top = Convert.ToInt32(c.Top * raport_inaltime);

}

foreach (Control c in gbVideo.Controls)

{

c.Width = Convert.ToInt32(c.Width * raport_latime);

c.Height = Convert.ToInt32(c.Height * raport_inaltime);

c.Left = Convert.ToInt32(c.Left * raport_latime);

c.Top = Convert.ToInt32(c.Top * raport_inaltime);

}

foreach (Control c in gbSetariVideo.Controls)

{

c.Width = Convert.ToInt32(c.Width * raport_latime);

c.Height = Convert.ToInt32(c.Height * raport_inaltime);

c.Left = Convert.ToInt32(c.Left * raport_latime);

c.Top = Convert.ToInt32(c.Top * raport_inaltime);

}

foreach (Control c in gbSenzori.Controls)

{

c.Width = Convert.ToInt32(c.Width * raport_latime);

c.Height = Convert.ToInt32(c.Height * raport_inaltime);

c.Left = Convert.ToInt32(c.Left * raport_latime);

c.Top = Convert.ToInt32(c.Top * raport_inaltime);

}

foreach (Control c in pInfoSenzori.Controls)

{

c.Width = Convert.ToInt32(c.Width * raport_latime);

c.Height = Convert.ToInt32(c.Height * raport_inaltime);

c.Left = Convert.ToInt32(c.Left * raport_latime);

c.Top = Convert.ToInt32(c.Top * raport_inaltime);

}

foreach (Control c in ctProcesareImagine.Controls)

{

c.Width = Convert.ToInt32(c.Width * raport_latime);

c.Height = Convert.ToInt32(c.Height * raport_inaltime);

c.Left = Convert.ToInt32(c.Left * raport_latime);

c.Top = Convert.ToInt32(c.Top * raport_inaltime);

}

foreach (TabPage tp in ctProcesareImagine.TabPages)

{

foreach (Control c in tp.Controls)

{

c.Width = Convert.ToInt32(c.Width * raport_latime);

c.Height = Convert.ToInt32(c.Height * raport_inaltime);

c.Left = Convert.ToInt32(c.Left * raport_latime);

c.Top = Convert.ToInt32(c.Top * raport_inaltime);

}

}

foreach (TabPage tp in ctDetectieCaractere.TabPages)

{

foreach (Control c in tp.Controls)

{

c.Width = Convert.ToInt32(c.Width * raport_latime);

c.Height = Convert.ToInt32(c.Height * raport_inaltime);

c.Left = Convert.ToInt32(c.Left * raport_latime);

c.Top = Convert.ToInt32(c.Top * raport_inaltime);

}

}

}

//eveniment decalnsat la modificarea dimensiunii formului

private void Main_SizeChanged(object sender, EventArgs e)

{

latime_noua = this.Width;

inaltime_noua = this.Height;

float w = (float)latime_noua / latime_curenta;

float h = (float)inaltime_noua / inaltime_curenta;

scaleaza_form(w, h);

latime_curenta = latime_noua;

inaltime_curenta = inaltime_noua;

}

public static Image ScalareImagine(Image image, int maxWidth, int maxHeight)

{

var ratioX = (double)maxWidth / image.Width;

var ratioY = (double)maxHeight / image.Height;

var ratio = Math.Min(ratioX, ratioY);

var newWidth = (int)(image.Width * ratio);

var newHeight = (int)(image.Height * ratio);

var newImage = new Bitmap(newWidth, newHeight);

Graphics.FromImage(newImage).DrawImage(image, 0, 0, newWidth, newHeight);

return newImage;

}

//––––––––––––––––––––––––––-

//proceseaza cadru

//eveniment declansat la modificarea tbLuminozitate

private void tbLuminozitate_Scroll(object sender, EventArgs e)

{

tbValoareLuminozitate.Text = tbLuminozitate.Value.ToString();

if (captura != null)

{

captura.SetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_BRIGHTNESS, luminozitate + (tbLuminozitate.Value * 20));

}

}

//eveniment declansat la modificarea tbContrast

private void tbContrast_Scroll(object sender, EventArgs e)

{

tbValoareContrast.Text = tbContrast.Value.ToString();

if (captura != null)

{

captura.SetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_CONTRAST, contrast + tbContrast.Value);

}

}

//eveniment declansat la modificarea tbClaritate

private void tbClaritate_Scroll(object sender, EventArgs e)

{

tbValoareClaritate.Text = tbClaritate.Value.ToString();

if (captura != null)

{

captura.SetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_SHARPNESS, claritate + tbClaritate.Value);

}

}

//––––––––––––––––––––––––––-

//detectie faciala

//eveniment declansat la modificarea tbScala

private void tbScala_Scroll(object sender, EventArgs e)

{

tbValoareScala.Text = tbScala.Value.ToString();

if (captura != null)

{

Application.Idle -= detecteaza_fete;

scala_df = 1 + (Convert.ToDouble(tbScala.Value) / 10);

Application.Idle += detecteaza_fete;

}

}

//eveniment declansat la modificarea tbNrMinVecini

private void tbNrMinVecini_Scroll(object sender, EventArgs e)

{

tbValoareNrMinVecini.Text = tbNrMinVecini.Value.ToString();

if (captura != null)

{

Application.Idle -= detecteaza_fete;

treshold_nr_minim_vecini_df = Convert.ToInt32(tbNrMinVecini.Value);

Application.Idle += detecteaza_fete;

}

}

//eveniment declansat la selectarea rbFidelitateRidicata

private void rbFidelitateRidicata_CheckedChanged(object sender, EventArgs e)

{

if (rbFidelitateRidicata.Checked == true)

{

Application.Idle -= detecteaza_fete;

tip_detectie_df = Emgu.CV.CvEnum.HAAR_DETECTION_TYPE.DO_CANNY_PRUNING;

Application.Idle += detecteaza_fete;

}

}

//eveniment declansat la selectarea rbFidelitateScazuta

private void rbFidelitateScazuta_CheckedChanged(object sender, EventArgs e)

{

if (rbFidelitateScazuta.Checked == true)

{

Application.Idle -= detecteaza_fete;

tip_detectie_df = 0;

Application.Idle += detecteaza_fete;

}

}

//––––––––––––––––––––––––––-

//cronometru

//eveniment declansat o data la 2 secunde – cronometru

private void cron_Tick(object sender, EventArgs e)

{

if (ctProcesareImagine.SelectedIndex == 1)

{

var query = (from val in numar_fete_partial group val by val into g orderby g.Count() descending select g.Key).First();

numar_fete_partial.Clear();

if (Convert.ToInt32(query) != 0)

{

tbMesajDetectieFaciala.BackColor = Color.LightGreen;

tbMesajDetectieFaciala.Text = "Numar de fete detectate: " + query.ToString();

}

else

{

tbMesajDetectieFaciala.BackColor = Color.Gold;

tbMesajDetectieFaciala.Text = "Nu au fost detectate fete!";

}

}

if (ctProcesareImagine.SelectedIndex == 2 && imagine_de_cautat!=null)

{

var query = (from val in numar_similaritati_partial group val by val into g orderby g.Count() descending select g.Key).First();

numar_similaritati_partial.Clear();

if (Convert.ToBoolean(query) == true)

{

tbMesajDetectieSimilaritati.BackColor = Color.LightGreen;

tbMesajDetectieSimilaritati.Text = "Elemente similare detectate!";

}

else

{

tbMesajDetectieSimilaritati.BackColor = Color.Gold;

tbMesajDetectieSimilaritati.Text = "Nu au fost detectate elemente similare!";

}

}

if (ctProcesareImagine.SelectedIndex == 3)

{

var query = (from val in numar_siluete_partial group val by val into g orderby g.Count() descending select g.Key).First();

numar_siluete_partial.Clear();

if (Convert.ToInt32(query) != 0)

{

tbMesajDetectieSiluete.BackColor = Color.LightGreen;

tbMesajDetectieSiluete.Text = "Numar de siluete detectate: " + query.ToString();

chDetectieSiluete.Series["Numar siluete"].Points.AddXY(DateTime.Now.ToLongTimeString(), query);

}

else

{

tbMesajDetectieSiluete.BackColor = Color.Gold;

tbMesajDetectieSiluete.Text = "Nu au fost detectate siluete!";

chDetectieSiluete.Series["Numar siluete"].Points.AddXY(DateTime.Now.ToLongTimeString(), 0);

}

}

if (ctProcesareImagine.SelectedIndex == 4)

{

try

{

var query = (from val in cuvinte_numere_inmatriculare_partial group val by val into g orderby g.Count() descending select g.Key).First();

int index = cuvinte_numere_inmatriculare_partial.IndexOf(query);

if (query != null)

{

tbMesajDetectieCaractere.BackColor = Color.LightGreen;

tbMesajDetectieCaractere.Text = query.ToString();

pbDCD.Image = imagini_numere_inmatriculare_partial[index].ConcateVertical(imagini_numere_inmatriculare_filtrate_partial[index]).ToBitmap();

}

imagini_numere_inmatriculare_partial.Clear();

imagini_numere_inmatriculare_filtrate_partial.Clear();

regiuni_numere_inmatriculare_partial.Clear();

cuvinte_numere_inmatriculare_partial.Clear();

}

catch (Exception ex)

{

//nu face nimic

}

}

}

//––––––––––––––––––––––––––-

//detectie similaritati

//eveniment declansat la apasarea butonului captureaza

private void bCaptureazaDetectieSimilaritati_Click(object sender, EventArgs e)

{

if (imagine_de_cautat == null)

{

Image<Bgr, Byte> cadru_image_box_primar = captura.QueryFrame();

if (cadru_image_box_primar != null)

{

//schimba text buton

bCaptureazaDetectieSimilaritati.Text = "Actualizati imaginea de cautat";

//mesaj

tbMesajDetectieSimilaritati.BackColor = Color.LightSalmon;

tbMesajDetectieSimilaritati.Text = "Se analizeaza fluxul video…";

cbPuncteInteres.Enabled = true;

cbLiniiSimilaritate.Enabled = true;

cbDetectieSimilaritati.Enabled = true;

tbDetectieSimilaritati.Enabled = true;

//captureaza imagine de cautat din fluxul video

imagine_de_cautat = cadru_image_box_primar.Resize(pbVideo.Width, pbVideo.Height, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR);

//modifica layout

pbVideo.BackgroundImage = null;

pbVideo.BackColor = Color.Black;

Application.Idle -= proceseaza_cadru_detecteaza_similaritati;

Application.Idle += detecteaza_similaritati;

}

}

else

{

Application.Idle -= detecteaza_similaritati;

Application.Idle += proceseaza_cadru_detecteaza_similaritati;

imagine_de_cautat = null;

bCaptureazaDetectieSimilaritati.Text = "Captureaza";

tbDSImDeGasit.Text = "";

//mesaj

tbMesajDetectieSimilaritati.BackColor = Color.LightSalmon;

tbMesajDetectieSimilaritati.Text = "Selectati imaginea de cautat!";

cbPuncteInteres.Enabled = false;

cbLiniiSimilaritate.Enabled = false;

cbDetectieSimilaritati.Enabled = false;

tbDetectieSimilaritati.Enabled = false;

}

}

//eveniment declansat la modificarea indexului din combobox detectie similaritati

private void cbDetectieSimilaritati_SelectedIndexChanged(object sender, EventArgs e)

{

if (cbDetectieSimilaritati.SelectedIndex == cbDetectieSimilaritati.Items.IndexOf("Numar vecini"))

{

tbDetectieSimilaritati.Minimum = 2;

tbDetectieSimilaritati.Maximum = 10;

tbDetectieSimilaritati.Value = numar_vecini_ds;

tbValoareDetectieSimilaritati.Text = numar_vecini_ds.ToString();

tbDetectieSimilaritati.Focus();

}

if (cbDetectieSimilaritati.SelectedIndex == cbDetectieSimilaritati.Items.IndexOf("Threshold unicitate"))

{

tbDetectieSimilaritati.Minimum = 0;

tbDetectieSimilaritati.Maximum = 10;

tbDetectieSimilaritati.Value = Convert.ToInt32(threshold_unicitate_ds * 10);

tbValoareDetectieSimilaritati.Text = threshold_unicitate_ds.ToString();

tbDetectieSimilaritati.Focus();

}

if (cbDetectieSimilaritati.SelectedIndex == cbDetectieSimilaritati.Items.IndexOf("Increment scala"))

{

tbDetectieSimilaritati.Minimum = 1;

tbDetectieSimilaritati.Maximum = 10;

tbDetectieSimilaritati.Value = Convert.ToInt32((increment_scala_ds – 1) * 10);

tbValoareDetectieSimilaritati.Text = increment_scala_ds.ToString();

tbDetectieSimilaritati.Focus();

}

if (cbDetectieSimilaritati.SelectedIndex == cbDetectieSimilaritati.Items.IndexOf("Segmente rotatie"))

{

tbDetectieSimilaritati.Minimum = 1;

tbDetectieSimilaritati.Maximum = 5;

tbDetectieSimilaritati.Value = segmente_rotatie_ds / 10;

tbValoareDetectieSimilaritati.Text = segmente_rotatie_ds.ToString();

tbDetectieSimilaritati.Focus();

}

}

//eveniment declansat la modificarea tbDetectieSimilaritati

private void tbDetectieSimilaritati_Scroll(object sender, EventArgs e)

{

if (cbDetectieSimilaritati.SelectedIndex == cbDetectieSimilaritati.Items.IndexOf("Numar vecini"))

{

if (captura != null)

{

Application.Idle -= detecteaza_similaritati;

numar_vecini_ds = tbDetectieSimilaritati.Value;

tbValoareDetectieSimilaritati.Text = numar_vecini_ds.ToString();

Application.Idle += detecteaza_similaritati;

}

}

if (cbDetectieSimilaritati.SelectedIndex == cbDetectieSimilaritati.Items.IndexOf("Threshold unicitate"))

{

if (captura != null)

{

Application.Idle -= detecteaza_similaritati;

threshold_unicitate_ds = (double)tbDetectieSimilaritati.Value / 10;

tbValoareDetectieSimilaritati.Text = threshold_unicitate_ds.ToString();

Application.Idle += detecteaza_similaritati;

}

}

if (cbDetectieSimilaritati.SelectedIndex == cbDetectieSimilaritati.Items.IndexOf("Increment scala"))

{

if (captura != null)

{

Application.Idle -= detecteaza_similaritati;

increment_scala_ds = ((double)tbDetectieSimilaritati.Value / 10)+1;

tbValoareDetectieSimilaritati.Text = increment_scala_ds.ToString();

Application.Idle += detecteaza_similaritati;

}

}

if (cbDetectieSimilaritati.SelectedIndex == cbDetectieSimilaritati.Items.IndexOf("Segmente rotatie"))

{

if (captura != null)

{

Application.Idle -= detecteaza_similaritati;

segmente_rotatie_ds = tbDetectieSimilaritati.Value * 10;

tbValoareDetectieSimilaritati.Text = segmente_rotatie_ds.ToString();

Application.Idle += detecteaza_similaritati;

}

}

}

//eveniment declansat la apasarea butonului bImDeGasit

private void bImDeGasit_Click(object sender, EventArgs e)

{

if (imagine_de_cautat == null)

{

DialogResult dr = ofdDSImagineDeCautat.ShowDialog();

if (dr == DialogResult.OK || dr == DialogResult.Yes)

{

tbDSImDeGasit.Text = ofdDSImagineDeCautat.FileName;

}

else

{

return;

}

try

{

imagine_de_cautat = new Image<Bgr, Byte>(tbDSImDeGasit.Text);

}

catch

{

MessageBox.Show("Incarcarea nu a avut loc cu succes. Reincercati!");

imagine_de_cautat = null;

return;

}

if (imagine_de_cautat != null)

{

//schimba text buton

bCaptureazaDetectieSimilaritati.Text = "Actualizati imaginea de cautat";

//mesaj

tbMesajDetectieSimilaritati.BackColor = Color.LightSalmon;

tbMesajDetectieSimilaritati.Text = "Se analizeaza fluxul video…";

cbPuncteInteres.Enabled = true;

cbLiniiSimilaritate.Enabled = true;

cbDetectieSimilaritati.Enabled = true;

tbDetectieSimilaritati.Enabled = true;

//modifica layout

pbVideo.BackgroundImage = null;

pbVideo.BackColor = Color.Black;

Application.Idle -= proceseaza_cadru_detecteaza_similaritati;

Application.Idle += detecteaza_similaritati;

}

}

else

{

imagine_de_cautat = null;

Application.Idle -= detecteaza_similaritati;

Application.Idle += proceseaza_cadru_detecteaza_similaritati;

DialogResult dr = ofdDSImagineDeCautat.ShowDialog();

if (dr == DialogResult.OK || dr == DialogResult.Yes)

{

tbDSImDeGasit.Text = ofdDSImagineDeCautat.FileName;

}

else

{

return;

}

try

{

imagine_de_cautat = new Image<Bgr, Byte>(tbDSImDeGasit.Text);

}

catch

{

MessageBox.Show("Incarcarea nu a avut loc cu succes. Reincercati!");

imagine_de_cautat = null;

return;

}

if (imagine_de_cautat != null)

{

//schimba text buton

bCaptureazaDetectieSimilaritati.Text = "Actualizati imaginea de cautat";

//mesaj

tbMesajDetectieSimilaritati.BackColor = Color.LightSalmon;

tbMesajDetectieSimilaritati.Text = "Se analizeaza fluxul video…";

cbPuncteInteres.Enabled = true;

cbLiniiSimilaritate.Enabled = true;

cbDetectieSimilaritati.Enabled = true;

tbDetectieSimilaritati.Enabled = true;

//modifica layout

pbVideo.BackgroundImage = null;

pbVideo.BackColor = Color.Black;

Application.Idle -= proceseaza_cadru_detecteaza_similaritati;

Application.Idle += detecteaza_similaritati;

}

}

}

//––––––––––––––––––––––––––-

//detectie caractere

//eveniment declansat la apasarea butonului bDCSAlegetiImaginea

private void bDCSAlegetiImaginea_Click(object sender, EventArgs e)

{

DialogResult dr = ofdDCSAlegetiImaginea.ShowDialog();

if (dr == DialogResult.OK || dr == DialogResult.Yes)

{

tbDCSAlegetiImaginea.Text = ofdDCSAlegetiImaginea.FileName;

}

else

{

return;

}

try

{

imagine_OCR = new Image<Bgr, Byte>(tbDCSAlegetiImaginea.Text);

}

catch

{

MessageBox.Show("Incarcarea nu a avut loc cu succes. Reincercati!");

imagine_OCR = null;

return;

}

if (imagine_OCR != null)

{

detecteaza_caractere(imagine_OCR);

}

}

//eveniment declansat la navigarea prin taburile ctDetectieCaractere

private void ctDetectieCaractere_SelectedIndexChanged(object sender, EventArgs e)

{

//daca este selectat primul tab – Dinamic

if (ctDetectieCaractere.SelectedIndex == 0)

{

tbMesajDetectieCaractere.BackColor = Color.LightSalmon;

tbMesajDetectieCaractere.Text = "Se analizeaza fluxul video…";

Application.Idle += detecteaza_numere_inmatriculare;

cron.Start();

}

//daca este selectat primul tab – Static

if (ctDetectieCaractere.SelectedIndex == 1)

{

Application.Idle -= detecteaza_numere_inmatriculare;

cron.Stop();

tbMesajDetectieCaractere.BackColor = Color.LightSalmon;

tbMesajDetectieCaractere.Text = "Selectati imaginea sursa!";

}

}

//eveniment declansat la modificarea indexului din combobox detectie caractere-dinamic

private void cbDetectieCaractere_SelectedIndexChanged(object sender, EventArgs e)

{

if (cbDetectieCaractere.SelectedIndex == cbDetectieCaractere.Items.IndexOf("Threshold binarizare"))

{

tbDetectieCaractere.Minimum = 70;

tbDetectieCaractere.Maximum = 130;

tbDetectieCaractere.Value = detector.threshold_binarizare;

tbValoareDetectieCaractere.Text = detector.threshold_binarizare.ToString();

tbDetectieCaractere.Focus();

}

if (cbDetectieCaractere.SelectedIndex == cbDetectieCaractere.Items.IndexOf("Threshold contur"))

{

tbDetectieCaractere.Minimum = 100;

tbDetectieCaractere.Maximum = 200;

tbDetectieCaractere.Value = detector.threshold_contur;

tbValoareDetectieCaractere.Text = detector.threshold_contur.ToString();

tbDetectieCaractere.Focus();

}

if (cbDetectieCaractere.SelectedIndex == cbDetectieCaractere.Items.IndexOf("Threshold unificare contur"))

{

tbDetectieCaractere.Minimum = 150;

tbDetectieCaractere.Maximum = 250;

tbDetectieCaractere.Value = detector.threshold_unificare_contur;

tbValoareDetectieCaractere.Text = detector.threshold_unificare_contur.ToString();

tbDetectieCaractere.Focus();

}

}

//eveniment declansat la modificarea tbDetectieCaractere

private void tbDetectieCaractere_Scroll(object sender, EventArgs e)

{

if (cbDetectieCaractere.SelectedIndex == cbDetectieCaractere.Items.IndexOf("Threshold binarizare"))

{

if (captura != null)

{

Application.Idle -= detecteaza_numere_inmatriculare;

Application.Idle -= preview_threshold_binarizare;

detector.threshold_binarizare = tbDetectieCaractere.Value;

tbValoareDetectieCaractere.Text = detector.threshold_binarizare.ToString();

Application.Idle += preview_threshold_binarizare;

}

}

if (cbDetectieCaractere.SelectedIndex == cbDetectieCaractere.Items.IndexOf("Threshold contur"))

{

if (captura != null)

{

Application.Idle -= detecteaza_numere_inmatriculare;

Application.Idle -= preview_threshold_contur;

detector.threshold_contur = tbDetectieCaractere.Value;

tbValoareDetectieCaractere.Text = detector.threshold_contur.ToString();

Application.Idle += preview_threshold_contur;

}

}

if (cbDetectieCaractere.SelectedIndex == cbDetectieCaractere.Items.IndexOf("Threshold unificare contur"))

{

if (captura != null)

{

Application.Idle -= detecteaza_numere_inmatriculare;

Application.Idle -= preview_threshold_contur;

detector.threshold_unificare_contur = tbDetectieCaractere.Value;

tbValoareDetectieCaractere.Text = detector.threshold_unificare_contur.ToString();

Application.Idle += preview_threshold_contur;

}

}

}

//functie pentru preview modificari imagine la modificarea parametrului "Threshold binarizare"

private void preview_threshold_binarizare(object sender, EventArgs arg)

{

Image<Bgr, Byte> cadru_image_box_primar = captura.QueryFrame();

if (cadru_image_box_primar != null)

{

Image<Bgr, Byte> cadru_image_box = cadru_image_box_primar.Resize(pbVideo.Width, pbVideo.Height, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR);

Image<Gray, Byte> final = cadru_image_box.Convert<Gray, Byte>().ThresholdBinaryInv(new Gray(detector.threshold_binarizare), new Gray(255));

pbVideo.Image = final.ToBitmap();

}

}

//functie pentru preview modificari imagine la modificarea parametrului "Threshold contur" si "Threshold unificare contur"

private void preview_threshold_contur(object sender, EventArgs arg)

{

Image<Bgr, Byte> cadru_image_box_primar = captura.QueryFrame();

if (cadru_image_box_primar != null)

{

Image<Bgr, Byte> cadru_image_box = cadru_image_box_primar.Resize(pbVideo.Width, pbVideo.Height, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR);

Image<Gray, Byte> final = cadru_image_box.Canny(detector.threshold_contur, detector.threshold_unificare_contur);

pbVideo.Image = final.ToBitmap();

}

}

//eveniment declansat la eliberarea butoanelor mouse-ului

private void tbDetectieCaractere_MouseUp(object sender, MouseEventArgs e)

{

Application.Idle -= preview_threshold_binarizare;

Application.Idle -= preview_threshold_contur;

Application.Idle += detecteaza_numere_inmatriculare;

}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//functie pentru preluarea unui cadru de la elementul de captura si transpunerea lui in ImageBox

private void test(object sender, EventArgs arg)

{

}

private void bTest_Click(object sender, EventArgs e)

{

Application.Idle -= proceseaza_cadru;

Application.Idle -= detecteaza_fete;

Application.Idle -= detecteaza_similaritati;

Application.Idle -= proceseaza_cadru_detecteaza_similaritati;

Application.Idle -= detecteaza_siluete;

Application.Idle += test;

}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//functie full screen

private void pbVideo_DoubleClick(object sender, EventArgs e)

{

if (esteFullScreen == false)

{

//modificare flag

esteFullScreen = true;

//setare proprietate invizibil pentru toate controalele

foreach (Control ctrl in this.Controls)

{

ctrl.Visible = false;

}

//–––––––––––––––––––––––––––––

//gbVideo

//calculare raport scalare gbVideo

double raport_scalare_full_screen_orizontal_gbVideo = (double)this.Width / gbVideo.Width;

double raport_scalare_full_screen_vertical_gbVideo = (double)this.Height / gbVideo.Height;

factor_scalare_fullscreen_gbVideo = Math.Min(raport_scalare_full_screen_orizontal_gbVideo, raport_scalare_full_screen_vertical_gbVideo);

//salvare date initiale gbVideo

locatie_gbVideo = gbVideo.Location;

latime_gbVideo = gbVideo.Width;

inaltime_gbVideo = gbVideo.Height;

gbVideo.Visible = true;

//modificare date gbVideo

gbVideo.Location = new Point(0, 0);

gbVideo.Width = Convert.ToInt32(gbVideo.Width * factor_scalare_fullscreen_gbVideo);

gbVideo.Height = Convert.ToInt32(gbVideo.Height * factor_scalare_fullscreen_gbVideo);

//modificare date pbVideo

pbVideo.Width = Convert.ToInt32(pbVideo.Width * factor_scalare_fullscreen_gbVideo);

pbVideo.Height = Convert.ToInt32(pbVideo.Height * factor_scalare_fullscreen_gbVideo);

//modificare pozitie controale in gbVideo

foreach (Control c in gbVideo.Controls)

{

if (c != pbVideo)

{

c.Top = Convert.ToInt32(c.Top * factor_scalare_fullscreen_gbVideo);

}

}

//–––––––––––––––––––––––––––––

//gbControl

factor_scalare_fullscreen_gbControl = (double)((double)(this.Width – gbVideo.Width) / (double)gbControl.Width);

//salvare date initiale gbControl

locatie_gbControl = gbControl.Location;

latime_gbControl = gbControl.Width;

inaltime_gbControl = gbControl.Height;

gbControl.Visible = true;

//modificare date gbControl

gbControl.Location = new Point(gbVideo.Width, 0);

gbControl.Width = Convert.ToInt32(gbControl.Width * factor_scalare_fullscreen_gbControl);

gbControl.Height = Convert.ToInt32(gbControl.Height * factor_scalare_fullscreen_gbControl);

//modificare pozitie controale in gbControl

foreach (Control c in gbControl.Controls)

{

c.Width = Convert.ToInt32(c.Width * factor_scalare_fullscreen_gbControl);

c.Height = Convert.ToInt32(c.Height * factor_scalare_fullscreen_gbControl);

c.Left = Convert.ToInt32(c.Left * factor_scalare_fullscreen_gbControl);

c.Top = Convert.ToInt32(c.Top * factor_scalare_fullscreen_gbControl);

}

//–––––––––––––––––––––––––––––

//gbSenzori

factor_scalare_fullscreen_gbSenzori = (double)((double)(this.Width – gbVideo.Width) / (double)gbSenzori.Width);

//salvare date initiale gbSenzori

locatie_gbSenzori = gbSenzori.Location;

latime_gbSenzori = gbSenzori.Width;

inaltime_gbSenzori = gbSenzori.Height;

gbSenzori.Visible = true;

//modificare date gbSenzori

gbSenzori.Location = new Point(gbVideo.Width, gbControl.Height);

gbSenzori.Width = Convert.ToInt32(gbSenzori.Width * factor_scalare_fullscreen_gbSenzori);

gbSenzori.Height = Convert.ToInt32(gbSenzori.Height * factor_scalare_fullscreen_gbSenzori);

foreach (Control c in gbSenzori.Controls)

{

c.Width = Convert.ToInt32(c.Width * factor_scalare_fullscreen_gbSenzori);

c.Height = Convert.ToInt32(c.Height * factor_scalare_fullscreen_gbSenzori);

c.Left = Convert.ToInt32(c.Left * factor_scalare_fullscreen_gbSenzori);

c.Top = Convert.ToInt32(c.Top * factor_scalare_fullscreen_gbSenzori);

}

foreach (Control c in pInfoSenzori.Controls)

{

c.Width = Convert.ToInt32(c.Width * factor_scalare_fullscreen_gbSenzori);

c.Height = Convert.ToInt32(c.Height * factor_scalare_fullscreen_gbSenzori);

c.Left = Convert.ToInt32(c.Left * factor_scalare_fullscreen_gbSenzori);

c.Top = Convert.ToInt32(c.Top * factor_scalare_fullscreen_gbSenzori);

}

//–––––––––––––––––––––––––––––

//ctProcesareImagine

factor_scalare_fullscreen_ctProcesareImagine = (double)((double)(this.Width – gbVideo.Width) / (double)ctProcesareImagine.Width);

//salvare date initiale ctProcesareImagine

locatie_ctProcesareImagine = ctProcesareImagine.Location;

latime_ctProcesareImagine = ctProcesareImagine.Width;

inaltime_ctProcesareImagine = ctProcesareImagine.Height;

ctProcesareImagine.Visible = true;

//modificare date ctProcesareImagine

ctProcesareImagine.Location = new Point(gbVideo.Width, gbControl.Height+gbSenzori.Height);

ctProcesareImagine.Width = Convert.ToInt32(ctProcesareImagine.Width * factor_scalare_fullscreen_ctProcesareImagine);

ctProcesareImagine.Height = Convert.ToInt32(ctProcesareImagine.Height * factor_scalare_fullscreen_ctProcesareImagine);

//modificare pozitie controale in ctProcesareImagine

foreach (Control c in ctProcesareImagine.Controls)

{

c.Width = Convert.ToInt32(c.Width * factor_scalare_fullscreen_ctProcesareImagine);

c.Height = Convert.ToInt32(c.Height * factor_scalare_fullscreen_ctProcesareImagine);

c.Left = Convert.ToInt32(c.Left * factor_scalare_fullscreen_ctProcesareImagine);

c.Top = Convert.ToInt32(c.Top * factor_scalare_fullscreen_ctProcesareImagine);

}

foreach (TabPage tp in ctProcesareImagine.TabPages)

{

foreach (Control c in tp.Controls)

{

c.Width = Convert.ToInt32(c.Width * factor_scalare_fullscreen_ctProcesareImagine);

c.Height = Convert.ToInt32(c.Height * factor_scalare_fullscreen_ctProcesareImagine);

c.Left = Convert.ToInt32(c.Left * factor_scalare_fullscreen_ctProcesareImagine);

c.Top = Convert.ToInt32(c.Top * factor_scalare_fullscreen_ctProcesareImagine);

}

}

foreach (TabPage tp in ctDetectieCaractere.TabPages)

{

foreach (Control c in tp.Controls)

{

c.Width = Convert.ToInt32(c.Width * factor_scalare_fullscreen_ctProcesareImagine);

c.Height = Convert.ToInt32(c.Height * factor_scalare_fullscreen_ctProcesareImagine);

c.Left = Convert.ToInt32(c.Left * factor_scalare_fullscreen_ctProcesareImagine);

c.Top = Convert.ToInt32(c.Top * factor_scalare_fullscreen_ctProcesareImagine);

}

}

//–––––––––––––––––––––––––––––

//pbRELogo

factor_scalare_fullscreen_pbRELogo = (double)((double)(this.Width – gbVideo.Width) / (double)pbRELogo.Width);

//salvare date initiale gbSenzori

locatie_pbRELogo = pbRELogo.Location;

latime_pbRELogo = pbRELogo.Width;

inaltime_pbRELogo = pbRELogo.Height;

pbRELogo.Visible = true;

//modificare date gbSenzori

pbRELogo.Location = new Point((gbVideo.Width + (this.Width – gbVideo.Width – Convert.ToInt32(pbRELogo.Width * factor_scalare_fullscreen_pbRELogo)) / 2), pbPhoto.Location.Y);

pbRELogo.Width = Convert.ToInt32(pbRELogo.Width * factor_scalare_fullscreen_pbRELogo);

pbRELogo.Height = Convert.ToInt32(pbRELogo.Height * factor_scalare_fullscreen_pbRELogo);

}

else

{

esteFullScreen = false;

foreach (Control ctrl in this.Controls)

{

ctrl.Visible = true;

}

if (captura_in_progres)

{

lProcesareImagine.Visible = true;

ctProcesareImagine.Visible = true;

}

else

{

lProcesareImagine.Visible = false;

ctProcesareImagine.Visible = false;

}

//–––––––––––––––––––––––––––––

//gbVideo

gbVideo.Location = locatie_gbVideo;

gbVideo.Width = latime_gbVideo;

gbVideo.Height = inaltime_gbVideo;

pbVideo.Width = Convert.ToInt32(pbVideo.Width / factor_scalare_fullscreen_gbVideo);

pbVideo.Height = Convert.ToInt32(pbVideo.Height / factor_scalare_fullscreen_gbVideo);

foreach (Control c in gbVideo.Controls)

{

if (c != pbVideo)

{

c.Top = Convert.ToInt32(c.Top / factor_scalare_fullscreen_gbVideo);

}

}

//–––––––––––––––––––––––––––––

//gbControl

gbControl.Location = locatie_gbControl;

gbControl.Width = latime_gbControl;

gbControl.Height = inaltime_gbControl;

foreach (Control c in gbControl.Controls)

{

c.Width = Convert.ToInt32(c.Width / factor_scalare_fullscreen_gbControl);

c.Height = Convert.ToInt32(c.Height / factor_scalare_fullscreen_gbControl);

c.Left = Convert.ToInt32(c.Left / factor_scalare_fullscreen_gbControl);

c.Top = Convert.ToInt32(c.Top / factor_scalare_fullscreen_gbControl);

}

//–––––––––––––––––––––––––––––

//gbSenzori

gbSenzori.Location = locatie_gbSenzori;

gbSenzori.Width = latime_gbSenzori;

gbSenzori.Height = inaltime_gbSenzori;

foreach (Control c in gbSenzori.Controls)

{

c.Width = Convert.ToInt32(c.Width / factor_scalare_fullscreen_gbSenzori);

c.Height = Convert.ToInt32(c.Height / factor_scalare_fullscreen_gbSenzori);

c.Left = Convert.ToInt32(c.Left / factor_scalare_fullscreen_gbSenzori);

c.Top = Convert.ToInt32(c.Top / factor_scalare_fullscreen_gbSenzori);

}

foreach (Control c in pInfoSenzori.Controls)

{

c.Width = Convert.ToInt32(c.Width / factor_scalare_fullscreen_gbSenzori);

c.Height = Convert.ToInt32(c.Height / factor_scalare_fullscreen_gbSenzori);

c.Left = Convert.ToInt32(c.Left / factor_scalare_fullscreen_gbSenzori);

c.Top = Convert.ToInt32(c.Top / factor_scalare_fullscreen_gbSenzori);

}

//–––––––––––––––––––––––––––––

//ctProcesareImagine

ctProcesareImagine.Location = locatie_ctProcesareImagine;

ctProcesareImagine.Width = latime_ctProcesareImagine;

ctProcesareImagine.Height = inaltime_ctProcesareImagine;

foreach (Control c in ctProcesareImagine.Controls)

{

c.Width = Convert.ToInt32(c.Width / factor_scalare_fullscreen_ctProcesareImagine);

c.Height = Convert.ToInt32(c.Height / factor_scalare_fullscreen_ctProcesareImagine);

c.Left = Convert.ToInt32(c.Left / factor_scalare_fullscreen_ctProcesareImagine);

c.Top = Convert.ToInt32(c.Top / factor_scalare_fullscreen_ctProcesareImagine);

}

foreach (TabPage tp in ctProcesareImagine.TabPages)

{

foreach (Control c in tp.Controls)

{

c.Width = Convert.ToInt32(c.Width / factor_scalare_fullscreen_ctProcesareImagine);

c.Height = Convert.ToInt32(c.Height / factor_scalare_fullscreen_ctProcesareImagine);

c.Left = Convert.ToInt32(c.Left / factor_scalare_fullscreen_ctProcesareImagine);

c.Top = Convert.ToInt32(c.Top / factor_scalare_fullscreen_ctProcesareImagine);

}

}

foreach (TabPage tp in ctDetectieCaractere.TabPages)

{

foreach (Control c in tp.Controls)

{

c.Width = Convert.ToInt32(c.Width / factor_scalare_fullscreen_ctProcesareImagine);

c.Height = Convert.ToInt32(c.Height / factor_scalare_fullscreen_ctProcesareImagine);

c.Left = Convert.ToInt32(c.Left / factor_scalare_fullscreen_ctProcesareImagine);

c.Top = Convert.ToInt32(c.Top / factor_scalare_fullscreen_ctProcesareImagine);

}

}

//–––––––––––––––––––––––––––––

//pbRELogo

pbRELogo.Visible = false;

pbRELogo.Location = locatie_pbRELogo;

pbRELogo.Width = latime_pbRELogo;

pbRELogo.Height = inaltime_pbRELogo;

}

}

//eveniment declansat la navigarea prin taburile ctProcesareImagine

private void ctProcesareImagine_SelectedIndexChanged(object sender, EventArgs e)

{

//daca este selectat primul tab – Captura Video

if (ctProcesareImagine.SelectedIndex == 0)

{

Application.Idle -= detecteaza_fete;

Application.Idle -= detecteaza_similaritati;

Application.Idle -= proceseaza_cadru_detecteaza_similaritati;

Application.Idle -= detecteaza_siluete;

Application.Idle -= detecteaza_numere_inmatriculare;

cron.Stop();

imagine_de_cautat = null;

imagine_OCR = null;

Application.Idle += proceseaza_cadru;

}

//daca este selectat al doilea tab – Detectie faciala

if (ctProcesareImagine.SelectedIndex == 1)

{

Application.Idle -= proceseaza_cadru;

Application.Idle -= detecteaza_similaritati;

Application.Idle -= proceseaza_cadru_detecteaza_similaritati;

Application.Idle -= detecteaza_siluete;

Application.Idle -= detecteaza_numere_inmatriculare;

haar = new Emgu.CV.HaarCascade("haarcascade_frontalface_default.xml");

//mesaj

tbMesajDetectieFaciala.BackColor = Color.LightSalmon;

tbMesajDetectieFaciala.Text = "Se analizeaza fluxul video…";

Application.Idle += detecteaza_fete;

cron.Stop();

imagine_de_cautat = null;

imagine_OCR = null;

cron.Start();

}

//daca este selectat al treilea tab – Detectie similaritati

if (ctProcesareImagine.SelectedIndex == 2)

{

Application.Idle -= proceseaza_cadru;

Application.Idle -= detecteaza_fete;

Application.Idle -= detecteaza_siluete;

Application.Idle -= detecteaza_numere_inmatriculare;

cron.Stop();

tbDSImDeGasit.Text = "";

imagine_OCR = null;

cron.Start();

//mesaj

tbMesajDetectieSimilaritati.BackColor = Color.LightSalmon;

tbMesajDetectieSimilaritati.Text = "Selectati imaginea de cautat!";

//continuare streaming video pentru capturarea imaginii de cautat

Application.Idle += proceseaza_cadru_detecteaza_similaritati;

}

//daca este selectat al patrulea tab – Detectie siluete

if (ctProcesareImagine.SelectedIndex == 3)

{

Application.Idle -= proceseaza_cadru;

Application.Idle -= detecteaza_fete;

Application.Idle -= detecteaza_similaritati;

Application.Idle -= proceseaza_cadru_detecteaza_similaritati;

Application.Idle -= detecteaza_numere_inmatriculare;

cron.Stop();

imagine_de_cautat = null;

imagine_OCR = null;

chDetectieSiluete.Series["Numar siluete"].Points.AddXY(DateTime.Now.ToLongTimeString(), 0);

cron.Start();

Application.Idle += detecteaza_siluete;

}

//daca este selectat al cincilea tab – Detectie caractere

if (ctProcesareImagine.SelectedIndex == 4)

{

Application.Idle -= proceseaza_cadru;

Application.Idle -= detecteaza_fete;

Application.Idle -= detecteaza_similaritati;

Application.Idle -= proceseaza_cadru_detecteaza_similaritati;

Application.Idle -= detecteaza_siluete;

cron.Stop();

imagine_de_cautat = null;

//daca este selectat modul dinamic

if (ctDetectieCaractere.SelectedIndex == 0)

{

tbMesajDetectieCaractere.BackColor = Color.LightSalmon;

tbMesajDetectieCaractere.Text = "Se analizeaza fluxul video…";

Application.Idle += detecteaza_numere_inmatriculare;

cron.Start();

}

//daca este selectat modul static

if (ctDetectieCaractere.SelectedIndex == 1)

{

Application.Idle -= detecteaza_numere_inmatriculare;

cron.Stop();

tbMesajDetectieCaractere.BackColor = Color.LightSalmon;

tbMesajDetectieCaractere.Text = "Selectati imaginea sursa!";

}

}

}

}

}

Similar Posts

  • Sistemul Informational Privind Intocmirea Si Prezentarea Situatiilor Financiare

    Capitolul I Cadrul general privind întocmirea și prezentarea situațiilor financiare Avantajele conferite de existența unui cadru conceptual in contabilitatea unei țări se referă la următoarele caracteristici: reprezintă un ghid al organismului de normalizare, in opera de elaborare și perfecționare a normelor contabile; este o referință necesară rezolvării problemelor contabile pentru care nu există nici o…

  • Mediul Online

    Capitolul I. Jocul video – fenomen cultural contemporan Jocul video, una dintre principalele activitatăți de divertisment în lumea contemporană, este un joc electronic în care se interacționează cu o interfață grafică pentru a genera un răspuns vizual pe ecran. Grant Tavinor, autorul unei cărți despre arta jocurilor video le definește în felul următor: ,,X poate…

  • Arhitecturi Lan

    Arhitecturi lan CUPRINS Notiuni Generale ………………………………………………………………………………………………………………4 Reteaua de calculatoare………………………………………………………………………………………………………..4 Serverul de fisiere………………………………………………………………………………………………………………..5 Statia de lucru……………………………………………………………………………………………………………………..5 Tipuri de utilizatori………………………………………………………………………………………………………………5 Tipuri de retele……………………………………………………………………………………………………………………6 LAN…………………………………………………………………………………………………………………………………..6 WAN………………………………………………………………………………………………………………………………….9 MAN………………………………………………………………………………………………………………………………..10 Internet……………………………………………………………………………………………………………………………..11 Intranet……………………………………………………………………………………………………………………………..12 Extranet…………………………………………………………………………………………………………………………….12 Topologia retelelor locale…………………………………………………………………………………………………..13 Retea magistrala comuna…………………………………………………………………………………………………….13 Retea radiala sau stea………………………………………………………………………………………………………….15 Retea inel………………………………………………………………………………………………………………………….16 Retea Mesh……………………………………………………………………………………………………………………….16 Variante ale topologiile standard…………………………………………………………………………………………17 Topologia stea-bus……………………………………………………………………………………………………….17 Topologia stea-inel……………………………………………………………………………………………………….17 Topologia peer to peer…………………………………………………………………………………………………..18 Alte retele…

  • Piata de Automobile

    CUPRINS Introducere Capitolul 1 – Fundamente teoretice privind tema studiată 1.1 Vânzarea de mașini în România 1.2 Noțiuni teoretice despre leasing 1.3 Închirierea de mașini (Rent a car) Capitolul 2 – Noțiuni teoretice despre uneltele folosite în realizarea aplicației 2.1 Limbajul Java. Generalități. 2.2 Elemente pentru realizarea interfețelor grafice în Java 2.3 Lucrul cu baze…

  • Extinderea Interoperabilitatii Aplicatiilor Software

    ABSTRACT Capitolul I. ARHITECTURA ENTERPRISE I.1. Arhitectura Client – Server I.2. Arhitectura Multi-Nivel Distribuita I.3. Arhitectura bazată pe Servicii Web I.4. Arhitectura orientată pe servicii (SOA) I.4.1. Ce este SOA? I.4.2. Cum este structurată o arhitectură SOA? Capitolul II. SERVICII WEB II.1. Ce este un serviciu web? II.2. Arhitectura serviciilor Web II.3. Cum funcționează serviciile…

  • Scurt Istoric al Limbajului H.t.m.l

    Cuprins Introducere În octombrie 1967 s-a făcut planul pentru realizarea unei rețele de calculatoare numit ARPANET, iar în decembrie 1969 funcționau primele patru calculatoare. Problema cu care se confruntau a fost modulul de conectare separată a fiecărei rețele fără să taie legătura la resurse pentru legăturile constante. Problema a fost rezolvată printr-o tehnică numită “packet…