FerNNClassifier

来源:互联网 发布:互联网 消防大数据平台 编辑:程序博客网 时间:2024/05/17 21:14

本序列文章的目的是总结一下这段时间所学到的,主要分为以下几部分,本章是第五部分。

算法概述

2 runtld.cpp源码解析

3 tld.cpp源码解析

4 LKTracker(重点)

5 FerNNClassifier.cpp源码解析(重点)

6 tld_utils.cpp源码解析



方差分类器

代码中是通过积分图来计算一个图的灰度值的方差的。


fern分类器

a先讲解一下一个图的fern特征

这个fern分类器分为10个小的分类器(10棵树),

每棵树有13个节点,一个图被这13个节点处理后会变为13位的二进制码(比如0011001100010)。

10棵树处理后,就会产生1013位的二进制码。就是该图的fern特征。


b上面提高一个图会被一棵树的13个节点处理,那么这个特征抽取过程是怎么样的呢?下面讲解。

   A分类器的初始化

一棵树的初始化工作,根据一个patch的大小,随机均匀产生点对的集合,就是13个点对。所谓点对,就是两个点,比如(11)和(15),表示两个像素在图像的位置,这些点以后用来定位像素。

10棵树的初始化就是重复上面的操作了。

   B计算一个patch(指定大小的图)fern特征

先看看一个patch如何被一棵树处理。

一棵树其实就是13个点对的集合,每个点对处理一次,比如这个点对(24)和(56),把这两个点在patch的像素找出来比较大小,返回1或者013个点对就得到131或者0了。这样一个patch就被一棵树处理为一个13位的二进制码了。

一个patchfern特征就是被10棵树处理后的1013位二进制码了。


c训练过程

  A先验概率:每个fern特征在每棵树下都对应有一个先验概率。

比如计算fern特征在第i棵树的先验概率:

idx=fern[i],则

posteriors[i][idx]= ((float)(pCounter[i][idx]))/(pCounter[i][idx]+nCounter[i][idx]);

其中,

pCounter[i][idx]对于第i棵树,含有idx特征的正样本的数量

nCounter[i][idx]对于第i棵树,含有idx特征的负样本的数量

   B训练的过程,就是根据新的正负样本,不断更新pCounternCounterposteriors的值。

如果每一个新进来的样本,要通过之前的先验概率的和对它进行权重的判断,要跟某个阈值比较,符合条件才用新来的样本来更新posteriors


d分类

其实就是对fern特征进行权值衡量,判断大于还是小于某个阈值。



Nnc分类器

所有的patch要处理为15*15的大小。

训练:每进来一个新的样本patch,先将这个patch将之前保存的所有正的负的patch做比较,算出一个相似度的值,如果这个相似度跟某个阈值比较符合条件,就将这个新样本添加到库中。

那么这个相似度是怎么算的呢?

先说说一个patch和另一个patch的相似度怎么算。

代码中用的是库函数,算法是CV_TM_CCORR_NORMED(网上翻译为归一化相关匹配法)。

http://www.cnblogs.com/xrwang/archive/2010/02/05/MatchTemplate.html


我看论文提到的是

Similaritybetween two patches pi , pj is defined as

S(pi, pj ) = 0.5(NCC(pi , pj ) + 1),

whereNCC is a Normalized Correlation Coefficient.

NormalizedCorrelation Coefficient网上翻译为归一化相关系数


这里先不管究竟哪种算法好。

总之,一个pacth跟库中所有正样本比较,算出最大相似度,也跟所有负样本算出最大相似度。

两者结合算出相对相似度和保守相似读。(具体细节看代码)




