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.

1 megjegyzés:

Megjegyzés küldése

Return top