AZ ESZTÉTIKUS MARKER SZOFTVERES ÉRTELMEZÉSE ELŐFELDOLGOZOTT DIGITÁLIS KAMERAKÉP ALAPJÁN KÉSZÍTETTE: Kis Krisztián MÉRNÖK INFORMATIKUS HALLGATÓ

Hasonló dokumentumok
Loványi István vizsgakérdései kidolgozva (béta)

Csövek belső felületének vizsgálata

Brósch Zoltán (Debreceni Egyetem Kossuth Lajos Gyakorló Gimnáziuma) Gráfelmélet II. Gráfok végigjárása

15. Programok fordítása és végrehajtása

SupOrt. talpfelvétel készítő program felhasználói leírás v3.1

Készítette:

T.R.U.S.T. Tax Return Unified Support Tool. Nyomtatványkitöltő Felhasználói útmutató

Robottechnika projektfeladat

gyógypedagógus, SZT Bárczi Gusztáv Egységes Gyógypedagógiai Módszertani Intézmény 2

ARCHLine.XP Windows. Újdonságok. Felhasználói kézikönyv. ARCHLine.XP 2009 Újdonságok

Gate Control okostelefon-alkalmazás

ÓRAREND SZERKESZTÉS. Felhasználói dokumentáció verzió 2.1. Budapest, 2009.

Zárójelentés. Az autonóm mobil eszközök felhasználási területei, irányítási módszerek

BAUSFT. Pécsvárad Kft Pécsvárad, Pécsi út 49. Tel/Fax: 72/ ISO-bau. Szigetelés kiválasztó verzió.

Virtuális Egér. Horváth Zsolt, Schnádenberger Gábor, Varjas Viktor március 20.

Tanulmányozza az 5. pontnál ismertetett MATLAB-modell felépítést és működését a leírás alapján.

Conrad Szaküzlet 1067 Budapest, Teréz krt. 23. Tel: (061) Conrad Vevőszolgálat 1124 Budapest, Jagelló út 30. Tel: (061) Bresser

GÁZTURBINA-OPERÁTOROK TOVÁBBKÉPZÉSÉRE SZOLGÁLÓ SZIMULÁTOR FEJLESZTÉSE

ORPHEUS. Felhasználói kézikönyv. C o p y r i g h t : V a r g a B a l á z s Oldal: 1

Készítette: Citynform Informatikai Zrt.

Képfeldolgozási módszerek a geoinformatikában

8. Mohó algoritmusok Egy esemény-kiválasztási probléma. Az esemény-kiválasztási probléma optimális részproblémák szerkezete

Gráfokkal megoldható hétköznapi problémák

FELHASZNÁLÓI KÉZIKÖNYV

2015 június: A hallás elemzése - Winkler István

mynct v0.0.1 Maró verzió Kezelési leírás

1.1 DEVIZÁS SZÁMLA KIEGYENLÍTÉSÉHEZ KAPCSOLÓDÓ AUTOMATIKUS ÁRFOLYAM KÜLÖNBÖZET KÖNYVELÉS

A FOGLAKOZÁS ADATAI: SZERZŐ. Vindics Dóra. Vezérelj robotot! A FOGLALKOZÁS CÍME A FOGLALKOZÁS RÖVID

Régi, statikus adatok élővé tétele és vizsgálata

Töltőfunkció Kezelési Utasítás

A évi integritásfelmérések céljai, módszertana és eredményei

Csődvalószínűségek becslése a biztosításban

Dr. Pétery Kristóf: AutoCAD LT 2007 Fóliák, tulajdonságok

Korszerű raktározási rendszerek. Szakdolgozat

Felhasználói kézikönyv

Komputer statisztika gyakorlatok

Általános funkciók partitúrái. Felhasználói dokumentáció verzió 2.0.

VÁLTOZÁSOK AZ ÉTDR MŰKÖDÉSÉBEN

A Magyar Posta Zrt. hálózatában értékesített lakossági betétekre vonatkozóan.

évi nyári olimpiai játékok

KÉZIKÖNYV. Shop midi - EDU. (manual-shop-midi-hun) * :52:30. EcoSim Kft. Budapest

10. fejezet Az adatkapcsolati réteg

Visszatérítő nyomaték és visszatérítő kar

Programozás I. Metódusok C#-ban Egyszerű programozási tételek. Sergyán Szabolcs

Geoinformatika I. (vizsgakérdések)

Országos kompetenciamérés 2007 Feladatok és jellemzőik. matematika 10. évfolyam

Gate Control okostelefon-alkalmazás

Bevezetés. Párhuzamos vetítés és tulajdonságai

Orvosi diagnosztikai célú röntgenképfeldolgozás

Napfotók (webkamerás felvételek) képfeldolgozása

MUNKAANYAG. Földi László. Szögmérések, külső- és belső kúpos felületek mérése. A követelménymodul megnevezése:

Diákigazolvány Elektronikus Igénylési Rendszer Oktatási Hivatal által biztosított igénylő felület. Felhasználói kézikönyv. v 4.1


Telepítési és használati utasítás. ( Kérjük őrizze meg gondosan!)

Dr. Illés Zoltán

Fejlesztési tapasztalatok multifunkciós tananyagok előállításával kapcsolatban Nagy Sándor

FELHASZNÁLÓI KÉZIKÖNYV Fixturlaser EVO

Az ablakos problémához

Lehet vagy nem? Konstrukciók és lehetetlenségi bizonyítások Dr. Katz Sándor, Bonyhád

Szerviz modul felhasználói leírása

ÍRÁSBELI KIVONÁS. 31. modul. Készítette: KONRÁD ÁGNES

A médiatechnológia alapjai

A 3D képgenerálás komplexitása

(11) Lajstromszám: E (13) T2 EURÓPAI SZABADALOM SZÖVEGÉNEK FORDÍTÁSA

ProAnt Felhasználói Útmutató

VÁLLALATIRÁNYÍTÁSI ÜGYVITELI PROGRAMRENDSZER. Váradi László OKTATÁSI SEGÉDANYAG. 2012/13. tanév 2. szemeszter 3. foglalkozás

A poláros fény rejtett dimenziói

Számítógépes képelemzés projektmunkák 2012

Szakdolgozat. Balázs Ádám Kuk József

Oktatáskutató és Fejlesztő Intézet TÁMOP / XXI. századi közoktatás (fejlesztés, koordináció) II. szakasz. Fejlesztőfeladatok

MATEMATIKA JAVÍTÁSI-ÉRTÉKELÉSI ÚTMUTATÓ

Makroökonómia I. segédanyag február

E-Fedezetkezelő. felhasználói kézikönyv. Fővállalkozói adminisztrátorok számára

Természetközeli erdőnevelési eljárások faterméstani alapjainak kidolgozása

4. modul Poliéderek felszíne, térfogata

Scherlein Márta Dr. Hajdu Sándor Köves Gabriella Novák Lászlóné MATEMATIKA 1. MÓDSZERTANI AJÁNLÁSOK MÁSODIK FÉLÉV

Minden jog fenntartva, beleértve bárminemű sokszorosítás, másolás és közlés jogát is.

Felhasználói kézikönyv Ciklus programozás. itnc 530. NC szoftver

Diplomaterv Portál. Elektronikus szakdolgozat és diplomaterv nyilvántartó és archiváló rendszer. Felhasználói útmutató v11

Kompenzátoros szintezőműszer horizontsík ferdeségi vizsgálata

A Nemzeti Névtér megvalósításának néhány kérdése

ÖSSZEADÁS, KIVONÁS AZ EGY 0-RA VÉGZŐDŐ SZÁMOK KÖRÉBEN

MENNYIT ÉR PONTOSAN AZ INGATLANOM?

SZABADALMI LEÍRÁS 771H7. szám.

TERC-ETALON Online Építőipari Költségvetés-készítő és Kiíró programrendszer Felhasználói kézikönyv

MATEMATIKA JAVÍTÁSI-ÉRTÉKELÉSI ÚTMUTATÓ

Központi proxy szolgáltatás

Napközbeni átutalás: Gyakori kérdések és definíciók

(11) Lajstromszám: E (13) T2 EURÓPAI SZABADALOM SZÖVEGÉNEK FORDÍTÁSA. (51) Int. Cl.: A47J 31/40 ( )

ARCHLine.XP Újdonságok. Release 2

Minden jog fenntartva, beleértve bárminemű sokszorosítás, másolás és közlés jogát is.

Informatikai tevékenység 2234 Maglód, Széchenyi u Mérnöki, tanácsadói tevékenység Iroda: Mobil: Telefon:

A HV-PCI6 VIDEODIGITALIZÁLÓ KÁRTYA ÉS ALKALMAZÁSAI (HV-PCI6 Video Digitizing Card and its Applications)

