Miért nem halad a projekt?

     Úgy lenne kedvem egyet panaszkodni, mennyi baj van egy ilyen projekttel... De ettől most eltekintek. Ehelyett inkább leírom, miért is nem halad a projekt...

     Legelső és legfontosabb: alkatrész... Valamelyik korábbi bejegyzésben volt egy videó, amin lehetett látni, mi történik a lábakkal, ha a pók a teljes súlyával ránehezedik... Nem bírja, s kész... Megoldás? Más anyagból elkészíteni. Mi ezzel a gond? Négy milliméteres alumínium lemezt nem lehet, csak 2x1 méteres méretben kapni. Egy ilyen lemez három és fél millió lejbe kerül. Nekem csak egy nyolcada kellene ennek a méretnek, amiért semmi értelme egy ekkora darabot megvásárolni... A 2actives igérte, hogy ha lesz nekik, akkor adnak egy akkora darabot... Sajnos az idő elég gyorsan eltelt, alumínium meg nem került.

     Ma elmentünk Ernyére (ne kérdezd hol van, mert én is most jártam ott először) s vettünk egy darab inox lemezt. Igaz, csak két milliméter vastag, de nagyon kemény... Feljöttem vele az egyetemre, azzal a szándékkal, hogy itt kivágódik az illető elem, de az élet újabb akadályt gördített elém. Az az ember, aki a CNC géppel foglalkozik (Lőrincz András mérnökúr) sajnos ezen a héten nincs itt az egyetemen. Így a probléma megoldása várat magára egészen hétfőig.

     Másik probléma : dolgozat. El nem hinné az ember, mennyi gond van egy ilyen dolgozattal. Megszerkeszteni az ábrákat, utánajárni a forrásanyagnak, megfelelő stílust használni, kigondolni a szöveget, azt mind leírni, újra meg újra átolvasni, majd újraírni, majd újraszerkeszteni...

     Ez az utóbbi foglalta le az időm nagyrészét... Meg a forráskódok átírása egy publikáható formába.

     Remélhetőleg a jövő héten, miután elkészül az alkatrész, már több időm lesz mindenfélére...

     Még írnék, de végetért az óra... Megyek fel a könyvtárba, megcsinálom a tavalyi projekt bemutatóját.

Kísért a múlt, avagy régi problémák új megvilágításban

     Látjátok feleim szümtükkel... De nem látjátok... Megint ugyanabba a hibába este, mint annó a projekt kezdetén... Meggondolatlanul (csak a lokális minimumra koncentrálva) egy olyan megoldást alkalmaztam, ami helyben elfedte a problémát, viszont hosszú távon biztos bukáshoz vezetett. Ez a tulajdonságokat kiszámoló kis függvényekben nyilvánult meg. Amikor (még tesztelési fázisban) csak 18*18-as képekkel kellett csak dolgozni, a matlabból C-be átírt kód nem hozta azt az eredményt, amit elvártam tőle. Ennek egyszerű oka volt. A matlabban az indexelés 1-től kezdődik, ezzel ellentétben a microblaze tömbjeinek indexe (a standard C-nek megfelelően) 0-tól kezdődik. Matlabban ezt úgy oldottam meg, hogy egy for ciklussal végigmentem a tömbön, s minden nullás értéket egyre cseréltem (lesz ami lesz alapon). A microblazen futó programban pedíg nagyvonalúan kerekítettem egy kicsit (a 100-ból 97 lett, az 50-ből 48, a 30-ból pedig 28). Ez, amíg csak 18*18-as képeken kellett tesztelni, addig nem okozott problémát. Viszont, mikor elérkezett a pillanat, hogy nagyobb méretekkel is hosszanpásztázzam a képet, kiderült, hogy talán nem ez volt a legjobb (kényszer)megoldás.

     Többszöri kisérlet és próbálkozás után arra a következtetésre jutottam, hogy csak úgy lehet megoldani, mint a matlabban (vagy megint kezdhetem előlről a tanítástól az egészet). Berakok egy plusz for ciklust, amivel megnézem, hogy hol nem nulla az illető pozícióérték és ott kivonok belőle egyet (hogy megfeleljen a standard C-s indexelési eljárásnak). Persze a téma még nyitott. Lehet, hogy a 2.0 verzióban már másképp fogom megoldani ezt az egészet.

Addig egy újabb kép, hogy a (már frissített forráskódú) Microblaze és matlab mennyire hasonlóan és mennyire pontosan számolja ki az illető tulajdonságértékeket:

Hexapod újdonságok

     Arra gondoltam, írok mégegy bejegyzést, mert a motorvezérlések órát nagyon unom... Beszámolok a fejleményekről. Kezdeném a legutóbbi videóval... Az a rózsaszín cetlis. Bármennyire is bonyolultnak tűnik, egy elég egyszerű alkalmazásról van szó.

     Legelső lépés: fogjuk a kamera grafikus felületét, s készítünk vele pár képet a követni kívánt objektumról. (Sajnos képeket most nem tudok berakni...) Ha ez megvan, megvizsgáljuk, hogy az illető szín milyen tartományokon belűl van. Ez a legfontosabb paraméter a színkövetésben. A tartomány. A rózsaszín színnek a következő paraméterei vannak : R : 170-190 ; G : 40-60; B : 30-50; 

     Addig már eljutottunk (korábbi bejegyzések segítségével), hogy megérkezik a képinformáció az FPGA-ba. Végigmegyünk egy for ciklussal a pixeleken és megvizsgáljuk, hogy melyik pixel van a megjelölt tartományon belül. Ha elég pontosan adtuk meg a tartományokat, akkor még azt is meg tudjuk határozni, hogy milyen távol van az illető objektum a kamerától. De ne szaladjunk ennyire előre. For ciklus. Végigpásztázzuk a képet, megvizsgáljuk, hogy hol vannak olyan pixelek, amelyek az illető tartományon belül van. Ha találunk egy ilyen pixelt, annak az X és Y koordinátáját eltároljuk valahová. Ha végeztünk a pásztázással, összeadjuk az X koordinátákat külön illetve az Y koordinátákat külön és elosztjuk a talált pixelek számával (vagyis átlagot számolunk belőle). Ha ezzel megvagyunk, megkapjuk az illető objektum közepét (persze ez nem mindig így működik... ha nem volt elég pontos a színbeállítás, akkor lehetnek elég komoly eltérések). A jobbra-balra irányban mozgató szervó 80 és 180-as PWM kitöltési tényező között mozoghat, hogy ne ütközzön bele a saját lábába (azt tudjuk, hogy a szervónak a két végállását a 0 és 255 közötti PWM kitöltési tényező adja). A koordináták, amit kapunk valahol 0 és 90 között vannak, mivel a kép horizontálisan tömörítve van egy kicsit (részletekért lásd a CMUCam3 felhasználói kézikönyvet). Ezt kell átalakítani kitöltési tényezővé. A fel-le irányú mozgás koordinátája 0 és 145 között mozog, ezt is szintén 80 és 180 közötti kitöltési tényezővé kell átalakítani...

     Franc essen bele.. nem tudok normálisan fogalmazni... Ez volt a baj a dokumentációnál is. Próbáltam nem konyhanyelven fogalmazni, de szinte mindíg belebonyolódtam a saját mondatomba. A kivonatomról nem is beszélve... Ezer karakterben mit lehet leírni? Vagy több kell oda, vagy kevesebb... De ezer karakter? Olyan, mint egy tizenhét másodperces trailer... Nem tudod, hogy mit tegyél bele...

     Na ott tartottunk, hogy megvan az X és Y koordináta. Megadunk egy semleges tartományt (a közepét a kinyerhető pixelértékeknek, vagyis fel-le irányban 65-75, jobbra-balra irányban 40-50 között). Ha a tárgyunk középpontja ezen a tartományon belül van, akkor nem mozgatjuk a egyik szervót sem. Ha X<40 && Y<65, akkor a kamera (hátulnézetből) jobbra és felfele fog mozogni. A többit meg ki lehet innen következtetni.

     Fejlesztési lehetőség: felhasználni a konkrét középpont értékeket, hogy tudjuk, meddig kell elmozdítani a kamerát, s nem csak arrafele húzni, hogy "majdcsak odaér valamikor"... Ez a legrövidebb idő tipusú vezérlés. Kisebb helyen vizsgálni a pixelértékeket (mert ha egyszer megtaláltuk a kép jobb felső sarkában, akkor valószínűsíthető, hogy a következő képen is valahol a környéken lesz... Ergo a középpont plussz minusz 40 pixel tartományban vizsgálni a pixelértékeket). Legrövidebb idő, legkevesebb energiafelhasználás. Mozgás érzékelés bevitele... Ezt bonyolult elmagyarázni... Egyszer körbenéz, választ refernciapontokat, s azokhoz viszonyítva megállapítja, hogy a képen hol van mozgás és csak ott vizsgálja az illető pixel értékeket. Utolsó ötlet: felhasználni a leftmost-rightmost pixelértékeket, illetve a talált pixelek mennyiségét és ez alapján meghatározni, hogy milyen messze van az illető tárgy a kamerától. S ha ez megvan, akkor a pók testét is mozgatni ennek függvényében előre vagy hátra. ha kevés pixel van, akkor előre, ha sok pixel van, akkor hátra.

     S ha minden jól megy, ez utóbbit meg is valósítom nemsokára... Csak legyenek meg az alumínium lábak...



     Új téma: arcfelismerés. Szó volt róla korábban, hogy a tanítóhalmaz felépítéséhez 18*18 méretű képet használtam. A matlabban is erre a méretre volt megírva minden, illetve az FPGA programjában is erre volt optimalizálva minden egyes kód és minden egyes tulajdonság. S nemrég elértem az FPGA-s projekttel is oda, hogy nagyobb méretre is végigpásztázzam a képet arcok után. Ekkor derült ki, hogy az általam használt méretek nem egyeznek meg a matlabban használt méretekkel (ha nem 18*18-as csúszóablakot használok). Most azon töröm a fejem, hogy mi lesz a megoldás. Van egy "négermunkás" megoldós, ahol minden egyes tuladonságot újra át kell írni matlabból ANSI C-re, és be kell illesszteni egy plusz for ciklust, ami végigmegy, s mindenhonnan kivon egyet, ahol nem zéró van eredetileg. Vagy deklarálok mégegy tömböt, egy maszkot, amivel maszkolom a kapott értékeket. Vagy kitalálok valami újat (ami eddig még nem jutott eszembe), ahogy meg lehet oldani ezt a feladatot. Mindenképp hétvégén ezen is fogok dolgozni...



     Még valamit akartam írni, de már nem jut eszembe...

