庖丁解牛TLD
一、庖丁解牛TLD——開篇
最近在網(wǎng)上多次看到有關(guān)Zdenek Kalal的TLD的文章,說他做的工作如何的帥,看了一下TLD的視頻,感覺確實(shí)做的很好,有人夸張的說他這個系統(tǒng)可以和Kniect媲美,我倒是兩者的工作可比性不大,實(shí)現(xiàn)的方法也不同。但這個哥們做的真的很棒,最可貴的是人家提供了源碼可以下載。他相關(guān)的工作網(wǎng)上一搜一大片,推薦一個鏈接http://www.cvchina.net/article-22-1.html,再給個作者網(wǎng)站的鏈接http://info.ee.surrey.ac.uk/Personal/Z.Kalal/。
看了他的demo視頻頓時心潮澎湃,趕緊下載了他的源代碼后又有些崩潰了。他的工作量還是很大的,得靜下心來慢慢研究。直接看代碼難免云里霧里的,先看看人家的論文吧。
這哥們這幾年可真沒少發(fā)paper啊,我比較關(guān)注他實(shí)現(xiàn)的算法。TLD即Tracking Learning Detector,我認(rèn)為就是依據(jù)跟蹤學(xué)習(xí)的目標(biāo)檢測??戳怂?8年發(fā)表的一篇文章,介紹了他的這個算法,那時候還把算法稱為TMD(tracking、modeling、detection),他的tracking工作時基于Lucas-Kanade光流法的。modeling學(xué)習(xí)的過程有g(shù)rowing和pruning兩方面的工作,可以正負(fù)反饋,得到較好的學(xué)習(xí)結(jié)果,對于他的學(xué)習(xí)過程,他在另一篇文章中又詳細(xì)介紹了P-N learning這種學(xué)習(xí)算法。detection的部分用的是隨機(jī)森林的機(jī)器學(xué)習(xí)辦法,加上bootstarps。對于特征的選擇,他提出了一種基于LBP特征的2bit BP特征。幾篇文章下來,我已經(jīng)有點(diǎn)暈乎了,這些算法都不是太熟悉,看來得結(jié)合代碼一個個啃了。
代碼正在一點(diǎn)點(diǎn)啃,有同樣興趣的朋友可以交流指導(dǎo)一下,不勝感激。
二、庖丁解牛TLD——初始化工作(為算法的準(zhǔn)備)
我說的初始化,還不是算法的初始化工作,而是讀入圖像,響應(yīng)鍵盤鼠標(biāo)之類的工作。作者提供的代碼中的工作包含了從攝像頭讀取和從文件中讀取兩種輸入方案。這里介紹一下從文件輸入的辦法。因?yàn)镺penCV從視頻讀取圖像序列的辦法有很好的demo,我這里就不介紹攝像頭的辦法了。TLD下載后有一個文件夾是_input,里面存放著一組圖片組,圖片文件的名字為00001.png、00002.png....。我讀取圖片組的關(guān)鍵代碼如下,這段代碼具有普遍意義,可以移植到以后想讀入圖片組的任意程序中:
stringstream fileNameStream; string sourceImageFileName; for(int nFrame=0; nFrame<NUM; nFrame++) {nFrame++;fileNameStream << "_input\\" << setw(5) << setfill('0') << nFrameNum << ".png";sourceImageFileName = fileNameStream.str();fileNameStream.clear();fileNameStream.str("");// 讀取圖像g_src = imread(sourceImageFileName); }這就實(shí)現(xiàn)了圖片的讀入工作,再參考camshiftdemo的辦法實(shí)現(xiàn)了鼠標(biāo)和鍵盤的響應(yīng)。鼠標(biāo)的響應(yīng)就是得到目標(biāo)區(qū)域的范圍,用鼠標(biāo)選中boundingbox。文件讀進(jìn)來了,目標(biāo)區(qū)域boundingbox也得到了,接下來就是需要對算法進(jìn)行研究了。
先介紹幾個我研究過的心得,bbox文件夾下面的代碼主要都是對boundingbox的處理。tld文件夾下面的存放的是主干的算法,從run_TLD入手,感覺就是對起始幀進(jìn)行初始化工作,然后逐幀讀入圖片序列,進(jìn)行算法處理。還是先分析初始化工作,作者的tldInitSource函數(shù)實(shí)現(xiàn)的就是基本的初始化,給一些變量賦值,開辟矩陣大小,這個沒什么好講的。tldInitFirstFrame文件完成的工作就是選中boundingbox,這個功能我已經(jīng)通過鼠標(biāo)的響應(yīng)得到了boundingbox,也可以略過不細(xì)分析。重點(diǎn)的初始化工作是在tldInit里實(shí)現(xiàn)的,這個函數(shù)也是我接下來研究的重點(diǎn),本人Matlab較差,真希望有高人指點(diǎn)啊,一起研究啊
三、庖丁解牛TLD——算法初始化
上一講我提到對于算法的初始化工作主要是在tldInit這個函數(shù)里實(shí)現(xiàn)的。主要分為如下幾大步驟,1)初始化Detector。2)初始化Trajectory。3)訓(xùn)練Detector
1)初始化Detector
其中bb_scan為掃描grid區(qū)域,該函數(shù)輸入為boundingBox,輸出為一系列的RectBox,是根據(jù)boundingBox的大小參數(shù)對待搜素區(qū)域選擇一系列的box作為備選的跟蹤區(qū)域,box的位置和尺度都有變化,和RectBox相應(yīng)的尺度。但RectBox有6個參數(shù),前4個分別為Rect的左上角坐標(biāo)(x1,y1)和右下角坐標(biāo)(x2,y2)。后兩個參數(shù)求大神解釋(PS:后來在fern函數(shù)里找到了解釋,分別為指向?qū)?yīng)尺度特征的指針位置、每一行box的數(shù)量——用在搜索鄰近box)!對于這個函數(shù)內(nèi)部我還有一個疑惑,就是對ntuples函數(shù)功能的使用,哎,怎奈Matlab語法都不熟悉,只能慢慢啃了,感覺作者這里就是把RectBox的左上角的所有可能的坐標(biāo)值傳入該函數(shù),得到左上角坐標(biāo)位置的全部組合(不知道理解對了沒)。
接下來的工作時特征的初始化,是在tldGenerateFeature函數(shù)里實(shí)現(xiàn)的。這個函數(shù)相對獨(dú)立,作者這里為了產(chǎn)生效果較好的隨機(jī)特征真是煞費(fèi)苦心,輸入的參數(shù)有兩個,一個是nTREE = 10,一個是nFEATURE = 13。輸出為nTREE組特征,每組特征為nFEATURE個點(diǎn)對,每一個點(diǎn)對有4個參數(shù),分別兩點(diǎn)坐標(biāo)(x1,y1),(x2,y2),取值范圍為(0~1)其中第一個點(diǎn)的分辨率為0.1,還不太明白這樣設(shè)計(jì)的原因,待進(jìn)一步分析代碼,有高人指點(diǎn)一下更好。值得注意的是產(chǎn)生的點(diǎn)對不是橫坐標(biāo)相同x1 = x2,就是縱坐標(biāo)相同y1 = y2。這里用圖片顯示一組特征,線段的兩個端點(diǎn)
下一步工作為初始化detector。這個功能是用強(qiáng)大的fern函數(shù)寫的,該函數(shù)有多個功能,根據(jù)傳入?yún)?shù)的標(biāo)志分別可以實(shí)現(xiàn)clear操作、init操作、update操作、evaluate操作、detect操作、get pattern操作。fern函數(shù)是用c寫的,混合編程沒有弄的太明白,還沒能調(diào)試一下看看,只能看代碼猜。在初始化detector的工作里,用到的是init操作。
2)初始化Trajectory
這部分沒有什么要說明的,都是些零碎的初始化工作,matlab里面對一些必要的變量開辟一些空間和定義一些變量的值。具體分析Trajectory的工作的時候可以具體再分析
3)訓(xùn)練Detector
首先得到Target,作者注釋說該Target只是用來顯示,有待我后續(xù)驗(yàn)證。得到Target要調(diào)用函數(shù)img_patch,img_patch函數(shù)是獲得一幅圖像中目標(biāo)區(qū)域box的像素信息patch。
接下來產(chǎn)生正樣本數(shù)據(jù)集,調(diào)用tldGeneratePositiveData。其中第二個參數(shù)為RectBox和box的重復(fù)區(qū)域比例信息,保存在overlap參數(shù)中,由函數(shù)bb_overlap得到。tldGeneratePositiveData函數(shù)首先根據(jù)overlap的比例信息選出重復(fù)區(qū)域比例大于60%并且前num_closet ?= 10個的最接近box的RectBox,相當(dāng)于對RectBox進(jìn)行篩選。并通過bb_hull函數(shù)得到這些RectBox的最大邊界。接下來的工作比較重要,要得到Pattern,調(diào)用的函數(shù)為tldGetPattern。初始化的工作就是對最接近box的RectBox區(qū)域得到其patch,然后調(diào)用tldPatch2Pattern將像素信息轉(zhuǎn)換為Pattern,具體的說就是歸一化RectBox對應(yīng)的patch的size(放縮至patch_size = 15*15),將2維的矩陣變成一維的向量信息,然后將向量信息均值設(shè)為0,調(diào)整為zero mean and unit variance(ZMUV),這個過程調(diào)用函數(shù)tldPatch2Pattern實(shí)現(xiàn)。接下來處理RectBox最大邊界的模糊信息,再次用到img_patch函數(shù),但這次調(diào)用的函數(shù)有很大的不同,還沒太理解作者要做什么啊,怎么感覺還有平移旋轉(zhuǎn)矩陣都出來了,暈啦(求高人指點(diǎn))。該函數(shù)最后返回3個參數(shù),pX為處理后的RectBox最大邊界處理后的像素信息,pEx最近鄰的RectBox的Pattern,bbP0為最近鄰的RectBox。
然后再產(chǎn)生負(fù)樣本數(shù)據(jù)tldGenerateNegativeData。得到遠(yuǎn)離box(重復(fù)區(qū)域比例小于20%)的num_patches = 100個Pattern保存到nX中,隨機(jī)選中num_patches = 100個RectBox得到對應(yīng)的patch保存到nEx中。這里調(diào)用了fern(5),即該函數(shù)的get pattern操作。
接下來對負(fù)樣本進(jìn)行分類,分類到訓(xùn)練集Training Set和驗(yàn)證集Validation Set中去。
接下來使用Training Set進(jìn)行訓(xùn)練,先調(diào)用fern(2),更新,然后調(diào)用tldTrainNN最近鄰訓(xùn)練數(shù)據(jù)。
接下來評估驗(yàn)證集Validation Set的閾值。調(diào)用tldNN驗(yàn)證。
至此,初始化的工作基本完成,限于本人水平有限,只能先對函數(shù)有個大概的認(rèn)識,深深覺得先要靜下心來把訓(xùn)練的算法搞清楚,再回過頭來再看一編代碼。
四、?庖丁解牛TLD——Tracking解析
前幾節(jié)都是根據(jù)作者的程序流程一步步介紹作者的工作,感覺只是對代碼的一個注釋,這次換一個思路,一部分一部分啃,作者的工作主要就是3部分么,tracking,learning,detection。
這次先介紹Tracking的工作。對于Tracking,作者主要使用的是他提出的Forward-Backward Error的辦法,使用Lucas-Kanade光流法跟蹤,對跟蹤的結(jié)果,用Forward-Backward Error做反饋,求FB error的結(jié)果與原始位置的歐式距離,把距離過大的跟蹤結(jié)果舍棄,他把這種利用FB error舍棄壞值的跟蹤方法叫做Median Flow,是把歐式距離集合中較大的50%的那些跟蹤結(jié)果舍棄。作者在他的文章Forward-Backward Error:Automatic Detection of Tracking Failures里提到用FB+NCC(交叉驗(yàn)證)的方案,可以使跟蹤的結(jié)果最佳。作者的Tracking的辦法就是根據(jù)我以上介紹的流程實(shí)現(xiàn)的。接下來結(jié)合代碼再詳細(xì)剖析一下
先用bb_points函數(shù)在box中均勻采樣10*10個點(diǎn),注意作者這里設(shè)置了采樣點(diǎn)的區(qū)域比box的區(qū)域少一圈邊界,邊界為5,在后面我會介紹作者這里的獨(dú)到用心。然后調(diào)用混合編程的lk函數(shù)實(shí)現(xiàn)lucas-Kanade光流法跟蹤,得到的結(jié)果有為這100個點(diǎn)的lk結(jié)果,前兩個參數(shù)為利用l-k方法得到的點(diǎn)當(dāng)前的跟蹤位置坐標(biāo),第三個參數(shù)是利用NCC把跟蹤預(yù)測的結(jié)果周圍取10*10的小圖片與原始位置周圍10*10(這里取10*10,有心的朋友應(yīng)該笑了,為什么作者之前在bb_points函數(shù)里要設(shè)置個邊界5,原來是防止越界哦)的小圖片(使用函數(shù)getRectSubPix得到)進(jìn)行模板匹配(調(diào)用matchTemplate),再對匹配的結(jié)果歸一化,把這個結(jié)果保存在第三個參數(shù)中,第四個參數(shù)為FB error的歐氏距離。這個lk函數(shù)過程中有很多參數(shù)可以設(shè)置,對最終的結(jié)果我想應(yīng)該應(yīng)該也是有的,有待實(shí)驗(yàn)驗(yàn)證。接下來就是利用作者提出的Median Flow,得到NCC和FB error結(jié)果的中值,分別去掉中值一半的跟蹤結(jié)果不好的點(diǎn),利用這一半(其實(shí)不到50%)的跟蹤點(diǎn)輸入函數(shù)bb_predict函數(shù)中預(yù)測bounding box在當(dāng)前幀的位置和大小。
這基本就是Tracking工作的主要部分了,至于被遮擋的tracking(tldTrack_occlusion),作者進(jìn)行了單獨(dú)處理,下一次再分析。
PS:很感謝最近有些網(wǎng)友與我一起研究TLD,不過本人能力不足,很多東西還是不理解,對于作者detection和learning的工作,感覺那部分的代碼實(shí)在好比天書,沒法拿出來和大家交流了,希望有識之士也能寫出來,和大家分享~~
五、庖丁解牛TLD——井底之蛙啦~
隨著和我交流TLD的朋友越來越多,我漸漸的知道的也多了,才發(fā)現(xiàn)我研究的結(jié)果只是滄海一粟。
這里先膜拜一下Alan Torres大神,他已經(jīng)用c++把TLD重新寫好了,而且代碼很規(guī)范。他設(shè)計(jì)的理念有:
1. depends *only* on OpenCV (2.3)?
2. no Matlab!?
3. easy to compile and run (on linux, work in progress on OSX and windows)?
4. fast! (and more potential to be much faster)?
5. No Matlab! (did I say no matlab?)?
沒有matlab,多平臺,更快的速度。真好,就是我想做的,不過他現(xiàn)在這個程序,在我這電腦上實(shí)現(xiàn)速度還不行。他代碼的下載地址為https://github.com/alantrrs/OpenTLD,好像打不開,我是在這上面得到的https://github.com/arthurv/OpenTLD。不過是個Linux版本的。大家這么強(qiáng),改改肯定就可以在xp下跑起來了,反正我是搞定了。
附上他軟件的設(shè)計(jì)接口。真是賞心悅目啊,不得不說人家做的東西很規(guī)范,慚愧慚愧
看不清還是下載下來大家自己看咯,不好意思,我不知道怎么能傳上去看得清晰
從他這個設(shè)計(jì)圖也可以看出來我之前幾講分析的流程還是可以接受的,init部分和track部分是相對獨(dú)立的。而比較復(fù)雜的是learning的部分和detect部分。下一步主攻這兩部分了。學(xué)習(xí)的越深入,越是發(fā)現(xiàn)自己很挫,都沒信心繼續(xù)寫下去了。硬著頭皮裝大蔥吧~
出處:http://blog.csdn.net/yang_xian521/article/details/6952870
總結(jié)
- 上一篇: 如何实现科技论文里面的算法
- 下一篇: Machine Learning wee