A tanítói pálya elnőiesedésének történeti előzményei

Budapesti Műszaki és Gazdaságtudományi Egyetem Villamosmérnöki és Informatikai Kar Irányítástechnika és Informatika Tanszék DARU IRÁNYÍTÁSA

EGYEZMÉNY. 22. Melléklet: 23. számú Elõírás. 2. Felülvizsgált szövegváltozat

Topográfia 7. Topográfiai felmérési technológiák I. Mélykúti, Gábor

Az enyhe értelmi fogyatékos fővárosi tanulók 2009/2010. tanévi kompetenciaalapú matematika- és szövegértés-mérés eredményeinek elemzése

Számítógépi képelemzés

A TWAIN adatforrás használata

Átírás:

MISKOLCI EGYETEM GÉPÉSZMÉRNÖKI ÉS INFORMATIKAI KAR AZ ESZTÉTIKUS MARKER SZOFTVERES ÉRTELMEZÉSE ELŐFELDOLGOZOTT DIGITÁLIS KAMERAKÉP ALAPJÁN KÉSZÍTETTE: Kis Krisztián MÉRNÖK INFORMATIKUS HALLGATÓ TÉMAVEZETŐ: Dr. Vincze Dávid EGYETEMI TANÁRSEGÉD Miskolc, 2014

Tartalomjegyzék 1. Bevezetés... 2 2. Python nyelv... 3 2.1. Története... 3 2.2. Szabványos könyvtárak... 3 3. OpenCV... 4 4. A Kinect ismertetése... 4 4.1 A Kinect paraméterek... 5 5. Az esztétikus marker bemutatása... 6 6. Az esztétikus marker felismerés folyamata... 7 6.1. Az esztétikus marker színekre bontása... 7 6.2. Kontúrkeresés szűrt képen... 8 6.3. Esztétikus marker behatárolása... 8 6.4. A marker sarokpontjainak megtalálása... 9 6.5. Hasznos rész kivágása, valamint nézőpont-korrekció... 9 7. Kivágott marker forgatása... 10 7.1. Marker lila színre szűrése... 10 7.2. Kontúrkeresés a szűrt képen... 11 7.3. Bázispont keresése... 14 7.4. Forgatás végrehajtása... 16 8. Háló berajzolása... 17 9. Háromszöget alkotó pixelek vizsgálata... 26 10. Háromszög színeinek meghatározása... 40 11. Összegzés... 42 12. Summary... 43 13. Irodalomjegyzék... 44 1

1. BEVEZETÉS A technika jelenlegi fejlődése szerint a robotok hamarosan megjelennek otthonainkban. Egyelőre a legnagyobb technikai problémát a robotok önálló tájékozódása, pályatervezése, akadálykerülése, helyzetfelismerése jelenti. Az önállóság segítésére hoztak létre az emberek úgynevezett optikai markereket, melyek a robotok számára információt tartalmaznak. Segítve a saját pozíciójuk meghatározását, illetve a környezetük feltérképezését. A markerek csoportját tovább lehet bontani természetes, valamint mesterséges markerekre. A természetes markereket már nem kell kitalálni, megtervezni, jelen vannak mindenhol. Lakásunkban is számtalan dolog szolgálhat természetes markerként. Ilyen például egy ablak, ajtó, közintézményekben egy bejárat, vagy kijárat tábla és sok minden más. Viszont hátránya is van ezeknek a típusú markereknek, ugyanis az ezekből történő információ kinyerés lényegesen nehezebb, mint a mesterségesen készített markerekből. A mesterséges markerek elkészítése során leginkább arra figyelnek oda a készítők, hogy a robot számára fontos információk pontosan, gyorsan, egyszerű algoritmusokkal kinyerhetőek legyenek. Ez lehetővé teszi a robot real-time tájékozódását. A mesterséges markerek további két csoportra bontható. Ipari és esztétikus markerekre. Az ipari markerek inkább olyan környezetben használatosak, ahol gyors és hatékony beolvasás a lényeg, a kinézete egyáltalán nem számít. Lakókörnyezetben egy ilyen marker elképzelhetetlen lenne már csak a mérete miatt. Az esztétikus markert ennek kiküszöbölésére hozták létre. Célja, hogy egy otthoni környezetbe teljesen beilleszkedjen. Egyéb, speciális alakzatokkal lehet javítani a marker beolvashatóságát, az ember számára pedig dizájn elemként is szolgálhat. Szakdolgozatom során, egy korábban elkészült szakdolgozat [9], amely az esztétikus marker előfeldolgozásával foglalkozik, mutat be erre kifejlesztett algoritmusokat. Ennek folytatásaként jelen dolgozatban a marker információtartalmának kinyeréséről esik szó. 2

2. PYTHON NYELV A marker felismerését Python [10] programozási nyelvvel valósítom meg eclipse fejlesztői környezetben OpenCV könyvtár segítségével. 2.1. Története: A Python az Alapítványi Matematikai Központban, Amszterdamban (Hollandia) készült, szerzője Guido Rossum. Nevét a Monty Python csoportról kapta. Az értelmező és a szabványos könyvtárak forrás- és (a legtöbb platformra) bináris kódjai szabadon elérhetőek. A Python egy általános célú, nagyon magas szintű programozási nyelv, melyet Guido van Rossum holland programozó kezdett el fejleszteni 1989 végén, majd hozott nyilvánosságra 1991-ben. A nyelv tervezési filozófiája az olvashatóságot és a programozói munka megkönnyítését helyezi előtérbe a futási sebességgel szemben. A Python többféle programozási paradigmát is támogat (funkcionális, objektumorientált és imperatív). Dinamikus típusokat és automatikus memóriakezelést használ, ilyen szempontból hasonlít a Tcl, Scheme, Perl és Ruby nyelvekhez, emellett szigorú típusrendszerrel rendelkezik. A Python úgynevezett interpreteres nyelv, amely azt jelenti, hogy nincs különválasztva a forrás- és tárgykód, a megírt program máris futtatható, ha rendelkezünk a Python értelmezővel. A Python értelmezőt számos géptípusra és operációs rendszerre elkészítették, továbbá számtalan kiegészítő könyvtár készült hozzá, így rendkívül széles körben használhatóvá vált. 2.2. Szabványos könyvtárak: A Pythonnak igen kiterjedt és széles körű standard könyvtára van, amit még kiegészítenek az egyéb (mások által megírt) publikus modulok. A standard könyvtár adattípusokat (például számokat és listákat) tartalmaz, amelyeket egyébként a nyelv magjának tekintenek. Tartalmaz még beépített függvényeket és kivételeket, melyeket használni lehet import nélkül, viszont a legnagyobb rész természetesen modulokban van. A modulok egy részét C-ben írták meg, és beépítették az interpreterbe, másokat python forráskódban kell importálni. Ilyen könyvtár például az OpenCV. 3

3. OpenCV Az OpenCV [11] (Open Source Computer Vision) egy olyan könyvtár, melynek függvényei segítségével elvégezhető a képfeldolgozás. A könyvtár programozási funkcióinak fő célja, hogy a gépi látás valós idejű legyen. Az Intel által kifejlesztett, de már a Willow Garage és Itseez is támogatják. Szabadon használható a nyílt forráskódú BSD licenc alatt. Főként a valós idejű képfeldolgozásra fókuszál. Hivatalosan 1999-ben indult az OpenCV projekt. A fő támogatója a projekt keretében számos optimalizálási szakértő az Intel Oroszországban, valamint az Intel Performance Library Team. Az első alfa verziót az OpenCV-ből 2000-ben hozta nyilvánosságra az IEEE a Computer Vision and Pattern Recognition konferencián, és öt béta változatot adtak ki 2001 és 2005 között. Az első 1.0-ás verziót 2006-ban adták ki. 2008 közepén vállalati segítséget kapott a Willow Garage-től és újra aktív fejlesztés alá vonták a projektet. Az 1.1-es verziót 2008 októberében adták ki. A második jelentős kiadása az OpenCV-nek 2009 októberében történt Az OpenCV 2 már tartalmazta a C++ interface fő változásait. Új függvények találhatóak benne és jobb megvalósítások vannak a meglévőkhöz képest. Hivatalos kiadások 6 havonta vannak és a fejlesztéseket most egy független orosz csapat csinálja, akiket a kereskedelmi vállalat (Willow Garage) támogatja. 4. A KINECT ISMERTETÉSE A roboton található egy Kinect [6], amely a marker felismeréséért felel. A Kinect a Microsoft által fejlesztett mozgás érzékelő rendszer. Eredetileg az XBOX 360 játék konzolhoz hoztak létre. 2010-ben jelent meg az XBOX változata, majd 2 évvel később lehetővé tették a PC-t használók számára a használatot. A Kinect segítségével a játékosok a mozgásukkal, és gesztusaikkal tudják irányítani a játékot. A Kinect két kamerából tevődik össze: egy színes kamerából, és egy mélység érzékelő kamerából. A két kamerából érkező információk miatt képes követni az emberek különböző mozgásait. 4