Nééémáááá ... Mozog a feje...

     Na megint... Új videó. Kommentár nem sok kell hozzá. Amikor a kamera mögötti led pirosan világít, olyankor látja a színt, amikor meg zöld, olyankor nem látja a színt. Az egyetlen baj a rózsaszín-piros kombinációval van. Időnként "elmélázik" az abroszon... Vagy a fotel terítőn... vagy valamin, amit én nem látok... De nem is ez a fontos. Hanem, hogy mozgatja a fejét :D Kicsit olyan, mintha már lenne benne valami...




     És mégegy videó... Ebbe van amit még én sem értek... De nagyon ott van...

Integrálkép megint

     Korábban szó volt arról, hogy mire jó az integrálkép, meg arról is, hogy hogy működik. Végre sikerült elérni azt, hogy az FPGA ügyesen kiszámolja a kamerától érkező képre az integrálképet (azt nem is mondom, hogy hipergyorsan... gyorsabban számolja ki az integrálképet, mint ahogy a soros port 115200-on gyúrni tudja az adatokat...)

     Aztán jött a tesztelés... Aztán kiderült, hogy rossz az indexelés. Aztán javítás -> tesztelés -> afrancessenbele -> hibakeresés -> hibajavítás -> tesztelés -> meginnemműködik -> ménemmenteminkábbsörözni -> hibakeresés -> hibajavítás -> tesztelés -> ezaaaaazzz... hoppááá nem ez az... -> vajonmeginnmilyenbajavan -> esszevágom -> csakmostneaddfel ->várjávárjá ->  assszemmegvan -> akishuncut -> hamossemegy átigazolok kommunikációra -> de miééééééért -> na jo... megírom elölről -> de várjálcsak... ott asszem van valami -> aztán megint hibajavítás és tesztelés.

     Eredmény :


     A képre kattintva megjelenik "élvezhető" méretben is. A lényeg, hogy a matintimg állományt matlabban töltöttem fel a matintimg=cumsum(cumsum(double(img)),2); függvény segítségével, az intimg értékét pedig az FPGA számolta ki. S talál... Mekkora buli lessz itt ma este... (ha befejezem a programot... :D )

     Aki nem érti, hogy miről van szó, az ne keseredjen el... Pár hónap kutakodás a témában és összeáll a kép...

(egy nappal később : ) Na ma is keresztülmentem egy komoly lelki vívódáson, hogy hagyjam az egészet a francba, s tegyem fel a JPEG kamerát, s csináljam meg az arcfelismerést laptopon... Mennyivel könnyebb lenne úgy az élet... De nem tettem... S elég jót haladtam a programmal. 18*18 méretben ügyesen kiszámolja az értékeket. Ez látható a következő képen:


Még kipróbálgatom nagyobb méretben is, hátha ott sem lesz nagy különbség.


Lépések

     Időm nincs irni, viszont van egy új videóm. Amit figyelni érdemes rajta az az első lábak megrogyása a szekvencia közepén. Sajnos a dibond nem bírja a terhelést. Remélhetőleg nemsokára elkészülnek az aluminium lábak is s azzal már nem lesz ilyen gond.




     Illetve van egy másik videóm is. Valami random szekvencia... Még csinálok ilyeneket, mert gyorsan mennek :P



Update:
Aztán nekifogtam programozni, csináljak valami értelmeset is. Persze közben zene, meg youtube a háttérben. Barangolás közben találtam egy hasonlóan "érdekes" projektet, mint az enyém... Őszintén szólva egy kicsit vigasztaló látvány volt (a vicces mellett), hogy más is küszködik hasonló problémákkal, mint én (vagyis, hogy nem elég erős a láb)...

Video:


És mégegy videó... Fekvőtámasz... Eric Prydz : Call on Me... Kicsit másképp, kicsit több lábbal :P

OpenCV

     Igaz, nem ide tartozik, de mégis ide írom. A tavalyi TDK projektemről van szó. Az a világítós kesztyüs izé, amiben úgy néztem ki pont, mint E.T. mikor barátkozik. Arra gondoltam, viszem azt is a temesvári TDK-ra. Ha egyébnek nem, poénnak jó lesz. Hátha valakinek megtetszik, s csinál valami értelmeset belőle. Mert az igazság az, hogy a TDK után úgy beraktam a fiókba, hogy most vettem ki azóta először. 11 hónap után. Pedig mennyit szórakoztam vele annó... S milyen jó volt...

Fontos >>> Minden videót FULL SCREEN-ben kell nézni és 720 pixellel. Különben szinte semmi nem látszik belőle.

Néhány videó, hogy miről is szólt az a valamikori dolgozat:

1. Bemelegítés, színek kiválasztása a webkamera képéből, majd egy kis bohóckodás.



2.Labdás játék. Lényege, hogy minél tovább tartsuk a labdát a képernyő közepén.



3. Virtuális billentyűzet. Vagy hogy Szabit idézzem: kaputelefon. A videóban csak annyi van belőle, hogy a (...) kiad egy új számot, amit a bal alsó sarokban ír ki. Ha helyesen ütöttük be az illető számot, akkor kigyúl a bal oldali zöld lámpa. Ha nem helyesen ütöttük be, akkor a jobboldali piros lámpa fog égni.



4. A két kéz közötti elfordulás és távolság mérése. Ezt felhasználtam a következő projektben.



5. Egér mozgatása illetve kattintás esemény generálása. Azt be kell vallani, hogy a kattintás még nem tökéletes... Kicsit rá kellene hangolni... De mostmár minek?



6. A NAGY projekt. Lehet benne a filmlejátszóból (ami szintén saját gyártmány, specifikusan erre a projektre készült) képeket kivenni és azokat forgatni, nagyítani. A video közben elég sokat bénázok... Amikor nem látszik a kezem a képernyőn, olyankor az egeret babrálom. Nem jutott eszembe (csak a video végén), hogy van egy hiba a projektben, amelyik nem engedi, hogy a legutolsónak levett képeket forgassam. Mindeniket lehet, csak azt nem... De na ... A lényeg így is ott van...



S hogy honnan indult ez az egész? Megtetszett a Minority Reportban a srácnak a felszerelése. Persze ő csak szinészkedik... Az enyém igazibb :P



