压缩跟踪Compressive Tracking源码理解

在前面一个介绍《Real-Time Compressive Tracking》这个paper的感知跟踪算法的博文中,我说过后面会学习下它的C++源码,但是当时因为有些事,所以就没有看了。今天,上到博客,看到一朋友在这个博文中评论说,有个地方不太明白。然后,觉得该履行自己的承诺,去学习学习源码了。所以刚才就花了几个小时去看了C++的源码,做了详细的注释。希望对大家有点帮助。在这也感谢这位朋友。当然,因为自己也刚刚接触这个领域,所以也有很多地方我也看不懂或者理解错了,也渴望大家的指导。

      下面是这个算法的工程网站:里面包含了上面这篇论文、MatlabC++版本的代码,还有测试数据、demo等。

            http://www4.comp.polyu.edu.hk/~cslzhang/CT/CT.htm

       之前自己学习这个《Real-Time Compressive Tracking》介绍的感知跟踪算法:

            http://blog.csdn.net/zouxy09/article/details/8118360

 

       非常感谢Kaihua等的paperReal-Time Compressive Tracking》,非常感谢它的C++代码的编写和贡献者Yang Xian

       这个C++代码编写的非常简洁、清晰和漂亮。另外,经原作者提示,代码注释中不明白的地方(我打问号的地方)可以看本博文的原作者的评论。非常感谢Yang Xian的指导。

       好了,废话不多说了。下面是自己注释的源码。因为代码编写的流程非常清晰,所以我就不总结流程了。这个工程包含三个文件:CompressiveTracker.cppCompressiveTracker.hRunTracker.cpp,其中因为RunTracker.cppTLD算法中的run_tld.cpp差不多,我这里就不注释了,大家可以参考我之前的:

        TLDTracking-Learning-Detection)学习与源码理解之(四)

            http://blog.csdn.net/zouxy09/article/details/7893032

 

下面是具体的源码:

CompressiveTracker.h