4.1. A KINECT PARAMÉTEREI Fő tulajdonságok: RGB kamera (640x480; 30FPS) Mélységérzékelő (IR; 640x480; 30FPS) Hangérzékelő Mozgató motor a dőlésszög változtatáshoz A kamerák 640x480-as képfelbontásai egy korlátot adnak az esztétikus marker felismerése közben. Nem biztos, hogy nagyobb távolságból, oldalsó szemszögből is felismeri a markert. Látószög: Vízszintes FOV: 57, Függőleges FOV: 43 Motor függőleges szögváltoztatása: 27 Mélységérzékelő érzékelési tartománya (ajánlott): 1.2m 3.5m Mélységérzékelő érzékelési tartománya: 0.8 6 m Adatfolyam: 640x480 16-bit depth @ 30 frames/sec (mélység-térkép) 640x480 32-bit colour@ 30 frames/sec (színes kamerakép) 16-bit audio @ 16 khz Audio érzékelő (PC-n jelenleg nem működik): hangfelvétel visszhang kiszűrés beszédfelismerés több nyelven 5

5. ESZTÉTIKUS MARKER BEMUTATÁSA A felismerni kívánt markert a BME Gép- és Terméktervezési Tanszék hallgatói alkották meg, amit egy TDK [1] [2] keretében be is mutattak. A marker egy változata az 1. ábrán láthatjuk. 1. ábra: Felismerni kívánt esztétikus marker A marker közepén láthatóak háromszögek egy négyzetbe fogva. Kizárólag ez a része tartalmaz információt az esztétikus markerből. A 9 darab négyzetet 9x4 egyenlő szárú háromszögre lehetne felosztani. Ezeknek a háromszögeknek a négyzeten belüli különböző elhelyezkedése más-más információt jelenthet a robot számára. Növelni lehet a kombinációk számát, ha a színek máshogy helyezkednek el, illetve újabb szint adunk hozzá. Ismét más információt hordoz, attól függően, hogy a kis négyzetek, hol helyezkednek el a nagy négyzeten belül. A tervezés során természetesen nem feledkezhetek meg az esztétikai kívánalmakról. 6

2. ábra: Esztétikai kívánalmak [1] Ahogy a 2. ábrán is látszik az esztétikum igen csak összetett dolog. Nem elég a színeket a formákkal összeilleszteni, hanem harmóniát is kell adni a markereknek, egy-egy szín más-más textúrán különbözően hat, mely személyenként eltérő véleményt és élményt tartalmaz, hisz akárcsak a szépség az esztétikum megítélése is szubjektív. A termékek megalkotásához tervezés, kreativitás szükséges, hogy végeredménynek egy ritmusos, érzelmi tartalommal rendelkező terméket hozzunk létre. A marker rendelkezik egy bázis ponttal. Ez a marker felismerése során játszik fontos szerepet. Mindig a nagy négyzet jobb alsó sarkában található nagy, sötétlila háromszög felel meg a bázispontnak. 6. Az esztétikus marker felismerés folyamata A felismerés folyamatainak előzetes lépései egy korábbi szakdolgozatban voltak részletesen ismertetve. Vázlatosan megemlíteném a korai lépéseket. 6.1 Az esztétikus marker színekre bontása A mobil robotnak [3] [4] [5] real-time módon kell a markert detektálnia a környezetéből. A felismerés során a Kinect által készített állóképek lettek használva. A színszűrés megkezdése előtt némi elő művelet hajtódott végre, egy zajszűrési folyamat. Erre azért volt szükség, mert a Kinect által felvett kép szemcsés. Ez a szemcsésség megnehezíti 7

a színekre bontást. A zajszűrés végeztével egy simított képet kapott a készítő, amin már pontosabban elvégezhette a markeren található formák kiszűrését a színek alapján. 6.2 Kontúrkeresés a szűrt képen Miután sikeresen megszűrte a képet az 5 színre (narancssárga, citromsárga, kék, sötétlila, világoslila), következő lépésben egy háromszögkereső algoritmust használva megkereste a képen a háromszögeket. Persze a különböző zajok miatt fals háromszögek is kiértékelődtek. Ezt további négy algoritmus segítségével finomította, hogy csak a markert alkotó háromszögek maradjanak meg. Működés alapján a négy algoritmus a - behatárolt területek nagysága alapján - az oldalak aránya alapján - átlagos háromszögméret alapján - átlagos súlypont alapján szűrte ki a felesleges háromszögeket. 6.3 Esztétikus marker behatárolása Miután sikerült megtalálni a markert alkotó háromszögek nagy részét, következő lépésben a marker oldalait határolta be. Ez csak akkor valósulhatott meg, ha elegendő mennyiségű háromszöget talált meg. Kevés esetén új képet kért be és előröl kezdte a marker felismerését. Több megoldást is kipróbált, de végül a következő folyamat bizonyult megfelelőnek: A marker széleihez közeli háromszögeket vizsgálta csak meg. Minden oldalnál, különkülön a legszélső, illetve legtávolabbi két pontot vette és kötötte össze. Így jó eséllyel megtalálta mind a négy oldalt. Ezután már csak annyi teendője volt, hogy ezeket a szakaszokat meghosszabbította. 8

6.4 A marker sarokpontjainak megtalálása A sarokpontok megtalálására azért volt szükség, hogy később csak a hasznos részt vizsgáljuk. Ehhez a négy sarokpont által behatárolt területet kellett kivágni. Első lépésben egy kontúrkereső algoritmus használatával megtalálta a meghosszabbított egyeneseket. Még itt is előfordulhatnak a markertől eltérő kontúrvonalak. Ennek elkerülése miatt ismét szűrők lettek beiktatva, hogy csak a marker kontúrvonalát adja vissza az algoritmus. Ezek után az algoritmusból kinyerhető a négy sarokpont koordinátája, amivel megkezdődhet a lehetséges marker kivágása. 6.5 Hasznos rész kivágása, valamint nézőpont-korrekció A marker sarokpontjainak megtalálása után végül megkezdődhet a kivágás. A sarokpontok sorba rendezése után, egy új képet létrehozva, a sarokpontok kitoljuk az új kép megfelelő sarokpontjába. Mindeközben perspektív transzformációt végrehajtva megtörténik a nézőpont-korrekció is. 9

7. Kivágott marker forgatása Miután megtörtént a hasznos rész kivágása, további vizsgálatokra van szükség. El kell dönteni, hogy a kivágott rész valóban egy markert tartalmaz. A továbbiakban mutatom be azokat az eljárásokat és algoritmusokat, amiket kifejlesztettem a program megoldására. 7.1 Marker lila színre szűrése Első lépésben meg kell vizsgálni, hogy a kivágott (valószínűleg) marker helyes irányban van e forgatva. Azt tudom biztosra, hogy a jobb alsó sarokban kell lennie fixen egy nagyobb sötétlila háromszögnek. Ezt használom fel a döntés során. Mielőtt bármit is elkezdenék, a kapott kivágott markeren elvégzek egy zajszűrést. A szűrésnek köszönhetően a kép szemcséssége megszűnik. Ezután pontosabban felismerhetőek lesznek a színek a szűrés folyamata alatt. Első lépésben ki kell szűrni a csak lila háromszögeket. A szűréshez meg kellett határozni, hogy a lila szín milyen tartományon belül mozog a HSV rendszerben. Segítséget nyújtott a cv.scalar függvény. PURPLE_MIN = cv.scalar (135, 90,45) PURPLE_MAX = cv.scalar(170, 210,100) PURPLE_L_MIN = cv.scalar(140, 100, 90) PURPLE_L_MAX = cv.scalar(160, 140, 155) PURPLE_RED_MIN = cv.scalar(0, 90, 100) PURPLE_RED_MAX = cv.scalar(8, 120, 128) A PURPLE_RED tartományhoz a túlcsordulás miatt volt szükségem. Ennek köszönhetően jobb eredményt kaptam. A szűrés után ezt a három színt a cv.addweighted() függvénnyel hozzárendeltem egymáshoz. Így már egy képen volt az összes lila. Az eredményt a 3. ábra mutatja. 10