[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. /* 
  2.  * FerNNClassifier.cpp 
  3.  * 
  4.  *  Created on: Jun 14, 2011 
  5.  *      Author: alantrrs 
  6.  */  
  7.   
  8. #include <FerNNClassifier.h>  
  9.   
  10. using namespace cv;  
  11. using namespace std;  
  12.   
  13. void FerNNClassifier::read(const FileNode& file){  
  14.   ///Classifier Parameters  
  15.   valid = (float)file["valid"];  
  16.   ncc_thesame = (float)file["ncc_thesame"];  
  17.   nstructs = (int)file["num_trees"];//树木的数量,为10  
  18.   structSize = (int)file["num_features"];//每个树的节点数量,为13  
  19.   thr_fern = (float)file["thr_fern"];  
  20.   thr_nn = (float)file["thr_nn"];  
  21.   thr_nn_valid = (float)file["thr_nn_valid"];  
  22. }  
  23.   
  24. /** 
  25.  * 随机产生一个patch的颜色(点位置)比较集 
  26.  * 先验概率初始化 
  27.  */  
  28. void FerNNClassifier::prepare(const vector<Size>& scales){  
  29.   acum = 0;  
  30.   //Initialize test locations for features  
  31.   int totalFeatures = nstructs*structSize;  
  32.   features = vector<vector<Feature> >(scales.size(),vector<Feature> (totalFeatures));  
  33.   RNG& rng = theRNG();  
  34.   float x1f,x2f,y1f,y2f;  
  35.   int x1, x2, y1, y2;  
  36.   for (int i=0;i<totalFeatures;i++){  
  37.       x1f = (float)rng;  
  38.       y1f = (float)rng;  
  39.       x2f = (float)rng;  
  40.       y2f = (float)rng;  
  41.       for (int s=0;s<scales.size();s++){  
  42.           x1 = x1f * scales[s].width;  
  43.           y1 = y1f * scales[s].height;  
  44.           x2 = x2f * scales[s].width;  
  45.           y2 = y2f * scales[s].height;  
  46.           features[s][i] = Feature(x1, y1, x2, y2);//所谓像素比较,就是指两个点的位置。随机产生的,产生后不改变  
  47.       }  
  48.   
  49.   }  
  50.   //Thresholds  
  51.   thrN = 0.5*nstructs;  
  52.   
  53.   //Initialize Posteriors  
  54.   for (int i = 0; i<nstructs; i++) {  
  55.       posteriors.push_back(vector<float>(pow(2.0,structSize), 0));  
  56.       pCounter.push_back(vector<int>(pow(2.0,structSize), 0));  
  57.       nCounter.push_back(vector<int>(pow(2.0,structSize), 0));  
  58.   }  
  59. }  
  60. /** 
  61.  * 按照预先算好的像素比较集,从image得到具体像素来计算像素比较,作为特征输出。一个图,一个缩放尺度,对应10棵树的特征 
  62.  * image:图像矩阵,存放像素信息 
  63.  * scale_idx:缩放尺寸 
  64.  * fern:算出特征值放这里 
  65.  */  
  66. void FerNNClassifier::getFeatures(const cv::Mat& image,const int& scale_idx, vector<int>& fern){  
  67.   int leaf;  
  68.   for (int t=0;t<nstructs;t++){  
  69.       leaf=0;  
  70.       for (int f=0; f<structSize; f++){  
  71.           leaf = (leaf << 1) + features[scale_idx][t*nstructs+f](image);//feature结构体存储的是两个点的位置  
  72.           //返回的patch图像片在(y1,x1)和(y2, x2)点的像素比较值,返回0或者1  
  73.           //然后leaf就记录了这13位的二进制代码,作为特征  
  74.       }  
  75.       fern[t]=leaf;//fern是存储10个13位二进制码的数组,表示一个patch的特征  
  76.   }  
  77. }  
  78. /** 
  79.  * 算出某些(13个)特征在所有(13棵)树的先验概率和 
  80.  */  
  81. float FerNNClassifier::measure_forest(vector<int> fern) {  
  82.   float votes = 0;  
  83.   for (int i = 0; i < nstructs; i++) {  
  84.       votes += posteriors[i][fern[i]];//一个棵对一个特征有一定的权值,就是10个概率相加  
  85.   }  
  86.   return votes;  
  87. }  
  88. /* 
  89.  * 如果正样本或者负样本的数量变化了,重现计算这个特征的先验概率 
  90.  * pCounter[i][idx]对于第i棵树,含有idx特征的正样本的数量 
  91.  * nCounter[i][idx]对于第i棵树,含有idx特征的负样本的数量 
  92.  */  
  93. void FerNNClassifier::update(const vector<int>& fern, int C, int N) {  
  94.   int idx;  
  95.   for (int i = 0; i < nstructs; i++) {  
  96.       idx = fern[i];  
  97.       (C==1) ? pCounter[i][idx] += N : nCounter[i][idx] += N;  
  98.      // pCounter[i][idx] 在第i棵树上,含有特征idx的正样本的数量  
  99.       if (pCounter[i][idx]==0) {  
  100.           posteriors[i][idx] = 0;  
  101.       } else {  
  102.           posteriors[i][idx] = ((float)(pCounter[i][idx]))/(pCounter[i][idx] + nCounter[i][idx]);  
  103.       }  
  104.   }  
  105. }  
  106. /* 
  107.  * 输入已经一些打好标签(标志着是正还是负样本)的特征值,来更新先验概率(训练的本质?) 
  108.  */  
  109. void FerNNClassifier::trainF(const vector<std::pair<vector<int>,int> >& ferns,int resample){  
  110.   // Conf = function(2,X,Y,Margin,Bootstrap,Idx)  
  111.   //                 0 1 2 3      4         5  
  112.   //  double *X     = mxGetPr(prhs[1]); -> ferns[i].first  
  113.   //  int numX      = mxGetN(prhs[1]);  -> ferns.size()  
  114.   //  double *Y     = mxGetPr(prhs[2]); ->ferns[i].second  
  115.   //  double thrP   = *mxGetPr(prhs[3]) * nTREES; ->threshold*nstructs  
  116.   //  int bootstrap = (int) *mxGetPr(prhs[4]); ->resample  
  117.   thrP = thr_fern*nstructs;                                                          // int step = numX / 10;  
  118.   //for (int j = 0; j < resample; j++) {                      // for (int j = 0; j < bootstrap; j++) {  
  119.       for (int i = 0; i < ferns.size(); i++){               //   for (int i = 0; i < step; i++) {  
  120.                                                             //     for (int k = 0; k < 10; k++) {  
  121.                                                             //       int I = k*step + i;//box index  
  122.                                                             //       double *x = X+nTREES*I; //tree index  
  123.           if(ferns[i].second==1){                           //       if (Y[I] == 1) {  
  124.               if(measure_forest(ferns[i].first)<=thrP)      //         if (measure_forest(x) <= thrP)  
  125.                 update(ferns[i].first,1,1);                 //             update(x,1,1);  
  126.           }else{                                            //        }else{  
  127.               if (measure_forest(ferns[i].first) >= thrN)   //         if (measure_forest(x) >= thrN)  
  128.                 update(ferns[i].first,0,1);                 //             update(x,0,1);  
  129.           }  
  130.       }  
  131.   //}  
  132. }  
  133.   
  134. void FerNNClassifier::trainNN(const vector<cv::Mat>& nn_examples){  
  135.   float conf,dummy;  
  136.   vector<int> y(nn_examples.size(),0);  
  137.   y[0]=1;//只有一个等于1啊,什么意思呢 ?只有第一个正样本?  
  138.   vector<int> isin;  
  139.   for (int i=0;i<nn_examples.size();i++){                          //  For each example  
  140.       NNConf(nn_examples[i],isin,conf,dummy);                      //  Measure Relative similarity  
  141.       if (y[i]==1 && conf<=thr_nn){                                //    if y(i) == 1 && conf1 <= tld.model.thr_nn % 0.65  
  142.           if (isin[1]<0){                                          //      if isnan(isin(2))  
  143.               pEx = vector<Mat>(1,nn_examples[i]);                 //        tld.pex = x(:,i);  
  144.               continue;                                            //        continue;  
  145.           }                                                        //      end  
  146.           //pEx.insert(pEx.begin()+isin[1],nn_examples[i]);        //      tld.pex = [tld.pex(:,1:isin(2)) x(:,i) tld.pex(:,isin(2)+1:end)]; % add to model  
  147.           pEx.push_back(nn_examples[i]);  
  148.       }                                                            //    end  
  149.       if(y[i]==0 && conf>0.5)                                      //  if y(i) == 0 && conf1 > 0.5  
  150.         nEx.push_back(nn_examples[i]);                             //    tld.nex = [tld.nex x(:,i)];  
  151.   
  152.   }                                                                 //  end  
  153.   acum++;  
  154.   printf("%d. Trained NN examples: %d positive %d negative\n",acum,(int)pEx.size(),(int)nEx.size());  
  155. }                                                                  //  end  
  156.   
  157. /** 
  158.  * 这是nn分类起的核心,分类的根据就是根据相似度的值来分的 
  159.  * rsconf 相似度 
  160.  * csconf 保守相似度 
  161.  */  
  162. void FerNNClassifier::NNConf(const Mat& example, vector<int>& isin,float& rsconf,float& csconf){  
  163.   /*Inputs: 
  164.    * -NN Patch 
  165.    * Outputs: 
  166.    * -Relative Similarity (rsconf), Conservative Similarity (csconf), In pos. set|Id pos set|In neg. set (isin) 
  167.    */  
  168.   isin=vector<int>(3,-1);  
  169.   if (pEx.empty()){ //if isempty(tld.pex) % IF positive examples in the model are not defined THEN everything is negative  
  170.       rsconf = 0; //    conf1 = zeros(1,size(x,2));  
  171.       csconf=0;  
  172.       return;  
  173.   }  
  174.   if (nEx.empty()){ //if isempty(tld.nex) % IF negative examples in the model are not defined THEN everything is positive  
  175.       rsconf = 1;   //    conf1 = ones(1,size(x,2));  
  176.       csconf=1;  
  177.       return;  
  178.   }  
  179.   Mat ncc(1,1,CV_32F);  
  180.   float nccP,csmaxP,maxP=0;  
  181.   bool anyP=false;  
  182.   int maxPidx,validatedPart = ceil(pEx.size()*valid);  
  183.   float nccN, maxN=0;  
  184.   bool anyN=false;  
  185.   for (int i=0;i<pEx.size();i++){  
  186.       matchTemplate(pEx[i],example,ncc,CV_TM_CCORR_NORMED);      // measure NCC to positive examples 归一化相关匹配法  
  187.       nccP=(((float*)ncc.data)[0]+1)*0.5;  
  188.       if (nccP>ncc_thesame)  
  189.         anyP=true;  
  190.       if(nccP > maxP){  
  191.           maxP=nccP;  
  192.           maxPidx = i;  
  193.           if(i<validatedPart)  
  194.             csmaxP=maxP;  
  195.       }  
  196.   }  
  197.   for (int i=0;i<nEx.size();i++){  
  198.       matchTemplate(nEx[i],example,ncc,CV_TM_CCORR_NORMED);     //measure NCC to negative examples  
  199.       nccN=(((float*)ncc.data)[0]+1)*0.5;  
  200.       if (nccN>ncc_thesame)  
  201.         anyN=true;  
  202.       if(nccN > maxN)  
  203.         maxN=nccN;  
  204.   }  
  205.   //set isin  
  206.   if (anyP) isin[0]=1;  //if he query patch is highly correlated with any positive patch in the model then it is considered to be one of them  
  207.   isin[1]=maxPidx;      //get the index of the maximall correlated positive patch  
  208.   if (anyN) isin[2]=1;  //if  the query patch is highly correlated with any negative patch in the model then it is considered to be one of them  
  209.   //Measure Relative Similarity  
  210.   float dN=1-maxN;  
  211.   float dP=1-maxP;  
  212.   rsconf = (float)dN/(dN+dP);  
  213.   //Measure Conservative Similarity  
  214.   dP = 1 - csmaxP;  
  215.   csconf =(float)dN / (dN + dP);  
  216. }  
  217. /** 
  218.  * 根据新的负样本,重新计算fern特征的阈值 和 nn分类器的阈值 
  219.  * 阈值要比所有的负样本的自信度要大 
  220.  */  
  221. void FerNNClassifier::evaluateTh(const vector<pair<vector<int>,int> >& nXT,const vector<cv::Mat>& nExT){  
  222. float fconf;  
  223.   for (int i=0;i<nXT.size();i++){  
  224.     fconf = (float) measure_forest(nXT[i].first)/nstructs;  
  225.     if (fconf>thr_fern)  
  226.       thr_fern=fconf;  
  227. }  
  228.   vector <int> isin;  
  229.   float conf,dummy;  
  230.   for (int i=0;i<nExT.size();i++){  
  231.       NNConf(nExT[i],isin,conf,dummy);  
  232.       if (conf>thr_nn)  
  233.         thr_nn=conf;  
  234.   }  
  235.   if (thr_nn>thr_nn_valid)  
  236.     thr_nn_valid = thr_nn;  
  237. }  
  238.   
  239. void FerNNClassifier::show(){  
  240.   Mat examples((int)pEx.size()*pEx[0].rows,pEx[0].cols,CV_8U);  
  241.   double minval;  
  242.   Mat ex(pEx[0].rows,pEx[0].cols,pEx[0].type());  
  243.   for (int i=0;i<pEx.size();i++){  
  244.     minMaxLoc(pEx[i],&minval);  
  245.     pEx[i].copyTo(ex);  
  246.     ex = ex-minval;  
  247.     Mat tmp = examples.rowRange(Range(i*pEx[i].rows,(i+1)*pEx[i].rows));  
  248.     ex.convertTo(tmp,CV_8U);  
  249.   }  
  250.   imshow("Examples",examples);  
  251. }  



注:

原作者是用matlab实现的,我分析的源码是其他大神用c++和OpenCV实现的,源码可以从

https://github.com/arthurv/OpenTLD或者https://github.com/alantrrs/OpenTLD下载

本序列参考了zouxy09同学的序列文章,在此表示感谢

http://blog.csdn.NET/zouxy09/article/details/7893011

0 0
原创粉丝点击