Object Tracking

Folly Áron

Az object tracking

Az alábbi dolgozat Alper Yilmaz, Omar Javed és Mubarak Shah Object Tracking: A Survey valamint Omar Javed és Mubarak Shah Tracking And Object Classification For Automated Surveillance című cikkek alapján íródott.

A dolgozat témája videón mozgó objektumok észlelésének és követésének megvalósítása. Ez nagyon fontos eszköze a videós felügyeleti rendszereknek. Az alábbi program az object tracking, azaz az objektumkövetés leggyakoribb esetére a személykövetésre mutat egy egyszerű modellt. A Performance Evaluation of Tracking and Surveillance (PETS) az objektumok videón való felismerésére és követésére szolgáló algoritmusok kiértékelése, a videót az erre szolgáló adatbázisból vettük.

A videót természetesen frame-ek (azaz képek) sorozataként kezeljük. Az objektumkövetés lényege a következő: minden framet ketté kell bontani háttérre és előtérre úgy, hogy a mozgó objektum legyen az előtérben. A kamera a mi példánkban egy folyosóról készít felvételt, amelyen emberek haladnak keresztül. A háttér az üres folyosó kell legyen, azonban, hogy mit tekintünk háttérnek, azt frame-ről frame-re frissíteni kell, ezt hívjuk background updatenek. A foreground detecting során az adott frame-ről leválasztjuk a hátteret, ez lesz az előtér, melyben a személy van. Az előtérről egy úgynevezett maszkot (foreground mask) is készítünk, mely egy olyan kép amelyen az előtérhez tartozó pixelek fehérek, a háttérhez tartozó pixelek pedig feketék.

A frame-ek importálása

Megadjuk, hogy hány frame-mel akarunk dolgozni, és létrehozunk egy ennek megfelelő méretű tömböt, amibe a megfelelő könyvtárból importáljuk a frame-eket. A folyosón az első és utolsó néhány másodpercben még nem halad át ember, így a háromszázadik frame-től vett kétezer frame-mel dolgozunk.

SetDirectory[NotebookDirectory[]]

size=2000;
Images=Range[1,size];

ImportFrames[]:=Module[{},
For[i=1,i<=size,i++,
Images[[i]]=Import["d:\\Dokumentumok\\Egyetem\\ProgFel3\\FollyAron\\Data\\indoorGT"<>ToString[i+300]<>".jpg"];
]
]
ImportFrames[];

im1[size_]:=Table[Import["d:\\Dokumentumok\\Egyetem\\ProgFel3\\FollyAron\\Data\\indoorGT"<>ToString[i+300]<>".jpg"],{i,size}];