3. ábra: Lila színre szűrés 7.2 Kontúrkeresés a szűrt képen A kontúrkeresés első lépésében szükséges volt a szűrt kép inverzét vennem, ugyanis az inverz képen sokkal könnyebben megtalálhatóak a háromszögek kontúrvonalai. A fekete és fehér színek cseréjét a cv2.threshold, opencv függvény segítségével hajtottam végre. ret,thresh_purple = cv2.threshold(purple,127,255,1) A függvény első paraméterként megkapja a fekete fehér képet, amit a szűrés és összevonás elvégzése után kaptam. Második paramétere a küszöbérték lesz, harmadik a maximum érték, az utolsó 1-es pedig azt jelenti, hogy a kép binárisan invertált lesz. Az inverz képet a 4. ábrán szemléltetem. 11

4. ábra: A szűrt kép inverze Azonban az inverz kép - mivel már nincs semmi a környezetében mint, ahogy a képen is látszik, a széleknél a háromszögek teljesen feketék. Ilyen esetben a kontúrkereső algoritmus nem képes megtalálni a háromszöget. Ezt úgy sikerült kiküszöbölnöm, hogy egy nagyon vékony, két pixel vastagságú, fehér színű keretet húztam meg. A cv2.rectangle() függvény használatával könnyedén megoldható volt ez a probléma. cv2.rectangle(thresh_purple,(0,0),(449,449),255,2) Első paraméterként megkapja a threshold képet, második és harmadik paraméterként a kezdő és végpontot, következő a vonal színe, végül utolsó paraméterként a vastagságot pixelben megadva. Ez a pixelvastagság még nem tette pontatlanná a későbbi műveleteket. Most már elkezdődhetett a kontúrok keresése, amit egy cv2.findcontours() függvénnyel valósítottam meg. A megtalált kontúrokat pedig egy contours_purple nevű tömbbe mentettem el. contours_purple,h = cv2.findcontours(thresh_purple,1,2) 12

A megtalált kontúrokat az 5. ábrán mutatom be. 5. ábra: Lila háromszögek kontúrjai A megtalált kontúrok között találhatóak olyanok is melyekre nincs szükségem. Első lépésben az opencv ContourArea függvényének segítségével sikerült kiszűrni a csak nagy területtel rendelkező formákat és a kicsiket pedig eldobni. Ezen felül még ki kellett szűrni és csak a három sarokponttal rendelkező kontúrokat, azaz a háromszögek kontúrvonalait megtartani. Egy egyszerű if elágazással eldöntöttem, csak azokat vizsgálja tovább, amely kontúrok 3 csúcsponttal rendelkeznek. A két műveletnek köszönhetően már csak a nagy háromszögek maradtak meg. Azonban a vizsgálat során előfordult egy-két helyen, hogy még így is átcsúszott pár rossz háromszög. Elsősorban egy cikluson belül a háromszög oldalainak hossza folyamatosan mentésre kerül. elsooldal = math.sqrt(((approx[1][0][0]-approx[0][0][0])**2) + ((approx[1][0][1]-approx[0][0][1])**2)) 13

Az approx tömbben található a háromszög koordinátája, a ** pedig a hatványozást jelenti. Ugyanígy kiszámoltam a másik két oldal hosszát is. Miután megkaptam az oldalak hosszát, kiválasztottam belőlük a legnagyobb oldalt egy maximum kereséssel. A markerre pillantva kiderül, hogy a keresett háromszög legnagyobbik oldala körülbelül a marker szélességének kétötöd része. Tehát az imént kiválasztott legnagyobb hosszúságú oldalt összevetettem a marker szélességének kétötöd részével. Ez mind a cikluson belül zajlik. A következő kódrészleten ezt láthatjuk. if (maxoldal > (cv.getsize(imgfull)[0]/5*2*0.9)) and (maxoldal < (cv.getsize(imgfull)[0]/5*2*1.1)): A részletben látható cv.getsize() függvény segítségével a marker kép szélességét és hosszúságát kaphatjuk meg egy tömbben. Mivel nekünk elég csak a szélesség, így a tömb csak nulladik, azaz első elemét használjuk fel. A vizsgálat során egy tűrést is szükséges volt megadni, mivel a kapott marker nem szabályos. Az alsó határ és felső határ a marker szélességéhez köthető, tehát meret*(2/5)*0.9, a felső határ pedig meret*(2/5)*1.1. Az újabb szűrő bevezetésével sikerült a problémát véglegesen megszüntetnem. 7.3 Bázispont keresése Ezek után a megmaradt nagy háromszögek közül keresni kell a bázispontot, azaz a sarok háromszöget. Ezt úgy sikerült végrehajtanom, hogy összevetettem a háromszög pontjainak a koordinátáit a kép sarokpont koordinátáival. Amelyik pont volt legközelebb a kép valamelyik sarokpontjához, az ahhoz tartozó háromszög volt a keresett háromszög. Annak érdekében, hogy folyamatosan ellenőrizze és összevessen minden egyes nagy háromszög minden egyes pontját minden egyes sarokponttal, további ciklusok létrehozására volt szükségem. for coord in framecoord: for app in approx: A coord változó folyamatosan felveszi a marker egy sarokpont koordinátáját, mivel a framecoord tömbben azok vannak eltárolva meghatározott sorrendben. Az app változó pedig az éppen vizsgált háromszög egy csúcspont koordinátáját. Ezután megkezdődhetett egy-egy pont összevetése. 14

if abs(app[0][0]-coord[0])<20 and abs(app[0][1]-coord[1])<20: A koordinátapontoknak az x és y értékét külön vizsgáltam meg. A háromszög egyik csúcspont koordinátájának x értékét kivontam a marker egy sarokpont koordinátájának x értékéből. Ugyanígy végrehajtottam az y értékekre. Amennyiben mindkét esetben kisebb értékű lesz, mint húsz, akkor biztosak lehetünk benne, hogy megtaláltuk a sarokháromszöget. Fontos, hogy ne feledkezzünk meg arról, hogy a kivonás értékének vegyük az abszolút értékét. Íme, egy példa, hogy erre miért is van szükség: vizsgáljuk a marker azt a pontját melynek x koordinátája 450 és vizsgáljuk annak a háromszögnek azt a pontját melynek x koordinátája 350. Miután kivonjuk a 350-ből a 450-et -100-at kapunk. Láthatjuk, hogy közelébe sincs a sarokponthoz, mégis jónak értelmezi feltétel, mivel kisebb lesz, mint 20. Azonban, ha vesszük a kapott eredmény abszolút értékét, megkapjuk a tényleges távolságot. Így már a feltétel se engedi át a hibás pontot. A használt x koordinátapontok értékei csak példa jellegűek, nem pontosak. Amennyiben ezek után is mindkét feltételnek eleget tesz a vizsgált háromszög valamelyik pontja, megtaláltuk a nagy, fix helyen lévő, sötétlila háromszöget. 15

Szemléltetés a 6. ábrán. 6. ábra: Rossz helyen lévő háromszög 7.4 Forgatás végrehajtása Az 5. ábrán látható, hogy a fix háromszög a bal alsó sarokban található. Ez nem jó, mivel tudjuk, hogy ennek a lila háromszögnek a jobb alsó sarokban kellene lennie. Ennek érdekében a markert be kell forgatni a helyes irányba. A háromszög legszélső sarokpont indexe alapján döntjük el a háromszög helyét. A háromszög sarokpontjának indexét összevetjük, hogy 0-val, 1-el, vagy 3-al egyezik meg. Ha valamelyik számmal megegyezik, akkor rossz irányban van a markerünk, és meghívjuk a rotateimage() függvényünket, melynek átadjuk a képet, és az elforgatás mértékét fokban. A forgatás nagysága attól függ, hogy a coordindex melyik számmal egyezik meg. Ha 0, akkor a bázispont a bal felső sarokban van detektálva, így 180 fokot kell forgatni a képen, ha 1, akkor a jobb felső sarokban és -90 fokkal kell elforgatni, ha pedig 3, akkor a bal alsó sarokban 16

található meg, és 90 fokkal szükséges forgatni. Megvalósítása a következő kódrészletben látható. if coordindex == 0: imgfull = rotateimage(imgfull,180) if coordindex == 1: imgfull = rotateimage(imgfull,-90) if coordindex == 3: imgfull = rotateimage(imgfull,90) A kettes indexű sarokpont azért nincs benne, mert ha a pont indexe 2, akkor a háromszög jó helyen van. A roteteimage() függvényben előbb meghatározom a kép középpontját a középpont körül fogja forgatni a képet. Következő lépésben a cv2.getrotationmatrix2d() függvény létrehozza az affin mátrixot a kép középpontjából, és a szögből (amennyivel el szeretnénk forgatni a képet). A létrejött mátrix alapján pedig a cv2.warpaffin() függvény végrehajtja a forgatást a képen. rotate = cv2.getrotationmatrix2d(image_center,angle,1.0) rot_img = cv2.warpaffine(image, rotate, image.shape[0:2],flags=cv2.inter_linear) 17