[cpp]  view plain copy
  1. /************************************************************************ 
  2. * File: CompressiveTracker.h 
  3. * Brief: C++ demo for paper: Kaihua Zhang, Lei Zhang, Ming-Hsuan Yang,"Real-Time Compressive Tracking," ECCV 2012. 
  4. * Version: 1.0 
  5. * Author: Yang Xian 
  6. * Email: [email protected] 
  7. * Date: 2012/08/03 
  8. * History: 
  9. * Revised by Kaihua Zhang on 14/8/2012 
  10. * Email: [email protected] 
  11. * Homepage: http://www4.comp.polyu.edu.hk/~cskhzhang/ 
  12. ************************************************************************/  
  13. //这是一个比较常用的C/C++杂注,只要在头文件的最开始加入这条杂注,就能够保证头文件只被插入和编译一次  
  14. #pragma once  
  15. #include <opencv2/opencv.hpp>  
  16. #include <vector>  
  17.   
  18. using std::vector;  
  19. using namespace cv;  
  20. //---------------------------------------------------  
  21. class CompressiveTracker  
  22. {  
  23. public:  
  24.     CompressiveTracker(void);  
  25.     ~CompressiveTracker(void);  
  26.   
  27. private:  
  28.     int featureMinNumRect;  
  29.     int featureMaxNumRect;  
  30.     int featureNum;  //每个box的harr特征个数(也就是弱分类器个数)  
  31.     vector<vector<Rect>> features;  
  32.     vector<vector<float>> featuresWeight;  
  33.     int rOuterPositive; //在离上一帧跟踪到的目标位置的距离小于rOuterPositive的范围内采集 正样本  
  34.     vector<Rect> samplePositiveBox;  //采集的正样本box集  
  35.     vector<Rect> sampleNegativeBox;  //采集的负样本box集  
  36.     int rSearchWindow;   //扫描窗口的大小,或者说检测box的大小  
  37.     Mat imageIntegral;   //图像的积分图  
  38.     Mat samplePositiveFeatureValue;  //采集的正样本的harr特征值  
  39.     Mat sampleNegativeFeatureValue;  //采集的负样本的harr特征值  
  40.     //对每个样本z(m维向量),它的低维表示是v(n维向量,n远小于m)。假定v中的各元素是独立分布的。  
  41.     //假定在分类器H(v)中的条件概率p(vi|y=1)和p(vi|y=0)属于高斯分布,并且可以用以下四个参数来描述:  
  42.     //分别是描述正负样本的高斯分布的均值u和方差sigma  
  43.     vector<float> muPositive;  
  44.     vector<float> sigmaPositive;  
  45.     vector<float> muNegative;  
  46.     vector<float> sigmaNegative;  
  47.     float learnRate;   //学习速率,控制分类器参数更新的步长  
  48.     vector<Rect> detectBox;  //需要检测的box  
  49.     Mat detectFeatureValue;  
  50.     RNG rng;  //随机数  
  51.   
  52. private:  
  53.     void HaarFeature(Rect& _objectBox, int _numFeature);  
  54.     void sampleRect(Mat& _image, Rect& _objectBox, float _rInner, float _rOuter, int _maxSampleNum, vector<Rect>& _sampleBox);  
  55.     void sampleRect(Mat& _image, Rect& _objectBox, float _srw, vector<Rect>& _sampleBox);  
  56.     void getFeatureValue(Mat& _imageIntegral, vector<Rect>& _sampleBox, Mat& _sampleFeatureValue);  
  57.     void classifierUpdate(Mat& _sampleFeatureValue, vector<float>& _mu, vector<float>& _sigma, float _learnRate);  
  58.     void radioClassifier(vector<float>& _muPos, vector<float>& _sigmaPos, vector<float>& _muNeg, vector<float>& _sigmaNeg,  
  59.                         Mat& _sampleFeatureValue, float& _radioMax, int& _radioMaxIndex);  
  60. public:  
  61.     void processFrame(Mat& _frame, Rect& _objectBox);  
  62.     void init(Mat& _frame, Rect& _objectBox);  
  63. };  


CompressiveTracker.cpp

