Ročnikový projekt: Simple Object Tracking Autor: Robert Sasák,
[email protected]
Vývojová dokumentácia Platforma Program je určený pre operačný systém Windows a je napísaný v jazyku C/C++. Spracovanie obrazu je veľmi náročné na výpočtový výkon počítača. Z toho dôvodu som zvažoval aj písanie v ANSI C. Napokon som sa aj tak rozhodol pre prehľadnejšie programovanie v C++. Všetky operácie s obrazom sú robené cez knižnicu OpenCV, ktorá je napísaná v ANSI C. Aplikácia bola vyvíjaná vo vývojovom prostredí Microsoft Visual Studio 2008. V aplikácii som použil iba knižnice STD, OpenCV a OpenGL, ktoré sú dostupné pre všetky platformy. Z toho dôvodu by malo byť možné aplikáciu spustiť aj na iných operačných systémoch.
Logické rozdelenie programu •
Získane obrazu
•
Kalibrácia kamery
•
Rozoznanie popredia
•
Určenie ťažiska
•
Určenie trojdimenzionálnych súradníc
•
Vykreslenie 3D scény
Spracovanie obrazu
Rozoznanie popredia
v
Určenie ťažiska
Určenie trojdimenzionálnych súradníc
Vykreslenie scény
Získanie obrazu
Naj technickejšia časť je získať obraz z kamery pre ďalšie spracovanie. Spôsob sa mení od výrobcu k výrobcovi. Preto som zvolil knižnicu OpenCV, ktorá obsahuje jednotný spôsob získania obrazu bez ohľadu na rozhranie a typ kamery Situácia je ešte jednoduchšia s použitím interfejsu VideoInput. VideoInput je určený na prácu s viacerými kamerami. Samotné získavanie obrazu beží v osobitnom procese. Ďalej zabezpečuje, že obraz získaný s viacerých kamier je zosynchronizovaný. Metóda CAquarium::InitCams() inicializuje VideoInput a pole images[], ktoré obsahuje aktuálny snímok z kamery. Metóda CAquarium::queryImages() načíta najnovšie snímky do images[]. Kalibrácia kamery
Na určenie polohy ryby v trojdimenzionálnom priestore pomocou kamery je nutné zistiť ohniskovú vzdialenosť kamery. Obraz môže byť taktiež z dôvodu lacnej optiky zakrivený. Alebo môže byť senzor upevnený mimo optickú os. Parametre popisujúce nedokonalosť kamery sa nazývajúci vnútorne parametre kamery(Intrinsics parameters). Z toho dôvodu je nutné pre každú kameru urobiť kalibráciu. Kalibrácia v našom prípade neznamená nastavenie kamery, ale naopak určenie parametrov. OpenCV implementuje kalibráciu nasledovne. Na kalibráciu je potrebné získať aspoň 10 snímkov šachovnice v rôznych polohách. Šachovnica ma veľmi výraznú štruktúru, ktorá sa dá algoritmicky ľahko rozoznať na snímku. Na snímkoch sa strojovo identifikuje šachovnica. Body z 10 šachovníc sa skombinujú a na základe toho sa vypočítajú vnútorné parametre kamery. Kalibráciu
v
OpenCV
CAquarium::calibrate2D()
implementuje sa
každých
CalibFIlter. 20
snímkov
V pokúsi
metóde metóda
CalibFilter.FindEtalon() nájsť šachovnicu na aktuálnom snímku. Po nájdení 15 šachovníc CalibFilter vypočíta vnútorné parametre kamery. Kalibrácia prebieha na oboch kamerách súčasne. Ďalšou výhodou CalibFilter je, že dokáže tiež určiť relatívnu pozíciu kamier voči sebe. Opäť je na výpočet použitá dvojica snímkov so šachovnicou. Táto informácia je uložená vo forme translačnej matice voči prvej kamere. Tá je neskôr určená na prevod 2D súradnic do 3D.
Rozoznanie popredia
Ryba ako taká môže mať z rôznych uhlov skoro ľubovolný tvar a farbu. Naopak pozadie je stále rovnaké. Metóda na rozoznanie popredie je založená na porovnaní modelu pozadia s aktuálnym snímkom. Najjednoduchší model pozadia je určený jeho farbou. Za akvárium umiestním zelené pozadie. Každý snímok porovnám voči zelenej farbe. Pixely, ktoré nie sú zelené označím ako popredie. Tým získam siluety objektov. Táto metóda vyžaduje však špeciálne jednofarebné pozadie, čo v akvaristike nebýva zvykom. Ďalší model uvažuje ako pozadie priemer posledných niekoľko snímkov. Popredie sa opäť získa porovnaním aktuálneho snímku s pozadím. Tento model je oproti predošlému omnoho lepší. Model sa sám aktualizuje a je odolný aj voči pomalým zmenám osvetlenia. V akváriu však sa okrem ryby pohybujú aj vodné rastliny a ovzdušňovacie bubliny. Tieto budú nesprávne označené ako popredie. Práve problém s monotónnymi pohybujúcimi objektami rieši model CodeBook. Pozostáva z dvoch fáz. V prvej fáze sa učí ako vyzerá pozadie a v druhej fáze sa, tak ako v predošlých modeloch, porovnáva s aktuálnym snímkom. Rozdielne pixely sú označené ako popredie. Pre každý pixel je udržiavaný zoznam povolených rozsahov farieb. Ak pri porovnaní farba s aktuálneho snímku je z jedného z povolených rozsahov farieb, tak je pixel označený ako pozadie. Inak je označený ako popredie. Počas prvej fáze učenia sa vytvára zoznam povolených farebných rozsahov. Táto fáza trvá v praxi niekoľko desiatok sekúnd. V druhej fáze prebieha porovnanie modelu pozadia s aktuálnym snímkom. CodeBook takto odfiltruje nežiadúce monotónne pohybujúce rastliny a bubliny. Preto som sa rozhodol práve o implementáciu tohto algoritmu. Knižnica OpenCV obsahuje implementáciu algortimu CodeBook. Moja trieda CCodeBook predstavuje objektový interface k tomuto algoritmu. Metóda init() inizializuje potrebné štruktúry. Pomocou metódy update(image) sa počas prvej fáze buduje model pozadia. V druhej fáze sa označia jednotlivé pixely ako pozadie alebo popredie. Metóda segmentation(), pospája pixely označené ako popredie do súvislých plôch. Určenie ťažiska
Pre ďalšie spracovanie polohy ryby potrebujem určiť rybu ako jeden bod na každej kamere. Následne môžem pre tieto dva body vypočítať súradnice v trojdimenzionálnom svete. Algoritmus na určenie popredia mi vrátil bitovú masku popredie. Tvar plôch
popredia sa môže na oboch kamerách veľmi odlišovať. Preto je ťažké nájsť význačný bod. Z toho dôvodu som rozhodol pre vypočítanie ťažiska plochy. Ťažisko je stabilné voči chybám na okrajoch plôch. OpenCV obsahuje funkciu cvGetSpatialMoment() na výpočet ťažiska plochy. Samotný výpočet prebieha tiež v metóde CCodeBook::segmentation(). Určenie trojdimenzionálnych súradníc
Určením ťažiska som získal bod pre každú kameru. Oboma bodmi preložím priamku vychádzajúcu z kamery. Tam kde sa tieto dve priamky pretnú, tam v priestore sa pohybuje ryba. V praxi sa však dve priamky v priestore len zriedka pretnú. Preto je vhodnejšie nájsť dva body na priamkach, ktoré sú k sebe čo najbližšie. V strede medzi týmito bodmi určím pozíciu ryby. Funkcia ImageCStoWorldCS() prevedie body zo snímku na vektory. Ďalej funkcia intersection() vypočíta pozíciu najbližších bodov. Na záver midpoint() určí stredový bod. Vykreslenie 3D scény
Získané 3D pozície som interpretoval v podobe 3D scény. Keďže sa jedná len o veľmi jednoduchú scénu, tak som si vybral na jej vyrenderovanie OpenGL. Konkrétne knižnicu GLUT. Metóda CGraphic::drawObject(point) nakreslí jednoduchú červenú bodku. Metóda CGraphic::specialKeyboard()
zachytáva stlačené klávesy a upravuje
translačnú maticu. Ako výsledok sa scéna otáča alebo približuje.