A lépés végeredményét a 7. ábrán láthatjuk. 7. ábra: Jó helyen lévő háromszög 8. Háló berajzolása A kapott, már helyes irányba fordított kép alapján megkezdődhet a háló rajzolása. A hálóra a későbbiek miatt lesz szükség, azzal szabjuk meg, hogy meddig vizsgálja a pixeleket a háromszögek valós színeinek meghatározásánál. A háló készítését egy cv2.canny algoritmussal kezdtem. Ez egy éldetektáló függvény az opencv függvénykönyvtáron belül. Ahhoz, hogy az éldetektálás működjön, egy színkonverzióra volt szükségem. A képből egy fekete fehér egy csatornás, 8 bites képet hoztam létre. Ezen a képen fog történni az él keresése. Ezt a képet kapja meg a függvény első paraméternek. Második lesz az első küszöbérték a hiszterézis eljárás számára, a harmadik pedig a második küszöbérték. edges = cv2.canny(gray,10,35) 18

Mint ahogy azt látni is lehetett a kódrészletben, a talált vonalakat elmentem egy edges változóba, ugyanis még szükségem lesz rá. A végeredményt a 8. ábrán lehet látni. 8. ábra: A fekete-fehér kép detektált élei Ahogy a 8. ábrán is látszik, nagyon sok kis apró élt behúzott oda is, ahova nem kellett volna. Túlságosan pontatlan az eredmény, ezzel nem tudtam tovább dolgozni. Fél megoldást hamar találtam a küszöbértékek módosításával. A módosításnak köszönhetően rengeteg apró vonal eltűnt, és letisztultabb képet kaptam. A módosítás eredménye a 9. ábrán látható. 19

9. ábra: Az éldetektálás jobb eredménye Ahogy azt említettem, csak félmegoldást adott, hisz látható, hogy még így is maradtak benne oda nem illő vonalak. Hiába módosítottam tovább a küszöbértékeket nem adott jobb eredményt. Keresnem kellett egy másik megoldást. A cv2.houghlinesp() opencv függvény pont egy ilyen függvény, amely a megtalált éleket tovább vizsgálja és tovább szűri. Csak az egyeneseket hagyja meg. Eldobja a görbe, túl rövid és használhatatlan vonalakat. Csak az egyeneseket hagyja meg. Sajnos, ahogy a 10. ábrán is lehet látni, még így is maradt benne olyan rövid egyenes, amire nincs szükséges. Valamint a ferde éleket meg se találta. Szemléltetésképpen rárajzoltattam fehér vonallal a vizsgált marker képére. 20

10. ábra: Rossz megoldás a háló berajzolására Ahogy tovább kutattam, megtaláltam ennek a függvénynek a testvérét. A cv2.houghlines() nagyban hasonlít az előző függvényhez, de ez már megtalálja, megtartja a ferde éleket is. Illetve még jobban kiszűri a nem használható vonalakat. Szemléltetés a 11. ábrán. 21

11. ábra: Használható megoldás a háló berajzolására Következő lépésben, meghosszabbítva a vonalakat kirajzolódik a háló. A következő kódrészletben ennek a menete látható. for line in lines[0]: pt1 = (line[0],line[1]) pt2 = (line[2],line[3]) cv2.line(imgfull, pt1, pt2, (255,255,255), 3) A pt1 és pt2 fogja felvenni az adott vonal kezdő és végpontját, majd a cv2.line() függvénnyel rárajzoltattam a képre, így le tudtam ellenőrizni a végeredményt. Az eredmény a 12. ábrán látható. 22

12. ábra: Rossz háló A 12. ábrán látható, nagyon rossznak bizonyult ez a megoldás. Nem csak, hogy nem vette figyelembe a meredekséget (így a ferde éleket nem hosszabbította meg), még a közel vízszintes vonalak helyett is a két megközelítő vonalat húzott meg. Kipróbáltam egy másik, szabályosabb kivágott markeren is ezt az algoritmust. Valamivel jobb eredményt értem el. A két vonal közelebb került egymáshoz, ami már nem lett volna befolyásoló tényező, de a ferde vonalakat sajnos még így se vette figyelembe. A 13. ábrán látható ez az eredmény. 23

13. ábra: Nem elegendő háló Új megoldás után nézve, sikerült a meredekséget is figyelembe vennem. A cv2.houghlines() függvény külön elmenti a vonalak hosszát és meredekségét egy tömbbe. Ezen a tömbön végigmentem egy for ciklussal. A rho ciklusváltozó veszi fel a vonal hosszát, a theta pedig a meredekségét. Ennek a két adat segítségével ki lehet számolni a vonal folytatását, és azok végpontjait. Miután a meghosszabbított vonal végpontjait megtudtam, már csak annyi volt a teendőm, hogy a cv2.lines függvényt használva összekötöm a kezdő és végpontokat. for rho,theta in lines[0]: a = np.cos(theta) b = np.sin(theta) x0 = a*rho y0 = b*rho x1 = int(x0 + 1000*(-b)) y1 = int(y0 + 1000*(a)) x2 = int(x0-1000*(-b)) y2 = int(y0-1000*(a)) 24

A végeredmény a 14. ábrán látható. cv2.line(image,(x1,y1),(x2,y2),(255,255,255),2) 14. ábra: Háló megrajzolása Egy másik tesztképen is hasonlóan jó eredményt kaptam. A 15. ábrán látható. 25

15. ábra: Szintén jó háló Ahogy az a 14. és 15. ábrán is látszik, akadnak, olyan részek ahol megtöbbszörözi a vonalakat. Annak köszönhető ez a jelenség, hogy a kapott marker nem szabályos. A szabálytalanság miatt az éldetektálás során az egy vonalban felismert élek nincsenek teljesen egy vonalban, így a meghosszabbítás során több vonal jött létre. Ez viszont nem probléma. Igaz, így nem tudok megvizsgálni mindent pixel, de még így is elegendőt, hogy megtudjam az adott háromszög tényleges színét. A vonalhosszabbítás miatt olyan helyre is került vonal, ahová nem kellene. A nagy háromszögek esetében figyelhető ez meg. A későbbi vizsgálatok során a nagy háromszöget két kicsiként kezeltem. Amennyiben két egyforma lesz egymás mellett, tudni fogjuk, hogy az akkor egy nagy háromszög. A már használható hálót egy új, 450x450-es fekete képre rajzoltattam rá. A 16. ábrán látható. 26

16. ábra: Háló a fekete képen 9. Háromszöget alkotó pixelek vizsgálata A háromszögeket alkotó pixelek vizsgálatánál pontosabb eredményt kaphatunk, ha átalakítjuk azt HSV színrendszerbe. Ehhez szükség volt létrehozni egy üres 450x450 képet, majd egy színkonverziós függvény segítségével a markert átmentettem az üres képre, már HSV színrendszert [7] használva. cv.cvtcolor(imgfull, imghsv, cv.cv_bgr2hsv) A használt függvény a cv.cvtcolor() függvény, melynek első paramétere az RGB színrendszerű [8] marker kép. Az imghsv az üres kép, melyben az átkonvertált kép lesz letárolva. Harmadik paraméterével pedig azt adtam meg, milyen színrendszerbe konvertálja át a függvényünk. Annak érdekében, hogy a háromszögeket külön-külön meg tudjam vizsgálni, valahogy meg kellett találjam egyenként a háromszögeket, hogy aztán ciklussal végig tudjak menni rajtuk. 27