S milyen volt végigcsinálni a projektet? Fárasztó és szórakoztató. Rengeteget tanultam belőle (például, hogy nem tudok olyan jól improvizálni, ahogy szeretnék, valamint azt is, hogy az előadandó anyagot érdemes egyszer átismételni... vagy legalább végiggondolni...)









Itt épp azt néztük, mennyire sztájlos a kompozíció... :P

És itt a vége :













Eredmény: Második helyezés és egy Losonczi különdíj.

Megérte: Mindenképp. Ha tehetném, mégegyszer végigcsinálnám... Ugyanígy...

Femur

     Ma megsétáltattuk a pókot a város között egyet. Voltunk kint Szentgyörgyön vele. Egy kapusbácsi rá is kérdezett: Mi az fiuk? Varrógép? Aztán a Borsos Tamás utcában egy fiatal pár is megbámulta... Jó érzés volt...

     Megint sötétedésig dolgoztunk Szabival... Réka meg közben ügyesen írta az államvizsgáját. Felszereltük a PMod-okat (már amelyik megvan...) aztán ügyesen bekötöttük a szervókat és teszteltünk. Tesztelés során kiderült, hogy a képen látható alkatrész nem bírja a nyíró terhelést. Amikor a pók lerakta a lábait,a lábak nem voltak tökéletesen merőlegesek a talajra, emiatt erre az alkatrészre egy elég komoly csavaró erő hatott. Ez a csavaró erő megpróbálta a(z amugy sem tökéletes merőleges) síkból kifordítani. Ennek az erőnek nem tudott ellenállni.



Megoldás? Aluminium. Beszéltem Vitális úrral, aki beleegyezett, hogy az említett alkatrészt kis változtatással elkészítsük alumíniumból. A kis változtatás az abban áll, hogy az esztétika felől elmegyünk a funkcionalitás fele. Eredmény :


Letisztult forma. Semmi cicoma rajta. Pont amire kell. Holnap megérkezik az utolsó PMod is, azután meg programozás és tesztelés... Mint mindíg.

Tesztelés

     Még mindíg csak tesztelünk... Hétvégére megérkezik a tartalék szervó és a hiányzó PMod Con3-as. Akkor majd összekábelezem az egészet. Addig még pár videó:



Kicsit részletesebben

     Nem mondom azt, hogy végre van annyi időm, hogy... Mert nincs. Szabival egész délután azon ügyködtünk, hogy valahogy összerakjuk. A kezdeti nehézségeket leküzdve már egész jól lehetett haladni... Bármennyire is kételkedtem benne, hogy ma össze lesz rakva, mégis elkészült. Már csak egy dolog hiányzik belőle: rugós alátét.

     De hogy is kezdődött az egész? Többszöri megkeresésem után a 2Actives tulajdonosa Vitális István megigérte, hogy elkészíti a darabokat, s az árban majd később megegyezünk. Aztán telt-múlt az idő és eljutottunk hétfőn oda, hogy foghatunk neki legyártani az alkatrészeket. Kedden elkészültek a pályatervek (CNC maró pályájának a tervei), majd valamikor este hét óra körül felhívott, hogy mehetek az első darabok után. Ekkor készültek a következő képek:


Created with Admarket's flickrSLiDR.

     Ezek a képek már tegnap este megjelentek a blogon. Akkor felelőtlenül azt mondtam, hogy este még írok. Sajnos elég későn fejeztem be mindent, s inkább az alvást választottam, arra gondolva, hogy holnap is nap van, s megírom akkor. Ma voltam 8-10 között az egyetemen, kértem egy böhöm nagy Matrix nevű tápot, legyen mivel meghajtani a 20 szervót (bár igazság szerint már csak 19, mert egy nem bírta a folyamatos terhelést, és rövid szenvedés után kilehelte a füstöt magából). Miután végeztem az egyetem, csatlakozott hozzám Szabi, hogy rakjuk össze az alkatrészeket, nézzük meg, mennyire passzolnak.

     Közel hat óra munka után össze is állt, valószínűsíthetően egy elég végleges forma. Az összeszerelés alatt rájöttem pár dologra:
1. Jó, ha van mellettem valaki, aki kicsit másként nézi a dolgokat. A pók alján akadt az összes csavar (erről is van kép). Én bepánikoltam, s egyszerüen leblokkolt az agyam. Semmi értelmes megoldás nélkül. Azon gondolkodtam, hogy vajon miért nem adott az Inventor hibát... Aztán a "másik nézőpont" hozta a megoldást. Szabi javaslatára tettünk sok sok alátétet, s egy nagyobb csavart, s probléma letudva. 