[cpp]  view plain copy
  1. #include "CompressiveTracker.h"  
  2. #include <math.h>  
  3. #include <iostream>  
  4. using namespace cv;  
  5. using namespace std;  
  6.   
  7. //------------------------------------------------  
  8. //构造函数,初始化各参数  
  9. CompressiveTracker::CompressiveTracker(void)  
  10. {  
  11.     featureMinNumRect = 2;  
  12.     featureMaxNumRect = 4;  // number of rectangle from 2 to 4  
  13.     featureNum = 50;    // number of all weaker classifiers, i.e,feature pool  
  14.     rOuterPositive = 4; // radical scope of positive samples  
  15.     rSearchWindow = 25; // size of search window  
  16.     muPositive = vector<float>(featureNum, 0.0f);  
  17.     muNegative = vector<float>(featureNum, 0.0f);  
  18.     sigmaPositive = vector<float>(featureNum, 1.0f);  
  19.     sigmaNegative = vector<float>(featureNum, 1.0f);  
  20.     learnRate = 0.85f;  // Learning rate parameter  
  21. }  
  22.   
  23. CompressiveTracker::~CompressiveTracker(void)  
  24. {  
  25. }  
  26.   
  27. //通过积分图来计算采集到的每一个样本的harr特征,这个特征通过与featuresWeight来相乘  
  28. //就相当于投影到随机测量矩阵中了,也就是进行稀疏表达了。这里不明白的话,可以看下  
  29. //论文中的图二,就比较直观了。  
  30. //还有一点:实际上这里采用的不属于真正的harr特征,我博客中翻译有误。这里计算的是  
  31. //在box中采样得到的不同矩形框的灰度加权求和(当权重是负数的时候就是灰度差)  
  32. //当为了表述方便,我下面都用harr特征来描述。  
  33. //每一个样本有50个harr特征,每一个harr特征是由2到3个随机选择的矩形框来构成的,  
  34. //对这些矩形框的灰度加权求和作为这一个harr特征的特征值。  
  35. void CompressiveTracker::HaarFeature(Rect& _objectBox, int _numFeature)  
  36. /*Description: compute Haar features 
  37.   Arguments: 
  38.   -_objectBox: [x y width height] object rectangle 
  39.   -_numFeature: total number of features. The default is 50. 
  40. */  
  41. {  
  42.     //_numFeature是一个样本box的harr特征个数,共50个。而上面说到,  
  43.     //每一个harr特征是由2到3个随机选择的矩形框(vector<Rect>()类型)来构成的。  
  44.     features = vector<vector<Rect>>(_numFeature, vector<Rect>());  
  45.     //每一个反应特征的矩形框对应于一个权重,实际上就是随机测量矩阵中相应的元素,用它来与对应的特征  
  46.     //相乘,表示以权重的程度来感知这个特征。换句话说,featuresWeight就是随机测量矩阵。  
  47.     //这个矩阵的元素的赋值看论文中的第二部分。或者也可以参考下我的博文:(呵呵,好像博文也没说清楚)  
  48.     //http://blog.csdn.net/zouxy09/article/details/8118360  
  49.     featuresWeight = vector<vector<float>>(_numFeature, vector<float>());  
  50.       
  51.     //numRect是每个特征的矩形框个数还是论文中说的随机测量矩阵中的s?还有兼备两种功能?  
  52.     //论文中说s取2或者3时,矩阵就满足Johnson-Lindenstrauss推论。  
  53.     int numRect;  
  54.     Rect rectTemp;  
  55.     float weightTemp;  
  56.         
  57.     for (int i=0; i<_numFeature; i++)  
  58.     {  
  59.         //如何生成服从某个概率分布的随机数(或者说 sample)的问题。  
  60.         //比如,你想要从一个服从正态分布的随机变量得到 100 个样本,那么肯定抽到接近其均值的样本的  
  61.         //概率要大许多,从而导致抽到的样本很多是集中在那附近的。  
  62.         //rng.uniform()返回一个从[ 1,2)范围均匀采样的随机数,即在[ 1,2)内服从均匀分布(取不同值概率相同)  
  63.         //那么下面的功能就是得到[2,4)范围的随机数,然后用cvFloor返回不大于参数的最大整数值,那要么是2,要么是3。  
  64.         numRect = cvFloor(rng.uniform((double)featureMinNumRect, (double)featureMaxNumRect));  
  65.           
  66.         //int c = 1;  
  67.         for (int j=0; j<numRect; j++)  
  68.         {  
  69.             //我在一个box中随机生成一个矩形框,那和你这个box的x和y坐标就无关了,但我必须保证我选择  
  70.             //的这个矩形框不会超出你这个box的范围啊,是吧  
  71.             //但这里的3和下面的2是啥意思呢?我就不懂了,个人理解是为了避免这个矩形框太靠近box的边缘了  
  72.             //要离边缘最小2个像素,不知道这样理解对不对,恳请指导  
  73.             rectTemp.x = cvFloor(rng.uniform(0.0, (double)(_objectBox.width - 3)));  
  74.             rectTemp.y = cvFloor(rng.uniform(0.0, (double)(_objectBox.height - 3)));  
  75.             //cvCeil 返回不小于参数的最小整数值  
  76.             rectTemp.width = cvCeil(rng.uniform(0.0, (double)(_objectBox.width - rectTemp.x - 2)));  
  77.             rectTemp.height = cvCeil(rng.uniform(0.0, (double)(_objectBox.height - rectTemp.y - 2)));  
  78.             //保存得到的特征模板。注意哦,这里的矩形框是相对于box的相对位置哦,不是针对整幅图像的哦  
  79.             features[i].push_back(rectTemp);  
  80.               
  81.             //weightTemp = (float)pow(-1.0, c);  
  82.             //pow(-1.0, c)也就是-1的c次方,而c随机地取0或者1,也就是说weightTemp是随机的正或者负。  
  83.             //随机测量矩阵中,矩阵元素有三种,sqrt(s)、-sqrt(s)和零。为正和为负的概率是相等的,  
  84.             //这就是为什么是[2,4)均匀采样的原因,就是取0或者1概率一样。  
  85.             //但是这里为什么是sqrt(s)分之一呢?还有什么时候是0呢?论文中是0的概率不是挺大的吗?  
  86.             //没有0元素,哪来的稀疏表达和压缩呢?不懂,恳请指导!(当然稀疏表达的另一个好处  
  87.             //就是只需保存非零元素。但这里和这个有关系吗?)  
  88.             weightTemp = (float)pow(-1.0, cvFloor(rng.uniform(0.0, 2.0))) / sqrt(float(numRect));  
  89.               
  90.             //保存每一个特征模板对应的权重  
  91.             featuresWeight[i].push_back(weightTemp);  
  92.              
  93.         }  
  94.     }  
  95. }  
  96.   
  97. //在上一帧跟踪的目标box的周围采集若干正样本和负样本,来初始化或者更新分类器的  
  98. void CompressiveTracker::sampleRect(Mat& _image, Rect& _objectBox, float _rInner, float _rOuter, int _maxSampleNum, vector<Rect>& _sampleBox)  
  99. /* Description: compute the coordinate of positive and negative sample image templates 
  100.    Arguments: 
  101.    -_image:        processing frame 
  102.    -_objectBox:    recent object position  
  103.    -_rInner:       inner sampling radius 
  104.    -_rOuter:       Outer sampling radius 
  105.    -_maxSampleNum: maximal number of sampled images 
  106.    -_sampleBox:    Storing the rectangle coordinates of the sampled images. 
  107. */  
  108. {  
  109.     int rowsz = _image.rows - _objectBox.height - 1;  
  110.     int colsz = _image.cols - _objectBox.width - 1;  
  111.     //我们是在上一帧跟踪的目标box的周围采集正样本和负样本的,而这个周围是通过以  
  112.     //这个目标为中心的两个圆来表示,这两个圆的半径是_rInner和_rOuter。  
  113.     //我们在离上一帧跟踪的目标box的小于_rInner距离的范围内采集正样本,  
  114.     //在大于_rOuter距离的范围内采集负样本(论文中还有一个上界,但好像  
  115.     //这里没有,其实好像也没什么必要噢)  
  116.     float inradsq = _rInner*_rInner;  
  117.     float outradsq = _rOuter*_rOuter;  
  118.       
  119.     int dist;  
  120.   
  121.     //这四个是为了防止采集的框超出图像范围的,对采集的box的x和y坐标做限制  
  122.     int minrow = max(0,(int)_objectBox.y-(int)_rInner);  
  123.     int maxrow = min((int)rowsz-1,(int)_objectBox.y+(int)_rInner);  
  124.     int mincol = max(0,(int)_objectBox.x-(int)_rInner);  
  125.     int maxcol = min((int)colsz-1,(int)_objectBox.x+(int)_rInner);  
  126.           
  127.       
  128.     int i = 0;  
  129.     //分母相当于x能采集的范围乘以y能采集的范围,也就是可以采集的最大box个数,  
  130.     //那么_maxSampleNum(我们需要采集的box的最大个数)肯定得小于或者等于它。  
  131.     //那这个prob是干嘛的呢?到下面用到它的地方说  
  132.     float prob = ((float)(_maxSampleNum))/(maxrow-minrow+1)/(maxcol-mincol+1);  
  133.   
  134.     int r;  
  135.     int c;  
  136.       
  137.     _sampleBox.clear();//important  
  138.     Rect rec(0,0,0,0);  
  139.   
  140.     for( r=minrow; r<=(int)maxrow; r++ )  
  141.         for( c=mincol; c<=(int)maxcol; c++ ){  
  142.             //计算生成的box到目标box的距离  
  143.             dist = (_objectBox.y-r)*(_objectBox.y-r) + (_objectBox.x-c)*(_objectBox.x-c);  
  144.   
  145.             //后两个条件是保证距离需要在_rInner和_rOuter的范围内  
  146.             //那么rng.uniform(0.,1.) < prob 这个是干嘛的呢?  
  147.             //连着上面看,如果_maxSampleNum大于那个最大个数,prob就大于1,这样,  
  148.             //rng.uniform(0.,1.) < prob这个条件就总能满足,表示在这个范围产生的  
  149.             //所以box我都要了(因为我本身想要更多的,但是你给不了我那么多,那么你能给的,我肯定全要了)。  
  150.             //那如果你给的太多了,我不要那么多,也就是prob<1,那我就随机地跳几个走好了  
  151.             if( rng.uniform(0.,1.) < prob && dist < inradsq && dist >= outradsq ){  
  152.   
  153.                 rec.x = c;  
  154.                 rec.y = r;  
  155.                 rec.width = _objectBox.width;  //没有做尺度不变?至此至终box的大小都没变化  
  156.                 rec.height= _objectBox.height;  
  157.                   
  158.                 _sampleBox.push_back(rec);                
  159.                   
  160.                 i++;  
  161.             }  
  162.         }  
  163.       
  164.         _sampleBox.resize(i);  
  165.           
  166. }  
  167.   
  168. //这个sampleRect的重载函数是用来在上一帧跟踪的目标box的周围(距离小于_srw)采集若干box来待检测。  
  169. //与上面的那个不一样,上面那个是在这一帧已经检测出目标的基础上,采集正负样本来更新分类器的。  
  170. //上面那个属于论文中提到的算法的第四个步骤,这个是第一个步骤。然后过程差不多,没什么好说的了  
  171. void CompressiveTracker::sampleRect(Mat& _image, Rect& _objectBox, float _srw, vector<Rect>& _sampleBox)  
  172. /* Description: Compute the coordinate of samples when detecting the object.*/  
  173. {  
  174.     int rowsz = _image.rows - _objectBox.height - 1;  
  175.     int colsz = _image.cols - _objectBox.width - 1;  
  176.     float inradsq = _srw*_srw;        
  177.   
  178.     int dist;  
  179.   
  180.     int minrow = max(0,(int)_objectBox.y-(int)_srw);  
  181.     int maxrow = min((int)rowsz-1,(int)_objectBox.y+(int)_srw);  
  182.     int mincol = max(0,(int)_objectBox.x-(int)_srw);  
  183.     int maxcol = min((int)colsz-1,(int)_objectBox.x+(int)_srw);  
  184.   
  185.     int i = 0;  
  186.   
  187.     int r;  
  188.     int c;  
  189.   
  190.     Rect rec(0,0,0,0);  
  191.     _sampleBox.clear();//important  
  192.   
  193.     for( r=minrow; r<=(int)maxrow; r++ )  
  194.         for( c=mincol; c<=(int)maxcol; c++ ){  
  195.             dist = (_objectBox.y-r)*(_objectBox.y-r) + (_objectBox.x-c)*(_objectBox.x-c);  
  196.   
  197.             if( dist < inradsq ){  
  198.   
  199.                 rec.x = c;  
  200.                 rec.y = r;  
  201.                 rec.width = _objectBox.width;  
  202.                 rec.height= _objectBox.height;  
  203.   
  204.                 _sampleBox.push_back(rec);                
  205.   
  206.                 i++;  
  207.             }  
  208.         }  
  209.       
  210.         _sampleBox.resize(i);  
  211.   
  212. }  
  213.   
  214. // Compute the features of samples  
  215. //通过积分图来计算采集到的每一个样本的harr特征,这个特征通过与featuresWeight来相乘  
  216. //就相当于投影到随机测量矩阵中了,也就是进行稀疏表达了。这里不明白的话,可以看下  
  217. //论文中的图二,就比较直观了。所以这里得到的是:每个样本的稀疏表达后的harr特征。  
  218. //还有一点:实际上这里采用的不属于真正的harr特征,我博客中翻译有误。这里计算的是  
  219. //在box中采样得到的不同矩形框的灰度加权求和  
  220. void CompressiveTracker::getFeatureValue(Mat& _imageIntegral, vector<Rect>& _sampleBox, Mat& _sampleFeatureValue)  
  221. {  
  222.     int sampleBoxSize = _sampleBox.size();  
  223.     _sampleFeatureValue.create(featureNum, sampleBoxSize, CV_32F);  
  224.     float tempValue;  
  225.     int xMin;  
  226.     int xMax;  
  227.     int yMin;  
  228.     int yMax;  
  229.   
  230.     for (int i=0; i<featureNum; i++)  
  231.     {  
  232.         for (int j=0; j<sampleBoxSize; j++)  
  233.         {  
  234.             tempValue = 0.0f;  
  235.             for (size_t k=0; k<features[i].size(); k++)  
  236.             {  
  237.                 //features中保存的特征模板(矩形框)是相对于box的相对位置的,  
  238.                 //所以需要加上box的坐标才是其在整幅图像中的坐标  
  239.                 xMin = _sampleBox[j].x + features[i][k].x;  
  240.                 xMax = _sampleBox[j].x + features[i][k].x + features[i][k].width;  
  241.                 yMin = _sampleBox[j].y + features[i][k].y;  
  242.                 yMax = _sampleBox[j].y + features[i][k].y + features[i][k].height;  
  243.                 //通过积分图来快速计算一个矩形框的像素和,积分图不了解的话,可以看下我的这个博文:  
  244.                 //http://blog.csdn.net/zouxy09/article/details/7929570  
  245.                 //那么这里tempValue就是经过稀释矩阵加权后的灰度和了。  
  246.                 //每一个harr特征是由2到3个矩形框来构成的,对这些矩形框的灰度加权求和  
  247.                 //作为这一个harr特征的特征值。然后一个样本有50个harr特征  
  248.                 tempValue += featuresWeight[i][k] *   
  249.                     (_imageIntegral.at<float>(yMin, xMin) +  
  250.                     _imageIntegral.at<float>(yMax, xMax) -  
  251.                     _imageIntegral.at<float>(yMin, xMax) -  
  252.                     _imageIntegral.at<float>(yMax, xMin));  
  253.             }  
  254.             _sampleFeatureValue.at<float>(i,j) = tempValue;  
  255.         }  
  256.     }  
  257. }  
  258.   
  259. // Update the mean and variance of the gaussian classifier  
  260. //论文中是通过用高斯分布去描述样本的每一个harr特征的概率分布的。高斯分布就可以通过期望和方差  
  261. //两个参数来表征。然后通过正负样本的每一个harr特征高斯概率分布的对数比值,来构建分类器决策  
  262. //该box属于目标还是背景。这里计算新采集到的正负样本的特征的期望和标准差,并用其来更新分类器  
  263. void CompressiveTracker::classifierUpdate(Mat& _sampleFeatureValue, vector<float>& _mu, vector<float>& _sigma, float _learnRate)  
  264. {  
  265.     Scalar muTemp;  
  266.     Scalar sigmaTemp;  
  267.       
  268.     for (int i=0; i<featureNum; i++)  
  269.     {  
  270.         //计算所有正样本或者负样本的某个harr特征的期望和标准差  
  271.         meanStdDev(_sampleFeatureValue.row(i), muTemp, sigmaTemp);  
  272.          
  273.         //这个模型参数更新的公式见论文的公式6  
  274.         _sigma[i] = (float)sqrt( _learnRate*_sigma[i]*_sigma[i] + (1.0f-_learnRate)*sigmaTemp.val[0]*sigmaTemp.val[0]   
  275.         + _learnRate*(1.0f-_learnRate)*(_mu[i]-muTemp.val[0])*(_mu[i]-muTemp.val[0]));  // equation 6 in paper  
  276.   
  277.         _mu[i] = _mu[i]*_learnRate + (1.0f-_learnRate)*muTemp.val[0];   // equation 6 in paper  
  278.     }  
  279. }  
  280.   
  281. // Compute the ratio classifier   
  282. void CompressiveTracker::radioClassifier(vector<float>& _muPos, vector<float>& _sigmaPos, vector<float>& _muNeg, vector<float>& _sigmaNeg,  
  283.                                          Mat& _sampleFeatureValue, float& _radioMax, int& _radioMaxIndex)  
  284. {  
  285.     float sumRadio;  
  286.     //FLT_MAX是最大的浮点数的宏定义,那么-FLT_MAX就是最小的浮点数了  
  287.     //这个是拿来存放 那么多box中最大的分类分数的  
  288.     _radioMax = -FLT_MAX;   
  289.     //这个是对应于上面那个,是存放分类分数最大的那个box的  
  290.     _radioMaxIndex = 0;  
  291.     float pPos;  
  292.     float pNeg;  
  293.     int sampleBoxNum = _sampleFeatureValue.cols;  
  294.   
  295.     for (int j=0; j<sampleBoxNum; j++)  //每帧采样得到的需要检测的box  
  296.     {  
  297.         sumRadio = 0.0f;  
  298.         for (int i=0; i<featureNum; i++)  //每个box的需要匹配的特征数  
  299.         {  
  300.             //计算每个特征的概率,特征分布近似于高斯分布,故将描述该特征的均值和标准差代入高斯模型就可以  
  301.             //得到,分别在正样本和负样本的基础上,出现该特征的概率是多少。如果正样本时候的概率大,那么  
  302.             //我们就说,这个特征对应的样本是正样本。数学上比较大小,就是减法或者除法了,这里是取对数比值  
  303.             pPos = exp( (_sampleFeatureValue.at<float>(i,j)-_muPos[i])*(_sampleFeatureValue.at<float>(i,j)-_muPos[i]) / -(2.0f*_sigmaPos[i]*_sigmaPos[i]+1e-30) ) / (_sigmaPos[i]+1e-30);  
  304.             pNeg = exp( (_sampleFeatureValue.at<float>(i,j)-_muNeg[i])*(_sampleFeatureValue.at<float>(i,j)-_muNeg[i]) / -(2.0f*_sigmaNeg[i]*_sigmaNeg[i]+1e-30) ) / (_sigmaNeg[i]+1e-30);  
  305.               
  306.             //paper的方程4:计算分类结果,得到一个分数,这个分数是由一个样本或者box的50个特征(弱分类)  
  307.             //进入分类器分类得到的结果总和(强分类?)。表征的是目前这个box的特征属于正样本(目标)的  
  308.             //可能性大小。哪个分数最大,自然我就认为你是目标了。(当然,在具体应用中需要加一些策略去  
  309.             //改善误跟踪的情况。例如如果最高的分数都达不到一个阈值,那就不存在目标等)  
  310.             sumRadio += log(pPos+1e-30) - log(pNeg+1e-30);  // equation 4  
  311.         }  
  312.         if (_radioMax < sumRadio) //拿到最大的分数和相应的box索引  
  313.         {  
  314.             _radioMax = sumRadio;  
  315.             _radioMaxIndex = j;  
  316.         }  
  317.     }  
  318. }  
  319.   
  320. //传入第一帧和要跟踪的目标box(由文件读入或者用户鼠标框选),来初始化分类器  
  321. void CompressiveTracker::init(Mat& _frame, Rect& _objectBox)  
  322. {  
  323.     // compute feature template  
  324.     //计算box的harr特征模板,先存着  
  325.     HaarFeature(_objectBox, featureNum);  
  326.   
  327.     // compute sample templates  
  328.     //因为这是第一帧,目标box是由由文件读入或者用户鼠标框选的,是已知的,  
  329.     //所以我们通过在这个目标box周围,采集正样本和负样本来初始化我们的分类器  
  330.     sampleRect(_frame, _objectBox, rOuterPositive, 0, 1000000, samplePositiveBox);  
  331.     sampleRect(_frame, _objectBox, rSearchWindow*1.5, rOuterPositive+4.0, 100, sampleNegativeBox);  
  332.   
  333.     //计算积分图,用以快速的计算harr特征  
  334.     integral(_frame, imageIntegral, CV_32F);  
  335.   
  336.     //通过上面的积分图,计算我们采样到的正负样本的box的harr特征  
  337.     getFeatureValue(imageIntegral, samplePositiveBox, samplePositiveFeatureValue);  
  338.     getFeatureValue(imageIntegral, sampleNegativeBox, sampleNegativeFeatureValue);  
  339.       
  340.     //通过上面的正负样本的特征来初始化分类器  
  341.     classifierUpdate(samplePositiveFeatureValue, muPositive, sigmaPositive, learnRate);  
  342.     classifierUpdate(sampleNegativeFeatureValue, muNegative, sigmaNegative, learnRate);  
  343. }  
  344.   
  345. //传入上一帧跟踪到的box,来处理新的一帧  
  346. void CompressiveTracker::processFrame(Mat& _frame, Rect& _objectBox)  
  347. {  
  348.     // predict  
  349.     //在上一帧跟踪到的boxbox周围,采集需要检测的box框  
  350.     sampleRect(_frame, _objectBox, rSearchWindow, detectBox);  
  351.     //计算这一帧的积分图  
  352.     integral(_frame, imageIntegral, CV_32F);  
  353.     //用积分图来计算上面采集到的每个box的harr特征  
  354.     getFeatureValue(imageIntegral, detectBox, detectFeatureValue);  
  355.     int radioMaxIndex;  
  356.     float radioMax;  
  357.     //对上面的每个box进行匹配分类  
  358.     radioClassifier(muPositive, sigmaPositive, muNegative, sigmaNegative, detectFeatureValue, radioMax, radioMaxIndex);  
  359.     //得到分数最高的那个目标box  
  360.     _objectBox = detectBox[radioMaxIndex];  
  361.   
  362.     // update  
  363.     //在新跟踪到的这个目标box的周围,采集正样本和负样本来更新我们的分类器  
  364.     sampleRect(_frame, _objectBox, rOuterPositive, 0.0, 1000000, samplePositiveBox);  
  365.     sampleRect(_frame, _objectBox, rSearchWindow*1.5, rOuterPositive+4.0, 100, sampleNegativeBox);  
  366.       
  367.     //通过上面的积分图,计算我们采样到的正负样本的box的harr特征  
  368.     getFeatureValue(imageIntegral, samplePositiveBox, samplePositiveFeatureValue);  
  369.     getFeatureValue(imageIntegral, sampleNegativeBox, sampleNegativeFeatureValue);  
  370.       
  371.     //通过上面的正负样本的特征来更新我们的分类器  
  372.     classifierUpdate(samplePositiveFeatureValue, muPositive, sigmaPositive, learnRate);  
  373.     classifierUpdate(sampleNegativeFeatureValue, muNegative, sigmaNegative, learnRate);  
  374. }  


 

你可能感兴趣的:(压缩跟踪Compressive Tracking源码理解)