Első lépésben a korábban használt kontúrkereső algoritmust használtam fel. Annyi módosítással, hogy most az összes szín alapján kerestem a kontúrvonalakat. Miután megtalálta az összest, ismét csak a három csúcsponttal rendelkező kontúrokat hagytam meg. Ezt egy if elágazással hajtottam végre, és a feltételében volt megadva, ha a csúcspontok száma megegyezik hárommal, akkor folytatódhat a vizsgálat. Két ciklus segítségével végig tudunk menni a marker összes pixelén az x és y tengely mentén. Az isinside() függvények átadjuk az éppen vizsgált háromszög minden egyes pontjának koordinátáit, és a vizsgált pontot. Az isinside() függvényünk azért felelős, hogy visszaadja az IGAZ, valamint a HAMIS logikai értéket, attól függően, hogy a vizsgált pont benne van e a vizsgált háromszögben. A = area (x1, y1, x2, y2, x3, y3) A1 = area (x, y, x2, y2, x3, y3) A2 = area (x1, y1, x, y, x3, y3) A3 = area (x1, y1, x2, y2, x, y) return (A == A1 + A2 + A3) A kódban látható, hogy egy újabb függvény hívódik meg, az area(). Az area függvényünk a három pontból külön átadva neki egy pont x és y koordinátáját kiszámítja a terület nagyságát és visszaadja azt az isinside() függvényünknek. Ezeket az értékékeket, attól függően, hogy mely pontok lettek átadva neki különböző változókban tároljuk el. Az A változó a vizsgált háromszög területét veszi fel. Az A1, A2 és A3 pedig három különböző háromszög területét. Mindhárom esetben az egyik csúcspont a vizsgált pixel lesz, a másik kettő pedig a háromszög két csúcspontja. Az első esetben a 2. és 3. csúcspont, a második esetben az 1. és 3., az utolsó esetben pedig az 1. és 2.. Amennyiben a pont a háromszögön belül található az A1 A2 és A3 területek összege megegyezik az A háromszög területével és a függvényünk IGAZ értéket ad vissza. Ebben az esetben kinyerhető a pixel színe a cv.get2d() függvény segítségével. cv.get2d(imghsv, ycoord, xcoord) Eleinte csak egy háromszögre próbáltam ki az algoritmust, a pixeleket pedig, amelyek nem esnek bele a vizsgált háromszögön belül, szemléltetés céljából pirosra színeztem be. A 17. ábrán látható az eredmény. 28

17. ábra: Pixelvizsgálat Ahogy az a 17. ábrán is látható, megtalálta a háromszöget. Viszont rendkívül lassú volt. Illetve ez azt mutatta meg, hogy minden egyes háromszög esetén ismételten végigvizsgálja az összes pixelt a 450x450-es képen. Rettentően lassúvá vált így a pixelvizsgáló algoritmus, több percet is igénybe vett. Megpróbáltam lecsökkenteni egy adott háromszög vizsgálata esetén a háromszög környezetében lévő, feldolgozandó pixelek számát. Ezt úgy sikerült elérem, hogy a két for ciklust, amivel eddig végigmentem a marker összes pixelén, módosítottam. Manuálisan megadtam neki, hogy csak a háromszög körüli pixeleken mennyen végig. Mivel a jobb alsó háromszög volt a teszt, így a (300, 300) ponttól a (450, 450) pontig. Végeredményül a 18. ábrán látható képet kaptam. Szintén kiszíneztem azokat a pontokat pirosra, melyeket megvizsgált az algoritmus, de nem estek bele a háromszögbe. 29

18. ábra: Optimalizált pixelvizsgálat Jelentősen felgyorsult a feldolgozási idő, így az összes háromszög esetén is jóval gyorsabb lesz az algoritmus, ami már elegendő sebességgel bírna. Egy probléma jelentkezett, ami miatt mégiscsak el kellett vessem az ötletet. A manuálisan beállított for ciklusok később, futás közben nem módosíthatóak, így folyamatosan csak azt a jobb alsó sarokban lévő 150x150- es kis kockából vizsgálta a pixeleket. Emiatt egyedül csak a jobb alsó lila háromszög vizsgálata lett sikeres. Emiatt el kellett vetnem ezt a rossz megoldást és egy jobb, kézenfekvőbb módszer után kellett nézzek. Következő megoldásban, már a hálón nem kerestem háromszögeket, hanem magát a hálót használtam fel határvonalnak, ami majd megállítja az algoritmust. Hasonlóan képzeltem el a működését, mint a Paint-ben található bucket tool-nak, színkitöltő eszköznek. Az eszköz ugyanis csak addig tölti ki a területet, míg valami határoló vonal meg nem akadályozza annak tovább színezését. Mindeközben elvégezhető a pixelvizsgálat, hogy milyen színbe tartozik. 30

A megoldást rekurzív hívásokkal sikerült megvalósítani. Azaz olyan függvényhívások, melyek önmagukat hívják meg mindig más paraméterrel. Jelen esetben mindig a következő pixellel. A megoldás során itt is számtalan problémába ütköztem, de ezeket sikerült kiküszöbölnöm. Az egyik ilyen hiba az a python nyelv sajátosságából adódott. Alapértelmezetten a rekurzív hívások mélysége (ahányszor meghívja saját magát) windows operációs rendszeren 2000. Nekem körülbelül 200 000-re lenne szükségem, ami már túlzottan nagy. Ennek elkerülése érdekében felosztottam négy irányra. Balra, jobbra, fel és le, melyeket külön függvényhívásokban helyeztem el. Így már csak 50 000 szükséges. A limit beállításához importálni kellett a python egyik alapkönyvtárát, a sys könyvtárat. A könyvtárban található egyik függvény használatával, a setrecursionlimit()-el sikeresen módosítottam a mélység limitjét. Továbbiakban az algoritmust ismertetném. Első lépésben a marker sablonjáról meghatároztam a súlypontokat, hogy hol lennének az elvárt háromszögek egy tökéletesen felismert marker esetében. Ezek a súlypontok lesznek a referenciapontok, ahonnan kiindulva megvizsgáljuk a pixelek színét a háló legközelebbi vonaláig. A súlypontok fixen vannak felvéve egy tömbbe. S_pont = [[25,75],[75, 25],[75,125],[125,75],[225, 25],[175, 75], [225, 125],[275,75],[375, 25],[325, 75],[375, 125],[425, 75],[75, 175],[25, 225], [75, 275], [125, 225], [225, 175], [175, 225],[225, 275],[275, 225],[375, 175],[325,225],[375, 275],[425, 225], [75, 325], [25, 375], [75, 425], [125, 375],[225,325],[175, 375],[225, 425],[275, 375],[375, 325],[325, 375],[375,425],[425,375]] Az S_pont a tömb neve amiben el vannak tárolva a súlypontok. Utána pedig szögletes zárójelekbe felsorakoztatva az összes háromszög súlypontja. A referenciapontokat láthatóak a 19. ábrán zöld színnel jelölve. 31

19. ábra: Referencia pontok A nagy háromszögeknél megfigyelhető, hogy a referenciapont a hálón helyezkedik el. Ennek az az oka, mivel a háló kettévágta a nagy háromszöget. Ebben az esetben az a pixelvizsgálat el sem indul, hiszen egyből hálót érzékel és leáll, majd bekéri a következő háromszög súlypontját. A hiba elhárítása érdekében minden nagy háromszöget két kis háromszögként kezeltem. A kijavított referenciapontokat a 20. ábrán szemléltettem. 32

20. ábra: Javított referenciapontok A kódban ki kellett szedni a nagy háromszögek súlypontját és mindegyik helyét két-két súlyponttal helyettesítettem. A javításnak köszönhetően már megvizsgálja a nagy háromszögeket is, csak két kicsiként kezeli őket. Később azonban tudni fogjuk, ha két egyforma színű háromszög van egymás mellett, akkor azok egy nagy háromszöget alkotnak valójában. A lépés után egy for ciklussal végigmegyünk a pontokon, így lehetővé téve hogy minden háromszöget külön-külön megvizsgáljak. Cikluson belül meghívtam a floodfill() függvényemet, mely a pixelek vizsgálatáért felelős. floodfill(imghsv, marker_white_line,i[0],i[1]) Az imghsv a HSV színrendszerre konvertált képet, a marker_white_line a fekete képre kimentett hálót tartalmazza. Az i változónk a ciklusváltozó, melynek nulladik és első eleme a háromszög súlypontjának x és y koordinátáját tartalmazzák. Eleinte úgy döntöttem, nem foglalkozok a pixel színeinek kinyerésével. Arra törekedtem, hogy legyen egy működőképes algoritmusom, amely végignézi az összes pixelen. 33

Első lépésben, azzal a ponttal dolgozunk, amelyet átadtunk a függvényünknek. Ennek a pontnak kinyerjük a színét, mind a hálót tartalmazó képről, mind a markert tartalmazóról. white_px = white_line[y,x] px = img[y,x] A white_px változó veszi fel a hálót tartalmazó képből a színt, a px pedig a markerből. Ez a felcserélt x és y koordináták miatt lehetséges python nyelvben. A változók három elemű tömbök lesznek, amiknek az elemei: (255, 255, 255) fehér szín esetén. if(white_px[0]!=0): return Egy if elágazás segítségével, ha bármikor fehér vonalat ér, azaz fehér színű lesz a pixel, egyből visszatér return utasítással. Ez azt jelenti, hogy megszakad a vizsgálat, visszatér a függvényhíváshoz, és következő ponttal folytatja. Maga a feltétel fordítva működik. Mivel a háló csak két színből áll, feketéből és fehérből, így elégséges csak az első elemet megvizsgálni. Tudjuk, hogy csak fekete (0, 0, 0) és csak fehér (255, 255, 255) színből áll a háló. Ha a white_px nulladik, azaz első eleme nem egyenlő 0-val, biztosak lehetünk benne, hogy fehér vonalhoz érkeztünk. Ekkor lép életbe a pár sorral korábban említett return utasítás. Ellenkező esetben a pont felveszi a piros színt. white_line[y,x] = [0,0,255] Majd meghívja a függvény saját magát négyszer is a következő pixelekkel. Mégpedig azért négyszer, mert mind a négy irányba balra, jobbra, fel, le - vizsgálom a pixeleket. Ettől lesz az algoritmus területkitöltős. if (x < 449): floodfill(img, white_line, x+1, y) if (y > 0): floodfill(img, white_line, x, y-1) if (y < 449): floodfill(img, white_line, x, y+1) if (x < 0): floodfill(img, white_line, x-1, y) 34