2. Sting: Desert Rose, Shape of my heart, Englishman in NewYork számait nem lehet megunni...
    3. Ha téves feltevésből kiindulva vonunk le következtetéseket, akkor valószínűsíthető, hogy a következtetések is tévesek lesznek. Vagyis a tervezés során én arra alapoztam, hogy a szervó fejének méretei pontosak. Sajnos nem voltak azok. Nem voltam elég figyelmes, nem voltam elég felkészült s emiatt minden egyes lyuk egy negyed milliméterrel arrébb került, mint ahova kellett volna. Még jó, hogy dibond/alubond az alapanyag

    4. Az anyaggal kapcsolatos első aggodalmam elég gyorsan elszállt. Az elején az volt az érzésem, hogy nem fogja bírni a strapát. Ma majdnem egész nap rángattuk jobbra-balra, húztuk, csavaroztuk, aztán mégjobban húztuk, hogy mindenhová elérjen, s mindenhol találjon, s meg sem kottyant neki...

    5. Bármennyre is nem akarom beismerni, lehet, hogy Brassai tanárúrnak igaza volt. Jó lenne a lábakat minden oldalról befogatni. Nem kell sok módosítás hozzá, talán a 2.0 verzióba azok is belekerülnek.

    6. Mindíg jó egy segítő kéz. Sokszor egyedül annyit tud az ember tökölni...
           És most jöjjenek a képek:


      Created with Admarket's flickrSLiDR.

           S mit nem szabad elfelejteni? Anyukám azt mondta, hogy ha valamit adnak, azt meg kell köszönni. Most nem csak ezért szeretnék itt is köszönetet mondani Vitális Istvánnak, hanem azért is, mert volt olyan rendes és eltűrte azt, hogy folyton a nyakára jártam, s folyton azzal idegesítettem, hogy mikor lesz kész. Tudom, hogy a "nagyok" mindig elfoglaltak. Mindíg van valami fontos, amit épp akkor kell elintézni, vagy valaki, akit épp akkor kell felhívni. Mindezek és a két céggel járó problémák ellenére azt kell mondjam, nagyon türelmes volt velem szemben. És az, hogy csak miattam maradt bent munkaidő után, az még külön megérne egy misét...

           S ha valaki egy "Év focistája" kupával szeretné meglepni sajátmagát, vagy kellene pár ejtőernyős érem, amivel lehet feszedezni a csajok előtt, vagy vizilabdázós olimpiai arany, vagy balkán bajnok KickBox-os trófea, az nyugodtan fordulhat a 2Actives-hez.

           Persze ezen kívül még sok érdekessel foglalkozik a cég. Nekik van a környék egyetlen plazma vágója (de az nem fehér embernek való áron dolgozik). Ezen kívül csinálnak sok reklámot, meg plexiből gumikacsát, meg amit csak el lehet képzelni. Ez volt a reklám helye. :P

            http://www.2actives.ro/    

            http://www.cupe.ro/    

      A kupás oldalon lehet autómatricát kapni (Need For Speed -> Car Vinyl... )

      Ennyi volt a reklám mára. Jöjjön két videó, hogyan is nézett ki az összeszerelés...








           Ennyi mára. Fogok neki programozni.

      Elkészültek az alkatrészek...

           Tegnap este fél tíz körül fejeztük be...Majd este írok részletesebben is...


      Created with Admarket's flickrSLiDR.

           Egy videó a marásról :

      Szervók lelkivilága

           Ebben a bejegyzésben nem fogok sokat írni. Összekötöttem az inverz kinematikás programomat az FPGA-val, soros kábelen keresztül, hogy valós idejű kommunikációt tudjak kialakítani. A sorosan felküldött adatokat az FPGA leküldi a szervóknak, azok meg végzik a dolgukat, vagyis forognak jobbra, balra.

      C# királyságok

           Mai bejegyzésben bemutatásra kerül az előre legyártott szekvencia feltöltő program, illetve annak Microblaze-beli értelmezője. A feltöltő program, mint ahogy az a bejegyzés címéből is kiderül, C#-ban készült el. Azt kell mondjam, hogy a C# a tökéletes franciakulcs számomra. Könnyű használni, jól lehet benne felhasználói felületet tervezni, könnyű debugolni, könnyű visszafejteni.

           A program alapját a kedvenc soros portos kommunikációs terminálom illetve annak forráskódja adta, amelyik elerheto itt. Lényege, hogy az inverz kinematika számoló programban kigenerált értékeket fel tudjam tölteni a MicronRam-ba mindenféle fennakadás nélkül. Ezekre az értékekre azért van szükség, mert egyelőre nehéz lenne valós időben kiszámolni a szervók megfelelő pozícióit illetve értékeit.

            A program a következőképpen néz ki :


           Három fontos egysége van: bemeneti, beállítás és kimeneti. A bemeneti részben tudjuk megadni, hogy melyik állományt szeretnénk feltölteni. A beállítások résznél tudjuk kiválasztani a rendelkezésre álló soros portok közül, hogy melyiken keresztül szeretnénk kommunikálni, illetve, hogy melyik "particiót" szeretnénk felülírni. Kimeneti egységek a hiba ablak, az előnézet ablak, illetve az érkezett üzenetek ablak. A hiba ablakba kerül minden, amit a try-catch blokk kidob magából, illetve ide kerülnek a "nem megfelelően formázott " tipusú szövegek is. Az előnézet ablakban láthatjuk a kódot, amit feltöltünk az FPGA-ra. Ugyanitt módosításokat is eszközölhetünk, mivel módosítás esetén az itt megjelenített kód lesz feltöltve, s nem az, ami a szöveges állományban van. Az érkezett üzenetek ablakban jelennek meg az FPGA által küldött üzenetek. Itt kisérhetjük figyelemmel, hogy a küldés sikeres volt, vagy sem.

      Fontosabb forráskód részletek :

              private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
              {
                  // If the com port has been closed, do nothing
                  if (!port.IsOpen) return;
      
                  // Read all the data waiting in the buffer
                  string data = port.ReadExisting();
                  AppendTextBox(data + "\r\n");
                  //Console.WriteLine(port.ReadExisting());
              }
      
              public void AppendTextBox(string value)
              {
                  if (InvokeRequired)
                  {
                      this.Invoke(new Action<string>(AppendTextBox), new object[] { value });
                      return;
                  }
                  tbReceived.Text += value;
                  tbReceived.SelectionStart = tbReceived.Text.Length;
                  tbReceived.ScrollToCaret();
                  tbReceived.Refresh();
              }
      

           A port_DataReceived függvény a soros porton érkező adatokat kezelő szál. Minden egyes alkalommal, mikor valami adat kerül arra a vonalra, meghívódik ez a függvénye (viszont ez nem egy sima függvény, hanem egy szál). Az AppendTextBox függvény segítségével tud a szál a szövegdobozba írni (ilyen izémizé hozzáférési problémák vannak, ha kivülről próbálunk módosítani valamit, amit belülről is lehet... ilyenkor a c# arra ügyel, hogy nehogy egyszerre több helyről módosítsuk... egész királyul meg van oldva...).

      
              private void Form1_Load(object sender, EventArgs e)
              {
                  foreach (string s in SerialPort.GetPortNames()) cbComPort.Items.Add(s);
                  for (int i = 1; i < 20;i++ ) cbPartition.Items.Add(i);
                  cbComPort.SelectedIndex = 0;
                  cbPartition.SelectedIndex = 0;
              }
      

           Itt mondjuk meg, hogy mit csináljon a program, amikor elindul. Ebben a részben lekérdezzük a rendelkezésre álló soros portokat, valamint feltöltjük a particiokat tartalmazó kombóboxokat a megfelelő értékekkel.

      
              private void bSend_Click(object sender, EventArgs e)
              {
                  //Start the communication
                  port.Write(new byte[] {0xFF }, 0, 1);
                  // Select the partition
                  int part = int.Parse(cbPartition.Text);
                  port.Write(new byte[] { Convert.ToByte(part) }, 0, 1);
      
                  for (int ize = 0; ize < 100000000; ize++) ;
                  // send the number of lines.
                  port.Write(tbLineNum.Text.ToString());
                      port.Write(new byte[] { 0x0D }, 0, 1); //Carriage return. 
                  input = tbPreview.Text;
                  
                      string[] fields = input.Split(new char[] { ' ' });
      
                      progressBar1.Maximum = fields.Length;
      
                      for (int i = 0; i < fields.Length; i++)
                      {
                          try
                          {
                              int szam = int.Parse(fields[i]);
                              Console.WriteLine("Szam : " + szam);
                              port.Write(new byte[] { Convert.ToByte(szam) }, 0, 1);
                          }
                          catch
                          {
                              Console.WriteLine("Nem szam." + fields[i] + "\n");
                          }
                          progressBar1.Value = i;
                      }
                      progressBar1.Value = 0;
              }
      

           Ez történik, amikor megnyomjuk a küldés gombot. A program tudja, milyen lépéseket kell végigjárjon, hogy ne legyen fennakadás a kommunikációban. Ezeket a lépéseket előre le kell szögezni, hogy mindkét fél ismerje. Nagyjából úgy kell elképzelni, mint a TCP protokollt. Startbit, particio választás, csomag hossza, csomag. Csomagvég karakter nincs. Csomag vége utan rögtön következik a másik csomag.

          A programban még lesznek kisebb nagyobb (főként esztétikai jellegű) változtatások, viszont a motor ugyanez marad. Ideálisan alkalmazható az IK-SE programmal, ami az Inverz Kinematika V2.0 részben került bemutatásra.

      A programból érkező információt értelmező és feldolgozó MicroBlaze programrészlet a következőképpen néz ki:

      //====================================================
      // PREMADE SEQUENCE -> INTERRUPT HANDLER FUNCTION
      //====================================================
      //How to use it?
      //
      //        I. Send 255 to start the communication.
      //        II. Send the number of the Sequence, which you want to erase.
      //    III. Send the number of the parts of sequence numbers
      //         (if you have 49500 sequence, you send 2.)
      //    IV. Send the numbers, which multiplied gives the number of sequences
      //          (if you have 49500 sequence, you send (250 and 198) or (220 and 225)
      //                      or something similar.)
      //    V. Send the sequence values. (expl: 49500 number between 0 and 255)
      //    END.
      //Set a flag to fill the numbers from 49500 to the 0x0C7000 with 128 <- Not yet implemented
      //It would be good, to fill the memory segments with 101888 value =>0xC7000 memory address
      //implemented on user program side. TO send 101888 value. Approx. 18 minutes 
      
      void uart_interrupt_handler(void* addr_p)
      { 
      //receiving premade sequences from the computer and store them in the MicronRam Memory.
      Xuint8 empty;
      empty = XUartLite_IsReceiveEmpty(XPAR_RS232_PORT_BASEADDR);
                  if (empty == FALSE )
                  {
                      buchstabe2 = XUartLite_RecvByte(XPAR_RS232_PORT_BASEADDR);
                      //xil_printf("Buchstabe : %d pre_seq_stage = %d\n",buchstabe2,pre_seq_stage);
                      if((buchstabe2==255)&&(pre_seq_stage==0))    
                      {
                      pre_seq_stage=10;//START.
                      //xil_printf("Start receiving PWM. Send the Sequence number.\n");
                      }
                      
                      if(pre_seq_stage == 1)//Which MemorySEQ?
                      {
                          if((buchstabe2<=19)&&(buchstabe2>0))//Limits
                          {
                              //xil_printf("Selected Sequence : %d\n",buchstabe2);
                              premade_sequence = (Xuint8*)XPAR_MICRON_RAM_MEM0_BASEADDR + (2+buchstabe2)*0xC7000;
                              pre_seq_stage = 20;
                              //xil_printf("Send the number of lines.\n");
                          }
                          //else xil_printf("Please select a Sequence memory between 1 and 19 (inclusive).\n");//error message.
                      }
                      if (pre_seq_stage == 2)//how many numbers in the number of sequences
                      {
                          //xil_printf("First Number = %c \n",buchstabe2);
                          num_num = buchstabe2;
                          if (buchstabe2 == 13)
                          {
                              pre_seq_stage =30;
                              c3=c3*18;
                              c3=c3/10;            
                              
                              ////xil_printf("Vegleges szam ertek : %d\n",c3);
                              //xil_printf("Kuldjed a PWM ertekeket.\n");
                          }
                          else if ((buchstabe2>=48)&&(buchstabe2<=57))
                          {
                              c3=c3+(buchstabe2-48);
                              c3=c3*10;
                              //xil_printf("Szam erteke : %d\n",c3);
                          }
                      }
      
                      if(pre_seq_stage == 3)//reading the sequence values.
                      {
                          premade_sequence[counter] = buchstabe2;
                          //xil_printf("Received value : %d\n",buchstabe2);
                          //xil_printf("Saved value : %d\n",premade_sequence[counter]);
                          //xil_printf("Counter : %d C3 : %d\n",counter,c3);
                          counter = counter+1;
                          if(counter == c3)
                          {
                              c3=0;
                              pre_seq_stage = 0;
                              xil_printf("Vege a dalnak.\n");
                          }
                      }
                  if (pre_seq_stage==10) pre_seq_stage = 1;
                  if (pre_seq_stage==20) pre_seq_stage = 2;
                  if (pre_seq_stage==30) pre_seq_stage = 3;
                  }
      } 
      

            Röviden ennyi lenne a mai bejegyzés. Remélem este írhatok valami jobbat is, mint pár forráskód.

      Húsz sávos PWM vezérlő

           Tegnap este elkészült. Húsz szervó motrot egymástól függetlenül tud vezérelni. Sajnos eddig csak 16 szervón sikerült kipróbálni, de szerintem a maradék néggyel sem lesz semmi fennakadás.

      Forráskód ha kell valakinek, csak csipogni kell érte (Microblaze CustomIP-nek specializálva).

      A segítségért és a jótanácsokért köszönet Szász Szabolcsnak.

      Arcfelismerés pedás szemmel ;)

            A következő leírásban megpróbálom egy kicsit más megvilágításba helyezni az arcfelismerést. Megpróbálom úgy leírni, hogy nem csak Timi a pedáról, hanem a kapusbácsi is értse meg.

            Az agyunknak közel egy fél tizedmásodpercbe telik eldönteni egy látott képről, hogy arc, vagy nem arc. De hogyan is működik az agyunk? Na ez az, amit nagyon nehéz megérteni. Viszont vannak tézisek és vannak elméletek, hogy hogyan is működhet ez az egész. Vegyünk először egy neuront, és vizsgáljuk meg a benne lezajló folyamatokat.

           Neuron sokféle lehet, annak függvényében, hogy a testen belül hol helyezkedik el. Viszont van egy pár általános tulajdonságuk, mely mindenikre jellemző : mindenik idegsejt rendelkezik bemenettel, kimenettel, illetve az információ processzálására és továbbítására szolgáló résszel. Ezt úgy képzelhetjük el, hogy jön az inger (egy elektromos jel ) a dendriten keresztül, majd beérve a sejttestbe kisebb változáson megy keresztül (kicsit hozzáadnak, kicsit elvesznek belőle) és továbbítódik az axonon keresztül a neuron kimenetére, ami magyarul végfácska, latinul telodendrion. Az, hogy mi történik azzal az elektromos inpulzussal a neuronon belül, határozza meg az általa kiváltott érzést, vagy eszünkbe juttatott emléket. Sajnos a biológiai folyamat hátteréről sokkal többet nem is tudok mondani.

            Most jön a technikai háttér. Nagyon messzire nem is nyúlnék vissza a történelemben (annak ellenére, hogy a mesterséges neuron koncepciója már a 60as évek elején létezett). Lotfi A. Zadek-nek a nevét emelném ki a történelemből, aki megadta a megfelelő lökést a Soft Computing-nak. A soft computing az egy olyan elgondolás, hogy csak na... Arról szól, hogy a mi kis bináris világunkba vezessünk be átmeneteket.

            Itt egy kis kitérő. Mi is az a bináris világ? Amikor valaki vagy jó, vagy rossz. Vagy szép vagy csúnya. Vagy okos, vagy buta. Nincsenek átmenetek. Csak fekete van és csak fehér. Csak igazság és hazugság. Ezzel a koncepcióval szállt szembe a fent említett uriember. Ő azt mondta, hogy mi lenne, ha bevezetnénk a számítástechnikába egy átmenetet. Mi lenne, ha lenne szürke szinünk is, a sok fekete és fehér között... Mi lenne, ha lennének részigazságok is? Mi lenne, ha meg lehetne mondani, hogy mennyire igaz, vagy mennyire szép vagy mennyire fekete valami. Vagy mennyire magas, vagy mennyire gyors, mennyire meleg, mennyire koszos.

            És ez az elgondolás nagyon gyorsan teret hódított magának. Kiderült, hogy ennek segítségével nagyon sok olyan problémát lehet megoldani, amit a bináris logikánkkal nem lehetne. Aztán a téma több részre szakadt. Megjelentek a mesterséges ideghálózatok, a Fuzzy rendszerek és a Fuzzy logika, a valószínűségi kereső rendszerek és a genetikus algoritmusok. Mindenikről sokat sokat lehetne írni, mert mindenik nagyon érdekes téma.

            Mai írásom csak egyet emelne ki ezek közűl, mégpedig a mesterséges ideghálózatot. Korábban felvázoltam az idegsejtről kialakított képemet. Erre a képre alapoztak a tudósok-kutatók is, amikor arra gondoltak, készítenek egy olyan gépet, amelyik képes tanulni. Technikai szempontból a tanulás fogalma előző ismeretek dinamikus felhasználását is jelenti. Ennek segítségével felhatalmazták a gépet olyan döntések meghozatalának képességével, amelyekkel kapcsolatos kérdésről nem rendelkezett elegendő, vagy semmilyen információval.

            Ezt emberi nyelven úgy kell elképzelni, mint egy három éves gyereket. Lát egy virágot, megkérdezi mi az. Azt mondod neki, hogy virág. Lát egy másik virágot, megkérdezi mi az. Azt mondod neki, hogy az is virág. Megismétlődik ez még vagy húszszor és a gyerek levonja magának a következtetést, hogy hogyan is nézhet ki egy virág általánosan. A gyerek még nem tudja meghatározni, hogy miért virág egy virág, vagy hogy mitől lessz az. Ő csak azt tudja, hogy az egy virág.

            S hogyan is működik ez? Megpróbál a lehető legtöbb közös tulajdonságot összegyüjteni a virágokról. Olyan közös tulajdonságot, amelyik mindenik virágban szerepel, vagy valamilyen módon összeköthető az azelőtt látott virágokkal. Ezen kívül megpróbál minél több olyan tulajdonságot összeszedni, ami megkülönbözteti a többi addig látott dologtól (pl kövektől, fáktól, állatoktól).

           Játsszunk el a gondolattal. Mitől virág egy virág? Hogy magyaráznám el ET-nek, hogy hogyan is néz ki egy virág? Legelőszöris a virág szines. Az alja általában zöld, a teteje meg szines (lila, piros, fehér, rózsaszín, akármilyen). Van neki illata, általában édeskés, de nem mindíg. Elég kicsi, többnyire öt és harminc centi között van. Tappintásra a szára keményebb, a szirmai puhábbak. Általában nem szúr, persze vannak kivételek, mint a rózsa. A méhek szeretik körberöpködni őket. Saját akaratából nem mozog, és nem is támad.

            Ha újraolvassuk az ezelőtti bekezdést, meglátjuk, mennyire nem lehet binárisan leírni a virágokat. Viszont meg lehet mondani, hogy melyik tulajdonság mennyire fontos. Azt mondhatnánk, hogy a legfontosabb tulajdonság az alul zöld, felül szines kombináció. Azután jön a méret, majd az illat. S ha ET eljön a földre, felvértezve ezzel a tudással, akkor el tudja dönteni, hogy az, amit lát mennyire virág.

            Tisztában vagyok azzal, hogy a "mennyire virág" kifelyezés eléggé szokatlan. Viszont ezt így mondják. A szakzsargon hovatartozási függvénnyel írja le azt, amit én "mennyire virág"-nak nevezek. Vegyünk egy példát.


           Legelső tulajdonság: alul zöld, felül szines (vagyis nem zöld)-> megvan(0.9) . Illat? -> megvan(0.75)(persze itt a megvan, az egy zéró és egy közötti számot jelent, annak függvényében, hogy mennyire teljesíti az adott feltételt). Méret? megvan (0.95). Alul keményebb tappintásra mint felül? Megvan (0.9). Ide most meghatározhatnánk egyes sulyzókat, meg küszöbértéket, hogy melyik tulajdonság mennyire fontos, viszont ettől eltekintünk. Maradjunk annyiban, hogy egy ilyen véges specifikációval meg tudja különböztetni a virágokat a kutyától, vagy a fáktól.

           Viszont itt is lehet fals pozitív találat, ami azt jelenti, hogy valamit, ami nem virág, mégis virágnak kategorizálunk, mert az elvárásoknak megfelel. Lássunk egy példát:



           Alul zöld, felül szines? Megvan (0.9). Illat? Húúúú, az is megvan (bár nem olyan kellemes, ezért csak 0.5 jár érte). Méret ? Kicsivel 30 centi fölött? Az még belefér. Legyen 0.7. Alul keményebb, mint felül? Hmmm... Fogjuk rá... Attól függ, hol nézzük. Legyen 0.4. S ha megfelelően vannak beállítva a súlyzóim, akkor igen, ez egy virág.

            De ne térjünk el nagyon a mi problémánktól. Neuronháló. A lényege, hogy bizonyos dolgokat meg tud tanulni, ha fogjuk a kezét és megmondjuk, hogy a bemeneti információk közül melyik minek felel meg. Hihetetlenül sok dologra meg lehet tanítani. A kedvencem a robot, amelyik meg tudja fordítani a levegőben a palacsintát. Viszont meg lehet tanítani arcot felismerni, hangot felismerni, autót felismerni, közlekedési táblákat felismerni, kézírást kiolvasni, képes megtanulni a vásárlási szokásainkat, a vezetési szokásainkat és még sok egyebet. Képes magától megtanulni járni, (már ha egy robotról van szó), képes megtanulni a szervezetben lévő rákos sejteket osztályozni. A felhasználásának csak a képzeletünk szabhat határt.

            Én a neuronhálót megtanítottam arcot felismerni. S hogyan is nézett ez ki? Legelőször meg kell határozni a tulajdonságokat. Mitől arc egy arc? Számunkra attól, hogy van szeme, füle, szája, ott van valakinek a nyakán, van rajta haj, mozog jobbra-balra, mittudomén. Sok dolgot fel lehetne sorolni. Viszont ezek többsége olyan tulajdonság, amit nem lehet egyszerűen definiálni a számítógép számára. hogy mondanád meg a számítógépnek, hogy az az arc, amin van a szem, a fül, a száj stb? A számítógép sajnos még azokat sem tudja. Ezért veszünk olyan tulajdonságokat, amiket a számítógép is tud értelmezni.

           Első példánk a függőleges szimmetria. Az tudjuk, hogy az arcok nagy többsége (az anyajegyeket leszámítva) elég szimmetrikus. Ezzel elég könnyű dolgunk lesz. Fogjunk egy képet.


            Alakítsuk át szürke színtartományba, hogy ne kelljen a három színkomponenssel bajlódni (ez nem olyan fontos, csak minek gyűjteni a bajunkat, ha meg lehet oldani kicsit egyszerűbben is):


      Vágjuk standard méretre az arcot (majd mindeniket ugyanekkora méretre kell vágni):



            Definiáljuk a tulajdonságot kicsit számítógépesebben : Adott a kép(az arc). Tegyünk rá egy másik képet(azt amelyik itt lent van), ahol csak fehér és fekete pixelek vannak, majd számoljuk ki a fehér pixelek alatt lévő pixelek értékeit, és vonjuk ki belőle a fekete pixelek alatt lévő pixelek értékeit. Vagyis kiszámolom az arcnak a közepétől balra lévő összes pixel értékét (az tudjuk, hogy a fekete szín, az nulla, a fehér az 255, a többi meg e két érték között van. Így ábrázolja a számítógép a képet.) majd kivonom belőle a középvonaltól jobbra helyezkedő pixelek értékeit.


           Normalizáljuk az eredményet (ami azt jelenti, hogy minusz egy és egy közé szorítsuk be a lehetséges értékeket). (erre most nem térek ki, mert nem ez a legfontosabb).

           Ha mindezekkel megvagyunk, kaptunk egy számot. Egyetlen egy számot. Ez a szám jelzi, hogy mennyire szimetrikus az adott arc. Ugyanígy ki kell még számítani sok más tulajdonságot is, mint például a függőleges szimmetria, a két széle mennyivel sötétebb, mint a közepe, meg sok sok olyan, aminek még neve sincs. Mindeniknél az a lényeg, hogy a fehér rész által takart területen lévő pixelek értékéből kivonjuk a fekete rész által takart pixelek értékeit. Az általam használt "tulajdonságok" a következők :



           Mint már mondtam, legtöbbnek még csak neve sincs. Ezeket ki kell számolni sok sok arcra. (Esetemben közel hét és fél ezer arcra ki van számolva). Ugyancsak kiszámoljuk ezeket a tulajdonságokat sok olyan képre is, ami nem arcot tartalmaz. Ebből fog összeállni a tanító halmaz. A tanító halmaz mellé meg kell határozni azt is, hogy melyik eleme melyik kategóriához tartozik (vagyis kell egy másik tömb, amiben leírom, hogy melyik elem arc és melyik nem arc).


           A fenti képen látható az arcok és nem arcok eloszlása a vizszintes és függőleges szimmetria függvényében. Látható, hogy eléggé lefedik egymást (sajnos a piros alatt lévő zöld kis keresztek nem látszanak... De ott vannak).

           Ezt a két halmazt odaadjuk a Matlabnak, ami behangolja az egyes súlyzókat, amikről korábban szó volt. A súlyzók behangolása egy véletlenszerű értékről kezdődik. A matlab minden egyes bemenetre (képre) kiszámol egy lehetséges kimenetet, majd ellenőrzi, hogy az, ami neki kijött megegyezik-e azzal, amit én kategóriának megneveztem. Ha megegyezik, mindenki boldog. Ha nem egyezik meg, akkor hibát számol a jelenlegi súlyzók és a bemeneti értékek alapján, és újrahangolja a súlyzókat. A matlab megtanítja a mesterséges neuronhálónak, hogy melyik tulajdonság mennyire fontos. Amelyik tulajdonságban a legjobban eltérnek egymástól az arcok és nem arcok, az lesz a legfontosabb...

            Miután elkészült a matlab a tanítással (ez általában akkor ér véget, amikor már nem fejlődik tovább a háló felismerő képessége) akkor kapunk pár számot. Megkapjuk, hogy melyik tulajdonság mennyire fontos. Ezek alapján a számok alapján mi is ki tudjuk számolni egy illető képről, hogy arc, vagy nem arc.

      Csak az ínyencek kedvéért berakok egy kódrészletet, ami közel harminc százalékos pontossággal megmondja egy képről, hogy arc van-e rajta, illetve 99 százalékos pontossággal megmondja, hogy háttér van-e rajta. Nálam ez a két kategória volt definiálva.

      %legelso kepre tesztelo program, egy darab 5 bemenetes szurovel.
      function [arc_e,bemenet] = elsoszint(int,meret)
                  ymax=1;
                  ymin=-1;
                  xmin=[-0.0955946180555556;-0.119140625;-0.140046296296296;-0.0516493055555556;-0.17505787037037];
                  xmax=[0.234977816358025;0.183605806327161;0.100670331790123;0.291546103395062;0.120635609567901];
                  L1_w1=[0.36928518715899011;0.36978579938890427;1.1413417537692145;0.76312953988132237;0.34638348293995147];
                  eltolas_1=-0.36018228879138298;
                  sulyzo_2_1=-1.0686433962775299;
                  sulyzo_2_2=1.0686718484930315;   
                  
                  eltolas_2=[-1.0220214422201102;1.0220022513437266];
                  feature=zeros(1,5);
                  arc_e=zeros(2,1);
                  
      %legelso lepes : kiszamoljuk az ot darab bemenetet.
      
      %103 24 101 99 85 bemenetek
      num=1;
      sorszam(num)=7;%103
      sorok(num,1:7,:)=[0.00 0.00 0.40 0.25;
                        0.40 0.00 0.60 0.25;
                        0.60 0.00 1.00 0.25;
                        0.00 0.25 1.00 0.50;
                        0.00 0.50 0.40 1.00;
                        0.40 0.50 0.60 1.00;
                        0.60 0.50 1.00 1.00];
      
      plusz_minusz(num,1:7)=[1;-1;1;-1;1;-1;1];
      num=num+1;
      
      sorszam(num)=4;%24
      sorok(num,1:4,:)=[0.00 0.00 1.00 0.25;
                      0.00 0.25 1.00 0.50;
                      0.00 0.50 1.00 0.75;
                      0.00 0.75 1.00 1.00];
      
      plusz_minusz(num,1:4)=[1;-1;1;-1];
      num=num+1;
      
      sorszam(num)=9;%101
      sorok(num,1:9,:)=[0.00 0.00 0.20 0.25;
                        0.20 0.00 0.80 0.25;
                        0.80 0.00 1.00 0.25;
                        0.00 0.25 0.20 0.75;
                        0.20 0.25 0.80 0.75;
                        0.80 0.25 1.00 0.75;
                        0.00 0.75 0.20 1.00;
                        0.20 0.75 0.80 1.00;
                        0.80 0.75 1.00 1.00];
      
      plusz_minusz(num,1:9)=[-1;1;-1;1;-1;1;-1;1;-1];
      num=num+1;
      
      sorszam(num)=6;%99
      sorok(num,1:6,:)=[0.00 0.00 0.33 0.40;
                        0.33 0.00 1.00 0.40;
                        0.00 0.40 0.33 0.60;
                        0.33 0.40 1.00 0.60;
                        0.00 0.60 0.33 1.00;
                        0.33 0.60 1.00 1.00];
      
      plusz_minusz(num,1:6)=[-1;1;1;-1;-1;1];
      num=num+1;
      
      sorszam(num)=6;%85
      sorok(num,1:6,:)=[0.00 0.00 0.20 0.33;
                        0.20 0.00 0.80 0.33;
                        0.80 0.00 1.00 0.33;
                        0.00 0.33 0.20 1.00;
                        0.20 0.33 0.80 1.00;
                        0.80 0.33 1.00 1.00];
      
      plusz_minusz(num,1:6)=[-1;1;-1;1;-1;1];
      %--------------------------------------
          
          %atirjuk a 0 ertekeket 1-re, mert a matlabban a tombok 
          %1-tol vannak indexelve.
          merettel=sorok*meret;
      
          hol_van_zero=find(merettel<1);
          for i=1:length(hol_van_zero)
              merettel(hol_van_zero(i))=1;
          end
          merettel=round(merettel);
            for fsz=1:5
                 for i=1:sorszam(fsz)
                     feature_temp(fsz,i)=int(merettel(fsz,i,1),merettel(fsz,i,2))-int(merettel(fsz,i,1),merettel(fsz,i,4))-int(merettel(fsz,i,3),merettel(fsz,i,2))+int(merettel(fsz,i,3),merettel(fsz,i,4));
                 end
                 feature(fsz)=sum(feature_temp(fsz,1:sorszam(fsz)).*plusz_minusz(fsz,1:sorszam(fsz)));
             end
             feature=feature/(18*18*256);
                                  
                                  
                  bemenet = feature'; %beallitjuk a bemenetet
                  %minimum es maximum ertekek meghatarozasa
                  y=zeros(5,1);%ide kerulnek a normalizalt bemeneti ertekek
                  for i=1:5
                  y(i,1) = (ymax-ymin)*(bemenet(i,1)-xmin(i,1))/(xmax(i,1)-xmin(i,1)) + ymin;
                  end
                  %L1_w1 tartalmazza a Layer1-ben levo sulyzo ertekeit.
                  L1_w1_ki=sum(L1_w1.*y);%ehhez hozzaadjuk a sulyzot            
                  netsum_1_ki=eltolas_1+L1_w1_ki;%ez megy be a tangens hiperbolikuszba
                  %purelin_kimenet = purelin(netsum_1_ki);
                  %atviteli fuggveny szamolasa
                  purelin_kimenet = netsum_1_ki;
                  %a sulyzo_2_* a layer2-es ket sulyzoja
                  arc_e(1)=purelin_kimenet*sulyzo_2_1;
                  arc_e(2)=purelin_kimenet*sulyzo_2_2;
                  %ezt meg el kell toljuk a Layer2-Bias ertekevel            
                  majdnemvege = arc_e+eltolas_2;
                  %purelin atviteli fuggveny kiszamolasa a Layer 2-ben
                  %eredmeny = purelin(majdnemvege);
                  eredmeny=majdnemvege;
                  %if(eredmeny(1)>0.7)&&(eredmeny(2)<0)
                  if(eredmeny(1)>1)&&(eredmeny(2)<0)
                      arc_e=1;
                  else
                      arc_e=0;
                  end
      
      end
      
      


           Ez a függvény az öt nyertes tulajdonság felhasználásával számol egy kimeneti értéket. A neuronhálónak kétféle kimenete lehet. Egyes, vagy minusz egyes. Ha az első kategóriánál lesz egyes, az azt jelenti, hogy az illető bemenet az első kategóriához tartozik.

           S hogy miért jó ez? Mert olyan arcokról is el tudja dönteni nagy hatékonysággal, hogy arc, amelyiket még életében egyszer sem látott és amelyikről még senki nem mondta neki, hogy arc, csak ezekből a közös tulajdonságokból kiindulva. Mennyire hatékony, mennyire pontos? Ez csak a tulajdonságokon és a tanító halmazon múlik. Minél több tulajdonság, annál hatékonyabb. Minél több tanító elem, annál hatékonyabb.

           Mit tud ilyen módon felismerni? Szinte akármit. Lehet az gyalogos, autó, labda, forgalmi tábla, kutya, macska, akármi.

           Ha megvan a betanított neuronhálónk, és értjük a benne lezajló folyamatokat, akkor egy akármilyen képen könnyűszerrel végig tudunk pásztázni, hogy megtaláljuk, hol van a képen arc. A módszer a következő : Fogunk egy keretet, amit rárakunk a kép egyik sarkára. megvizsgáljuk, hogy a keret által határolt részben lévő képen van-e arc, vagy nincs. Ha van, bekeretezzük. Majd továbblépünk és egy kicsit arrébb is megnézzük, hogy arc, vagy nem. És így végigpásztázzuk az egész képet. Miután végeztünk, egy kicsit növeljük a keret méretét, és ujrapróbálkozunk. A keret méretének változtatása azért szükséges, hogy a képen szereplő összes méretű arcot megtaláljuk.

           Esetemben ez úgy működött, hogy végigpásztáztam a képet több különböző méretű kerettel, és összegyüjtöttem azokat a helyeket, ahol a program arcot talált. Összeadtam az összes X koordinátát, és eloszottam annyi részre, ahány arcot talált. Majd ugyanígy átlagot számoltam az Y koordinátából is. Ennek a módszernek a hatékony kezeléséhez azt is tudni kell, hogy ugyanazt az arcot többször is megtalálja a program, több különböző méretben, de mindíg ugyanott. Miután megvan az X és Y koordináta, rajzolok egy keretet a képre, az illető koordinátáknak megfelelően (vagy majd arra fogom mozdítani a robot fejét)...


      Röviden ennyi lenne. Remélem elég érthető voltam.

      Neuronháló újratöltve

           Mint már a korábbi bejegyzésekben is említettem, egy nenuronháló lesz megtanítva, hogy különbséget tegyen arcok és nem arcok között. Ennek a neuronhálónak a tanításához a Matlabot használtam fel, de ugyanígy bármilyen programozási nyelvet fel lehet használni (hiszen a Levenberg Marquardt féle minimumkeresés szinte minden programozási nyelvben implementálva van).



           A Levenberg Marquardt algoritmus egy numerikus módszer többparaméteres függvény minimumkeresésére, illetve egy nagyon jó és gyors módszer a neuronháló tanítására, ahol a kimeneti és elvárt érték közötti hiba kiszámításaután behangolásra kerül a neuronháló súlyzója. Sokak szerint nem ez a legjobb megoldás neuronháló tanításra, ott van még vagy nyolc másik módszer, köztük a "Scaled Conjugate Gradient" vagy a "Fletcher-Powell Conjugate Gradient", viszont ezzel az LM módszerrel sokkal (a francokat sokkal... csak egy kicsivel) jobb eredményeket értem el, sokkal kevesebb tanítási ciklus alatt. S hogy mi megy a háttérben? Na azt nem tudom...

           Optimum 1.-ből tanultuk, hogy ha globális minimumot szeretnénk megkapni, akkor több helyről kell elindítani a minimumkereső algoritmusunkat, és kiválasztani a sok megoldásból a legkisebbet, vagy ha mindenik megoldás ugyanoda vezet, akkor valószínűsíthető, hogy az a megoldás a globális minimum. Én is ezt tettem. Beállítottam, hogy a bemeneti értékeket véletlenszerűen ossza szét tanító, tesztelő és megerősítő (validáló) adatokra és lefuttattam 10szer egymás után a tanítást. A tanítás eredményéből kimásoltam a bemeneti súlyzókat (ezek döntik el, hogy az egyes tulajdonságok milyen mértékben vesznek részt a kimeneti válasz alakításában, mert minél nagyobb egy súlyzó értéke abszolút értékben, annál több "szavazati joga" van a kimenet alakulásába). Ezeket a súlyzókat növekvő sorrendbe helyeztem (mint már mondtam, abszolút értékben) és a következő listát kaptam :

      103, 24, 101, 99, 85, 89, 38, 47, 54, 39, 57
      103, 24, 101, 99, 85, 84, 39, 89, 38, 83, 63
      103, 24, 101, 99, 85, 89, 38, 54, 55, 39, 84
      103, 24, 101, 85, 38, 89, 39, 99, 84, 57, 47
      103, 24, 101, 99, 85, 39, 54, 57, 89, 38, 84
      103, 24, 101, 85, 38, 99, 89, 39, 54, 84, 57
      103, 24, 101, 99, 85, 89, 54, 38, 39, 57, 84
      101, 103, 24, 38, 57, 89, 99, 90, 54, 85, 84
      103, 24, 101, 99, 85, 38, 89, 84, 47, 39, 63
      103, 24, 101, 99, 85, 38, 47, 89, 63, 57, 84
      

           Az eredmény magáért beszél. Ez  a lista azt jelenti, hogy azok, akik ott szerepelnek, nagy valószínűséggel van annyi beleszólásuk a kimenet alakulásába, hogy ők tizen el tudják dönteni, hogy mi legyen a kimenet.


       
       
      Itt látható a tanítás eredménye egy átlagos tanitási ciklusra a tízből. 85.3%-os hatékonysággal ismeri fel az arcokat, illetve 99%-os hatékonysággal ismeri fel a nem arcokat. Ez mindenképp számomra nagyon jó eredmény, mert egy ilyen neuronnal már kategorizálni lehetne a képeknek nagy részét, minimális fals pozitív találattal. Ennek az eredménynek a tanítási ciklusa a következő ábrán látható:

            Itt a képre kattintva láthatjuk, hogy a tanítás kilenc ciklus alatt véget is ért. Az alatt a 10 teszt tanítás alatt átlagosan 7-12 tanítási ciklus alatt elértük a fent említett eredményt. Most, hogy megvan a 10 legnagyobb szavazattal rendelkező bemenet, megpróbálok valami jó eredményt kihozni csak azt a tizet felhasználva.

            Sajnos elsőre elég elszomorító eredményeket kaptam, ami a többségi szavazatokat illeti. Az arcoknak csak harminchat százaléka volt arcnak felismerve, illetve fals pozitív találat is volt, a nem arcok két százaléka, ami a végső összetételben az arcok tizenhat százalékát teszi ki... Lásd a képet lennebb...

           Ilyenkor az egyik megoldás az arcok többségbe helyezése. Ezzel befolyásolhatjuk a minimumpont elhelyezkedését. Másik megoldás a minimum kereső algoritmus többszöri lefuttatása... Először ezt próbálom ki, hátha valami jobb eredménnyel kecsegtet...

           Tíz perccel később: Semmi változás. Arcok több mint hatvan százalékát nem ismeri fel.

           Egy órával később: Előszedtem egy régebbi programomat, amivel lehetett képekre is tesztelni a súlyzóimat, meg az eltolásokat.

            Íme a program:

      %Keppel tesztelo fuggvenyt hivjuk meg;
      clear all
      close all
      clc
      
      img=imread('gs.jpg');
      kepint=cumsum(cumsum(double(img)),2);
      hol=zeros(3,1);
      szelesseg=650;
      magassag =487;
      feature=zeros(1,5);
      
      for meret=200:4:240        
          for x_megy=1:meret/2:(magassag-meret-1)
              for y_megy=1:meret/2:(szelesseg-meret-1)
                  int=kepint(x_megy:x_megy+meret,y_megy:y_megy+meret);
                  [arc_e,bemenet] = elsoszint(int,meret);
                  if(arc_e ==1)
                      %disp('Elsoszint Megvolt.');
                      [arc_e,bemenet]=masodikszint(int,meret,bemenet);
                      if arc_e==1
                          %disp('Masodik Szint Megvolt.');                    
                          [arc_e,bemenet]=harmadikszint(int,meret,bemenet);
                          if arc_e==1
                              hol=[hol [meret;x_megy;y_megy]];
                          end
                      else
                         % disp('<<<NEMARC>>>');
                      end
                      
                  else
                      %disp('NemARC');
                  end
      %             dispimg=img;
      %             dispimg(x_megy:x_megy+meret,y_megy)=255;
      %             dispimg(x_megy:x_megy+meret,y_megy+meret)=255;
      %             dispimg(x_megy,y_megy:y_megy+meret)=255;
      %             dispimg(x_megy+meret,y_megy:y_megy+meret)=255;
      %             imshow(dispimg);
                  %pause
              end
              clc
          end
      end
      hol=hol';
      dispimg=img;
      for i=2:length(hol)
          if(hol(i,1))>0 & (hol(i,2))>10 & (hol(i,3))>10
                  dispimg(hol(i,2):hol(i,2)+hol(i,1),hol(i,3))=255;
                  dispimg(hol(i,2):hol(i,2)+hol(i,1),hol(i,3)+hol(i,1))=255;
                  dispimg(hol(i,2),hol(i,3):hol(i,3)+hol(i,1))=255;
                  dispimg(hol(i,2)+hol(i,1),hol(i,3):hol(i,3)+hol(i,1))=255;
          end
      end
      imshow(dispimg);
      % x_megy=round(mean(hol(2,:)));
      % y_megy=round(mean(hol(3,:)));
      % meret=hol(1,length(hol));
      % 
      %             dispimg=img;
      %             dispimg(x_megy:x_megy+meret,y_megy)=255;
      %             dispimg(x_megy:x_megy+meret,y_megy+meret)=255;
      %             dispimg(x_megy,y_megy:y_megy+meret)=255;
      %             dispimg(x_megy+meret,y_megy:y_megy+meret)=255;
      %             imshow(dispimg);
      
      

            FIGYELEM : A következő képeken kitalált személyek láthatóak. Bármilyen egyezés valós személyekkel csak a huncut fantáziám nomeg a véletlen műve lehet. Ha mégis akadna bárki, aki a képek között magára ismer (és lessz olyan genya, hogy nem járul hozzá a tudomány fejlődéséhez és személyiségjogokkal való visszaélés miatti perrel fenyeget), az kérem jelezzen, hogy a képét cseréljem ki egy másik (szintén fiktív) személy képére.

           Pár tesztkép, amire lefuttattam, és viszonylag jó eredményeket kaptam :


            Aztán rájöttem, hogy a legegyszerűbb módja a többes találat kiküszöbölésének az, ha a találatokból átlagot számolok. Vagyis, ha van harminchat találatom egy bizonyos területen, akkor fogom az egészet, s összegyúrom egy globális X és egy globális Y koordinátába, s majd megmondom a póknak, hogy pont annak a közepére nézzen. Ezek a többes találatok vannak a második és negyedik képen kiküszöbölve.

           Persze azt meg kell említeni, hogy az arc méretét (vagyis egy bizonyos tartományt) mindíg kézzel kell bevinni, viszont valószínűleg egy komolyabb méréssorozat után majd a póknál tudok egy konkrét tartományt adni, amin belül érdemes az arcokat keresni... Itt is többnyire 200 és 350 pixel közötti méretben keres a program, viszont mindig kell egy kicsit hangolni, amiatt, hogy nem ugyanolyan távolságról voltak készítve...

           Egyre jobban tetszik ez a program... Már csak az a lényeg, hogy a MicroBlaze-be beleférjen...


           Na hülyeségből ennyi elég mára... Ha minden jól megy, holnap este felprogramozom a Microblaze-re is a harmadik szintet (ez most három szintes vizsgálatnak veti alá az egyes képrészleteket), s kipróbálom, mit tudok kihozni belőle... De addig... Addig relax van... Holnap megyek, megnézem a jamikat... S relax...
      Return top