TLD源碼學習-fern.cpp

TLD算法的運行過程中,關於圖像的操作,很大部分都是在fern.cpp中完成的,包括分配內存,計算一些指標,還有隨機森林。這部分我看了好幾遍,因爲裏面的結構實在有點多,而且比較繁瑣。下面記錄下我的結果。

按照tld調用fern的順序講。

(一)在tldinit.m中首先調用,fern(0),清楚所有靜態數據,

(二)然後是fern(1,tld.source.im0.input,tld.grid,tld.features,tld.scales),分配所需的內存空間和結構。

tld.source.im0.input,這是是第一幅圖像。

tld.grid,這是之前建立的關於窗格的矩陣。

是6*N的矩陣,每一列分別代表一個窗格,6個數分別表示坐上角x,y座標,右下角x,y座標,第幾個尺度(從1開始),該尺度下一行的窗格數,這樣看比較清楚,每列一個窗格,至於列數不確定,視具體情況而定。

tld.features,這是之前建立的特徵點位置,包括兩個域,第一個是52*10的矩陣,裏面都是由隨機函數生成,經過處理的0到1之間的點,代表在某個窗格中的偏移。第二個是個字符forest,沒啥大意義。

tld.scales,這是2*M的矩陣,每列表示一個scale下面,窗格的高和寬,即行數和列數。

下面說下這個函數具體分配了哪些空間。:

                iHEIGHT    = mxGetM(prhs[1]); //圖片的大小   
iWIDTH     = mxGetN(prhs[1]); 

                nTREES     = mxGetN(mxGetField(prhs[3],0,"x"));
nFEAT      = mxGetM(mxGetField(prhs[3],0,"x")) / 4;//因爲feature中是52*10,所以除以4剛好的13和論文裏一致。因爲feature有兩個域,所以要加mxGetField。

                thrN       = 0.5 * nTREES; //閥值
nSCALE     = mxGetN(prhs[4]); //尺度的數目

                IIMG       = (double*) malloc(iHEIGHT*iWIDTH*sizeof(double));
IIMG2      = (double*) malloc(iHEIGHT*iWIDTH*sizeof(double));//分配兩個圖像塊內存

                mBBOX      = mxGetM(prhs[2]);  //其實就是6,
nBBOX      = mxGetN(prhs[2]);//這是總共的格子數目 包括各個尺度下的

               BBOX  = create_offsets_bbox(mxGetPr(prhs[2]));//這個是關鍵之一,將輸入的窗格的座標轉換成內存地址,因爲建立窗格時使用的是平面座標,經過簡單的換算就可以變成內存地址,BBOX是7*N的矩陣,前四個是左上,右下角的x,y座標,第五個是該窗格的面積,第六個是指向該尺度下特徵點矩陣首地址的,因爲每個尺度下,大小不一樣,所有特徵點的偏移量不一樣,所有尺度下的特徵點矩陣依次往後排,所有每個尺度都要往後移,每次累加260個地址,第七個是該尺度下每行的窗格數目。這個是靜態的,以後還會用到這個結構體。

                double *x  = mxGetPr(mxGetField(prhs[3],0,"x")); //這個指向特徵點矩陣,就是那個52*10的
double *s  = mxGetPr(prhs[4]);    //指向尺度矩陣 2*M 每列就是該scale的高和寬
OFF   = create_offsets(s,x); //將特徵點轉換成每個尺度下的內存地址。這個也是很關鍵的東西,因爲那個feature就一個,而每個尺度下寬和高是不一樣的,所有按照各自的比例將特徵點矩陣換算成各自的地址,而且得到的是21*10*13*2的矩陣,21個尺度,10棵樹,13個特徵點,每個點2個座標值,就是x,y值,對應前面的BBOX中第6個每次累加260,其實就是移動一個’特徵塊‘,到達該尺度對應的特徵點矩陣。在說下這個21,這個OFF只是每個尺度下‘一個’窗格的特徵點矩陣,而且是最左上角的那個,所有計算下一個窗格特徵點位置時要記得往後移。

後面兩個for循環初始化下面三個結構體,全部爲0

static vector<vector <double> > WEIGHT;
static vector<vector <int> > nP;
static vector<vector <int> > nN;

(三)下面是fern(2,tld.X{1},tld.Y{1},tld.model.thr_fern,bootstrap);

這個是得到了正負樣本值後,對fern中的隨機森林進行具體的初始化

X{1}裏面是正負樣本,Y{1}指示對應的列是正樣本還是負樣本,thr_fern和bootstrap是設定的參數。

下面說下WEIGHT,nP,nN 這三個結構是啥,分別是10*2的13次方,10表示10棵樹,2的13次方是因爲,每棵樹13位,所以每個值都要有,nP[i][idx],表示第i棵樹特徵是idx的點出現的次數,nN類似, WEIGHT[i][idx],表示第i棵樹中,特徵idx出現在正樣本中的次數與出現總次數的比例。

fern(2)就是根據正負樣本的特徵值初始化以上三個結構體,將來detector工作的時候需要用到這三個東西。

(四)conf_fern = fern(3,nX2),nX2是負樣本矩陣,conf_fern是1*M的矩陣,表示對應的負樣本被當成正樣本的比例,用於糾正設定的系統參數tld.model.thr_fern。

(五)fern(4,img,tld.control.maxbbox,tld.var,tld.tmp.conf,tld.tmp.patt),這是在tldDetection中出現的

img就是輸入的圖片,tld.control.maxbbox和tld.var是系統參數,tld.var出現在tldinit中,tld.var = var(pEx(:,1))/2;是初始目標區域像素方差的一半,和論文中一致,後兩個是用來接收計算結果的,輸入是空的。

這個其實就是tld的檢測器,只不過有些東西前面分配好了而已。大致過程就是,滑動每個窗格,用

conf[I] = measure_bbox_offset(blur,I,minVar,tPatt)這個處理,I就是窗格的序號,minVar,是初始目標方差的一半用於級聯分類器的第一級,比它小的,直接返回,否則繼續,計算這窗格對應的局部2值特徵,並且到WEIGHT中查找,該特徵值,屬於正樣本的比例,conf就是10棵樹總的比例之和。

tld.tmp.conf,是窗格屬於正樣本的比例,越高越可能是正樣本,tld.tmp.patt,是每個窗格的patten值,即局部二值特徵。

(六)fern(5,im1,idxP,0) 就是計算輸入窗格的局部二值特徵值。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章