A feltételekre azért van szükség, mert a szélső háromszögeknél nem mindenhol található fehér vonal. Amennyiben nem lenne a feltétel ezeken a helyeken, kifutna a rekurzió a képen kívülre. A végeredmény szemléltetése a 21. ábrán látható. 21. ábra: Algoritmus futásának tesztelése Ahogy az a 21. ábrán is látszik, egész jól végigment minden pixelen. Ezt látván megkezdődhetett a pixel színeinek kinyerése és vizsgálta. A white_line[y,x] = [0,0,255] sort, ahol felveszi a piros színt, kicseréltem a következő sorokkal. if px[0] < 55 and px[0] > 20 and px[1] < 255 and px[1] > 80 and px[2] < 255 and px[2] > 80: white_line[y,x] = [0,255,255] elif px[0] < 15 and px[0] > 0 and px[1] < 230 and px[1] > 100 and px[2] < 230 and px[2] > 100: white_line[y,x] = [0,128,255] 35

elif px[0] < 130 and px[0] > 70 and px[1] < 255 and px[1] > 50 and px[2] < 255 and px[2] > 0: white_line[y,x] = [255,0,0] elif px[0] < 160 and px[0] > 140 and px[1] < 140 and px[1] > 100 and px[2] < 155 and px[2] > 90: white_line[y,x] = [255,0,128] elif px[0] < 160 and px[0] > 135 and px[1] < 240 and px[1] > 90 and px[2] < 100 and px[2] > 45: white_line[y,x] = [128,0,64] else: white_line[y,x] = [0,0,255] Minden egyes tartomány külön színt jelöl. Egy példán keresztül magyaráznám el, miért is van szükség tartományokra. A kék szín HSV kódja (100, 100, 240). A vizsgált pixelek a különböző zajok és a szemcsézettség miatt biztos, hogy nem adják vissza ilyen pontosan a pixelek színkódjait. Például az egyik kék pixel kódja (105, 120, 235). Ha nem tartománnyal vizsgálnánk, nem kéknek ismerné fel. Tartományok: 22. Citromsárga: (20, 80, 80) (55, 255, 255) 23. Narancssárga: (0, 100, 100) (15, 230, 230) 24. Kék: (70, 50, 0) (130, 255, 255) 25. Világos lila: (140, 100, 90) (160, 140, 155) 26. Sötét lila: (135, 90, 45) (160, 240, 100) Az utolsó else ágnál lévő színfelvételre csak a szemléltetés miatt van szükség, lényegi része nincs. Miután lefuttattam a kódot egy hibaüzenettel találkoztam. A rekurziót vélte hibásnak, az üzenet pedig: Stack overflow volt. Ez egy verem túlcsordulási hiba, ami a túlzott memória használat esetén jelentkezik. A verem számára korlátozott mennyiségben áll rendelkezésre memória. Valamint a mérete a használt programozási nyelvtől is függ. Elsőnek törölni próbáltam az éppen nem használt változókat a del() függvény segítségével, hogy helyet szabadítsak fel. Sajnos nem vezetett megoldásra, ugyanis olyan nagymértékű a rekurzió mélysége. 36

Másodjára a négy oldal hívását nem csak külön hívásokba helyeztem el, hanem külön függvényt is írtam nekik. Ennek hatására a függvényeknek külön-külön hely foglalódott a memóriában, így már elegendő volt a verem nagysága. A külön függvények miatt ki kellett egészítenem minden függvényt még pár plusz hívással. Ezzel értem el azt, hogy a függvények meghívják egymást és ne szakadjon meg a folyamat egy irány vizsgálata után. floodfill1(img, white_line, x-1, y) floodfill2(img, white_line, x+1, y) floodfill3(img, white_line, x, y+1) floodfill4(img, white_line, x, y-1) A futtatás során ismét hibába ütköztem. Index túllépés jelentkezett a floodfill4()-es függvény meghívása során. A kódot tanulmányozva rájöttem, hogy itt is ugyanaz a hiba lépett fel, mint korábban, az indextúlcsordulás. Ennek megoldására ismét feltételekbe kellett foglaljam a hívásokat. A feltételek: x < 449, akkor meghívódik a floodfill1 x > 0, akkor a floodfill2 y < 449, akkor a floodfill3 y > 0, akkor a floodfill4 A hívások eredménye a hiba kijavítása után a 22. ábrán látható. 37

22. ábra: A kitöltés rossz eredménye Amint az a képen is látszik a tartományok jól működnek, és jól felismerte a színeket, viszont meglepődve figyeltem, hogy csak a négy irányba vizsgált pixeleket. Tesztelés során kiderült, ha más sorrendbe hívom meg a függvényeket jobb eredményt kapunk, de nem elégségest. Valamint nincs is szükség meghívni mindet. Például a bal irányba történő vizsgálat után a fel és le irányt is szükséges meghívni. A többi iránynál ugyanígy jártam el. A módosítások eredménye megtekinthetőek a 23. ábrán. 38

23. ábra: Kitöltés jobb, de nem jó kitöltése Miután megváltoztattam a hívások sorrendjét, jóval jobb eredményt kaptam. Azonban, ahogy a 23. ábrán látszik, még mindig hiányzott az egyik irányban a vizsgálat. További tesztelések során, sikerült kijavítanom a problémát. Ehhez arra volt szükségem, miután például a bal irányba elkezdtem vizsgálni a pixeleket, ne utána hívja meg a fel és le irányt, hanem közvetlenül a vizsgálat közben. Az alábbi kódrészletnél látható a megoldás. if x > 0: floodfill1(img, white_line,x-1,y) if y > 0: floodfill4(img, white_line,x,y-1) if y < 449: floodfill3(img, white_line,x,y+1) else: floodfill(img,white_line,x,y) 39

Miután meghívja a floodfill1() függvényünket, azaz a bal irányt, láthatjuk, hogy egyből hívja meg a fel és le irányt. Persze ez csak akkor történik meg ha eleget tesz a feltételnek a vizsgált pont y koordinátája. Az eredmény a 24. ábrán látható. 24. ábra: Jó kitöltés A 24. ábrán is jól látszik, hogy vannak piros foltok a felismerés során. Piros színnel azokat a pixeleket jelöltem be, melyek nem estek bele egyik tartományba se. Ez úgy fordulhatott elő, hogy a markeren különböző foltok, fények találhatóak, így kívül estek a tartományon. A másik észrevétel, hogy egyes esetekben nem vizsgálta végig az algoritmus a háromszögen belül pixeleket. A kiindulási pontok azok a súlypontok voltak, ahol várhatóan lenne egy szabályos markeren lévő háromszögek súlypontjai. Mivel ezek a pontok nem egyeztek meg a háló által behatárolt háromszögek súlypontjaival mivel a vizsgálat elején kapott kivágott marker nem szabályos így a torzabb háromszögek esetén hamarabb falba ütközött a vizsgálat és leállt a folyamat. 40