im2[size_]:=Import["d:\\Dokumentumok\\Egyetem\\ProgFel3\\FollyAron\\Data\\indoorGT"<>ToString[#+300]<>".jpg"]&/@Range[size]

A background és az azt frissítő függvény

A kiindulási háttér az első frame. A backgroundot folyamatosan frissíteni kell, az alpha konstans az exponenciális tanulási ráta, ennek értéke határozza meg, hogy mennyire gyorsan frissül a háttér. Az aktuális háttér a korábbi framekből adódik össze, minnél régebbi egy frame, annál kevésbé számít bele az aktuális háttérbe.

BackGround=ImageData[Images[[1]],"Byte"];
alpha=0.2;

UpdateBackground[par_,α_:0.2]:=Module[{i=par},
BackGround=Floor[(1-α)BackGround + α ImageData[Images[[i]],"Byte"]];
]

A maszkot számoló függvény

Egy adott framehez a maszkot az aktuális háttér és a frame eltéréseként számoljuk. Létezik képek különbségét számoló függvény, azonban nekünk a képek adathalmazait kell kivonnunk egymásból, hogy negatív értékeket is kaphassunk. Mi ugyanis, az adott frame és az aktuális háttér eltérését, és nem különbségét keressük. Ha egy fekete (csupa nulla) képből kivonunk egy csupa fehér képet, akkor a fekete képet kapjuk, míg ha a képek adathalmazait vonjuk ki egymásból, és abszolút értéket veszünk, akkor a fehér kép az eredmény. A maszkra később viszont képként lesz szükségünk, ezért csinálunk belőle image-et.

Mask=Range[1,size];

GetMask[par_]:=Module[{im=par,diff,mask},
diff=Abs[BackGround-ImageData[Images[[im]],"Byte"]];
mask=Image[diff,"Byte"];
mask
]

gm[par_]:=Image[Abs[BackGround-ImageData[Images[[par]],"Byte"]],"Byte"];

Elvégezzük a trackinget

A MyProcess a program lényegi része: minden frame-hez frissíti a hátteret és meghatározza az előtérmaszkot. Fontos, hogy az UpdateBackground és a GetMask függvényeket párhuzamosan futtassuk, ugyanis a GetMasknek az aktuális háttérre van szüksége.

MyProcess[]:=Module[{},
BackGround=ImageData[Images[[1]],"Byte"];
For[i=1,i<=size,i++,
UpdateBackground[i];
Mask[[i]]=GetMask[i];
]
]
MyProcess[];

A maszk javítása

A kép természetesen nem csak ott változik, ahol épp egy ember mozog, ennek sok oka lehet: a kamera rezeghet, a napszakok váltakozásával a fényviszonyok is változnak, az objektumok árnyékot vetnek stb. Ezért fölösleges apró részek is belekerülnek a maszkba, ezeket érdemes kivenni a maszkból. Ha a maszk egy összefüggő része egy bizonyos méret alatti, akkor tudjuk, hogy az nem lehet egy ember. Ezeket a kis komponenseit a maszknak az alábbiakban töröljük, ez azonban nagyon erőforrásigényes.
A maszkot fekete-fehérré tesszük, azaz binarizáljuk úgy, hogy azok a részek a fehérek, ahol a frame egy adott szintnél jobban eltér a háttértől. A maszk lehet töredezett, annak érdekében, hogy összefüggő komponensekből álljon, a Blur függvénnyel kicsit elmosódottá tesszük a maszkot, amit ezután komponenseire bontunk.

MakeNullFunc[par1_,par2_]:=Module[{x=par1,y=par2},If[x==y,x=0];x];
KillSmallObject[par1_,par2_]:=Module[{MorphPic=par1,CompNum=par2},
MorphPic=Map[MakeNullFunc[#,CompNum]&,MorphPic,{2}];
MorphPic
]

GetOnlyPersonMask[par_]:=Module[{i=par, MorphMask, TallyMask},
MorphMask=MorphologicalComponents[Blur[Binarize[Mask[[i]],0.1],10],Method->"BoundingBox"];
TallyMask=Tally[Flatten[MorphMask]];
Map[If[#[[2]]<1200,MorphMask=KillSmallObject[MorphMask,#[[1]] ],]&,TallyMask];
MorphMask
]

A tracking szemléltetése

A videót párhuzamosan három képpel szemléltetjük: az első képen a maszkot látjuk, a másodikon a felismert objektumokat határoló téglalapot, a harmadikon pedig az eredeti videót, kiemelve rajta a felismert embereket.
A MyFastManipulate még nem használja a javított maszkot, azonban ez sokkal gyorsabb, míg a MyManipulate azt a maszkot használja, amiben már valóban csak a felismert ember van.

MyFastManipulate[par_]:=Module[{i=par, BinMask,MorphMask, HighLightedImage },
BinMask=Binarize[Mask[[i]],0.1];
MorphMask=MorphologicalComponents[Blur[Binarize[Mask[[i]],0.1],10],Method->"BoundingBox"];
HighLightedImage=Image[ImageData[Images[[i]],"Byte"]+20*MorphMask,"Byte"];
{BinMask,MorphMask//Colorize,HighLightedImage}
]

MyManipulate[par_]:=Module[{i=par, BinMask,OnlyPersonMask, HighLightedImage },
BinMask=Binarize[Mask[[i]],0.1];
OnlyPersonMask=GetOnlyPersonMask[i];
HighLightedImage=Image[ImageData[Images[[i]],"Byte"]+20*OnlyPersonMask,"Byte"];
{BinMask,OnlyPersonMask//Colorize,HighLightedImage}
]

Manipulate[MyFastManipulate[u],{u,1,size,1}]

Manipulate[MyManipulate[u],{u,1,size,1}]

"Speed" ,PerformanceGoal->"Speed"