Ennek ellenére elegendő információt ki lehet nyerni annak érdekében, hogy megfelelő biztossággal ki lehessen jelenteni, hogy egy háromszög milyen színű. 10. Háromszög színeinek meghatározása Miután sikerült kellő pontossággal meghatározni a pixelek színeit, egy kis kiegészítés szorult a programkód. A kiegészítés után már ki lehet jelenteni a háromszögek színeit. Első lépésben a tartományvizsgálat résznél kellett kiegészíteni. Létrehoztam hat üres tömböt melynek nevei yellow, orange, blue, darkpurple, lightpurple és other. Tehát a markert alkotó színek angol elnevezéseivel. Az other tömbbe fognak került azok a pixelek, melyek egyik tartományba se esnek bele. Példának felhozva kék színt. elif px[0] < 130 and px[0] > 70 and px[1] < 255 and px[1] > 50 and px[2] < 255 and px[2] > 0: white_line[y,x] = [255,0,0] if [x,y] not in blue: blue.append([x,y]) Miután a pixel felveszi az új színt, egy elágazás segítségével megvizsgáljuk a pixel koordinátáit, hogy már benne van e már a blue tömbbe. Amennyiben nincs még benne akkor hozzáfűzi a tömbhöz az append() beépített tömbkezelő függvény segítségével. Azért van erre szükség, mert miután az egyik irányból átvált egy másik irányba a vizsgálat, a súlypontot újra megvizsgálja. Ha nem lenne benne ez a feltétel, megduplázná ezeket a pontokat a tömbbe, és így egy kicsit csalóka lenne a pixelek száma. Második lépésben pedig annál a for ciklusnál történik módosítás, ahol a ciklusváltozó végigmegy a súlypontokon, ezáltal külön vizsgálva a háromszögeket. Ahogy az a 24. ábrán látható, egy háromszögön belül több szín is megjelenhet. Például a legfelső narancssárga sor középső eleme. Található benne kék, piros szín is a narancssárga mellett. Emiatt a háromszöget alkotó pixeleket többségi szavazásra kellett bocsájtsam. for j in [orange, blue, yellow, lightpurple, darkpurple, other]: list.append(len(j)) A ciklus előtt létrehoztam egy list nevű tömböt, és egy újbóli ciklussal még a korábbi cikluson belül egy tömbbe gyűjtöm a különböző színeket tartalmazó tömbök hosszát. Így 41

megtudtam, hogy egy adott színből hány darab található a háromszögön belül. A tömbök hosszát a len() beépített függvény segítségével határoztam meg. Ezután vettem a max() függvény segítségével a list tömb legnagyobb elemét. Majd azt, hogy egy háromszögben van e megfelelő mennyiségű ugyanolyan színű pixel a döntéshez két feltételhez kötöttem. if sum(list)!= 0: if ((float(maximum) / sum(list)) * 100) > 70: Az első feltételnél, kikötöttem, hogy a list tömböm nem lehet nulla értékű. Amennyiben nullát kapnék, annyira felismerhetetlen a háromszög, hogy nem lehet eldönteni róla, pontosan milyen színű is az. Amennyiben nem nulla, tehát van rá esély, hogy meghatározható a pixel színe, bevezettem a többségi szavazást. A maximum elemet elosztottam az összes háromszöget tartalmazó pixellel, majd megszoroztam 100-zal. Ha a kapott szám nagyobb százalékot ér el, mint 70%, akkor kijelenthetem a háromszög színét. if maximum == len(orange): print "Az adott sulypontu haromszog narancssarga szinu: ", "x: ", i[0], "y: ", i[1] Ahhoz, hogy ki tudjam jelenteni, hogy a háromszög pontosan milyen színű összevetettem a maximum elemet a színek pixeleit tartalmazó tömb hosszával. Ahol egyezést talált olyan színű lesz az adott súlypontú háromszög. A fenti kódban a narancssárga színre láthatunk példát. A többi szín is hasonlóképpen van megvalósítva. Végezetül a színek pixeleit tartalmazó tömböket lenulláztam. yellow, orange, blue, darkpurple, lightpurple, other = [],[],[],[],[],[] Ennek köszönhetően azt értem el, hogy a benne tárolt pixelek mindig csak annak a súlypontú háromszögnek a pixeleit tartalmazza, amit éppen vizsgálok. Az idáig bemutatott algoritmus képes tehát meghatározni, hogy valóban esztétikus markerrel van-e dolgunk, ha igen, akkor pedig képes kinyerni a marker háromszögeibe kódolt információt. Az algoritmusok implementációja, illetve működőképes demonstrációs programja megtalálható a cd mellékleten. 42

11. Összegzés A technológia folyamatos fejlődésének köszönhetően, a mobil robotok egyre inkább elterjednek, mind az iparban, mind az otthonainkban. Az újonnan készülő robotok önálló helyzetfelismerésének, pozícióváltoztatásának, akadálykerülésének megvalósítása a mérnökök számára újabbnál újabb kihívást jelentenek. Magát a programot, úgy kellett elkészítenem, hogy közvetlenül kapcsolódjon, a markert felismerés korábbi lépéseit megvalósító implementációhoz. Erre azért volt szükség, mert Barta János [9] szakdolgozat témája, és a saját témám közösen alkot egy nagyobb projektet. Szakdolgozatom során, a Kinect által már korábban rögzített, majd környezetéből kivágott lehetséges markert vizsgáltam tovább. Lépésről lépésre mutattam be egy lehetséges megoldást arra, hogy megvizsgáljuk a környezetéből kivágott részt, valóban egy információt tartalmazó markert ábrázol-e. Miután sikerült eldönteni, hogy a marker, valóban marker, nem jelenti azt, hogy a robot sikeresen feldolgozta a számára szükséges információt. A markeren belül számtalan variáció lehet a háromszögek elhelyezkedésére, valamint a színkombinációk száma is rengeteg. Ezért további algoritmusok szükségesek az információ feldolgozása érdekében. Az általam írt program a későbbiekben segítséget nyújthat több mobil robot számára is, amelyek a tájékozódáshoz a fent bemutatott esztétikus markert használják. Ötletet adhat, hasonló felépítésű markert felismerő programok elkészítésében. A python interpretes nyelv. Nincs különválasztva a forrás és tárgykód, emiatt lassan végzi el a megírt algoritmusokat. A javulás érdekében C vagy C++ nyelvre átültethető. 43

12. Summary Thanks to the intense developments in the field of robotics, mobile robots are becoming more and more common, both in the industry and in our homes. It is a challenging task for the engineers to make newer and newer robots with the capability of self-coordination, navigation and obstacle avoidance. I had to design and implement the program code to extend the previous implementation of the aesthetic marker recognition process. My thesis and the thesis work of János Barta [9], which describes the basic recognition mechanism, are involved in a more complex robotics project. In my thesis, I examined the aesthetic marker preprocessing method developed earlier [9]. This latter method results in an image, which contains the aesthetic marker, which has been cropped from the original image after successful detection of the marker. I give a possible step by step solution for deciding whether the marker, which was found by the previous method, is really an image of a valid aesthetic marker or not. Once it is determined that the marker is a real aesthetic marker, it does not necessarily mean that the contents can be processed and the incorporated information can be extracted. There are several possibilities for the arrangement of the triangles within the marker and there are many combinations for the used colors also. Therefore, other separate algorithms are needed to process the information stored in the marker. The program I have implemented can help in the development of future mobile robots, which make use of the aesthetic marker presented earlier. It can also serve as a base for developing similar programs on this subject. The programming language I used for the implementation, Python is an interpreted language. Hence the source and the object codes are not separated, therefore the implemented algorithms are performed relatively slowly. For improving the performance of the proposed methods, the code is planned to be ported to C or C++ programming language. 44

13. Irodalomjegyzék [1] Haláchy Nóra, Schmidt Dorottya: Esztétikus markerek robot lokalizációhoz, BME TDK konferencia, 2012 [2] Farkas, Z.V., Korondi, P., Illy, D., Fodor, L.: Aesthetic marker design for home robot localization, IECON 2012-38th Annual Conference on IEEE Industrial Electronics Society, 25-28 Oct. 2012, pp. 5510-5515. [3] Toronyi Zsuzsanna Szilvia: Mozgáskorlátozottak életkörülményeit segítő robot termékfejlesztése, BME Gépészmérnöki Kar, 2013 [4] Kovács Róbert: Portás és takarító robot termékfejlesztése, BME Gépészmérnöki Kar, 2013 [5] Navratil Péter: Kilincsnyitó mechatronikai modul tervezése mobil robotba, BME Gépészmérnöki Kar, 2013 [6] Microsoft: Kinect for Windows: http://www.microsoft.com/en-us/kinectforwindows/ (2014. május) [7] Varga Zoltán: Digitális képfeldolgozás és multimédia, Interaktív Oktató CD http://mazsola.iit.uni-miskolc.hu/data/segedletek/kepfeld_multm/vargaz/digim-colors.htm (2014. május) [8] Batta Imre: Az RGB színrendszerek http://www.epab.bme.hu/oktatas/jegyzetek/visualization/14_rgb.pdf (2014. május) [9] Barta János: Esztétikus marker felismerése digitális kameraképből nyílt forráskódú eszközök segítségével, Miskolci Egyetem, Gépészmérnöki és Informatikai Kar, 2013 [10] Python documentation: The Python Language Reference https://docs.python.org/3/reference/index.html (2014. május) [11] OpenCV User Guide http://docs.opencv.org/doc/user_guide/user_guide.html (2014. május) 45