现在的位置: 首页 > 综合 > 正文

TLD(Tracking-Learning-Detection)学习与源码理解之(六) .

2013年09月20日 ⁄ 综合 ⁄ 共 16828字 ⁄ 字号 评论关闭

转自:http://blog.csdn.net/zouxy09/article/details/7893081

下面是自己在看论文和这些大牛的分析过程中,对代码进行了一些理解,但是由于自己接触图像处理和机器视觉没多久,另外由于自己编程能力比较弱,所以分析过程可能会有不少的错误,希望各位不吝指正。而且,因为编程很多地方不懂,所以注释得非常乱,还海涵。

TLD.h

  1. #include <opencv2/opencv.hpp>
      
  2. #include <tld_utils.h>
      
  3. #include <LKTracker.h>
      
  4. #include <FerNNClassifier.h>
      
  5. #include <fstream>
      
  6.   
  7.   
  8. //Bounding Boxes
      
  9. struct BoundingBox : public cv::Rect {  
  10.   BoundingBox(){}  
  11.   BoundingBox(cv::Rect r): cv::Rect(r){}   //继承的话需要初始化基类
      
  12. public:  
  13.   float overlap;        //Overlap with current Bounding Box
      
  14.   int sidx;             //scale index
      
  15. };  
  16.   
  17. //Detection structure
      
  18. struct DetStruct {  
  19.     std::vector<int> bb;  
  20.     std::vector<std::vector<int> > patt;  
  21.     std::vector<float> conf1;  
  22.     std::vector<float> conf2;  
  23.     std::vector<std::vector<int> > isin;  
  24.     std::vector<cv::Mat> patch;  
  25.   };  
  26.     
  27. //Temporal structure
      
  28. struct TempStruct {  
  29.     std::vector<std::vector<int> > patt;  
  30.     std::vector<float> conf;  
  31.   };  
  32.   
  33. struct OComparator{  //比较两者重合度
      
  34.   OComparator(const std::vector<BoundingBox>& _grid):grid(_grid){}  
  35.   std::vector<BoundingBox> grid;  
  36.   bool operator()(int idx1,int idx2){  
  37.     return grid[idx1].overlap > grid[idx2].overlap;  
  38.   }  
  39. };  
  40.   
  41. struct CComparator{  //比较两者确信度?
      
  42.   CComparator(const std::vector<float>& _conf):conf(_conf){}  
  43.   std::vector<float> conf;  
  44.   bool operator()(int idx1,int idx2){  
  45.     return conf[idx1]> conf[idx2];  
  46.   }  
  47. };  
  48.   
  49.   
  50. class TLD{  
  51. private:  
  52.   cv::PatchGenerator generator;  //PatchGenerator类用来对图像区域进行仿射变换
      
  53.   FerNNClassifier classifier;  
  54.   LKTracker tracker;  
  55.     
  56.   //下面这些参数通过程序开始运行时读入parameters.yml文件进行初始化
      
  57.   ///Parameters
      
  58.   int bbox_step;  
  59.   int min_win;  
  60.   int patch_size;  
  61.     
  62.   //initial parameters for positive examples
      
  63.   //从第一帧得到的目标的bounding box中(文件读取或者用户框定),经过几何变换得
      
  64.   //到 num_closest_init * num_warps_init 个正样本
      
  65.   int num_closest_init;  //最近邻窗口数 10
      
  66.   int num_warps_init;  //几何变换数目 20
      
  67.   int noise_init;  
  68.   float angle_init;  
  69.   float shift_init;  
  70.   float scale_init;  
  71.     
  72.   ////从跟踪得到的目标的bounding box中,经过几何变换更新正样本(添加到在线模型?)
      
  73.   //update parameters for positive examples
      
  74.   int num_closest_update;  
  75.   int num_warps_update;  
  76.   int noise_update;  
  77.   float angle_update;  
  78.   float shift_update;  
  79.   float scale_update;  
  80.     
  81.   //parameters for negative examples
      
  82.   float bad_overlap;  
  83.   float bad_patches;  
  84.     
  85.   ///Variables
      
  86. //Integral Images  积分图像,用以计算2bitBP特征(类似于haar特征的计算)
      
  87. //Mat最大的优势跟STL很相似,都是对内存进行动态的管理,不需要之前用户手动的管理内存
      
  88.   cv::Mat iisum;  
  89.   cv::Mat iisqsum;  
  90.   float var;  
  91.     
  92. //Training data
      
  93.   //std::pair主要的作用是将两个数据组合成一个数据,两个数据可以是同一类型或者不同类型。
      
  94.   //pair实质上是一个结构体,其主要的两个成员变量是first和second,这两个变量可以直接使用。
      
  95.   //在这里用来表示样本,first成员为 features 特征点数组,second成员为 labels 样本类别标签
      
  96.   std::vector<std::pair<std::vector<int>,int> > pX; //positive ferns <features,labels=1>  正样本
      
  97.   std::vector<std::pair<std::vector<int>,int> > nX; // negative ferns <features,labels=0>  负样本
      
  98.   cv::Mat pEx;  //positive NN example  
      
  99.   std::vector<cv::Mat> nEx; //negative NN examples
      
  100.     
  101. //Test data 
      
  102.   std::vector<std::pair<std::vector<int>,int> > nXT; //negative data to Test
      
  103.   std::vector<cv::Mat> nExT; //negative NN examples to Test
      
  104.     
  105. //Last frame data
      
  106.   BoundingBox lastbox;  
  107.   bool lastvalid;  
  108.   float lastconf;  
  109.     
  110. //Current frame data
      
  111.   //Tracker data
      
  112.   bool tracked;  
  113.   BoundingBox tbb;  
  114.   bool tvalid;  
  115.   float tconf;  
  116.     
  117.   //Detector data
      
  118.   TempStruct tmp;  
  119.   DetStruct dt;  
  120.   std::vector<BoundingBox> dbb;  
  121.   std::vector<bool> dvalid;   //检测有效性??
      
  122.   std::vector<float> dconf;  //检测确信度??
      
  123.   bool detected;  
  124.   
  125.   
  126.   //Bounding Boxes
      
  127.   std::vector<BoundingBox> grid;  
  128.   std::vector<cv::Size> scales;  
  129.   std::vector<int> good_boxes; //indexes of bboxes with overlap > 0.6
      
  130.   std::vector<int> bad_boxes; //indexes of bboxes with overlap < 0.2
      
  131.   BoundingBox bbhull; // hull of good_boxes  //good_boxes 的 壳,也就是窗口的边框
      
  132.   BoundingBox best_box; // maximum overlapping bbox
      
  133.   
  134. public:  
  135.   //Constructors
      
  136.   TLD();  
  137.   TLD(const cv::FileNode& file);  
  138.   void read(const cv::FileNode& file);  
  139.     
  140.   //Methods
      
  141.   void init(const cv::Mat& frame1,const cv::Rect &box, FILE* bb_file);  
  142.   void generatePositiveData(const cv::Mat& frame, int num_warps);  
  143.   void generateNegativeData(const cv::Mat& frame);  
  144.   void processFrame(const cv::Mat& img1,const cv::Mat& img2,std::vector<cv::Point2f>& points1,std::vector<cv::Point2f>& points2,  
  145.       BoundingBox& bbnext,bool& lastboxfound, bool tl,FILE* bb_file);  
  146.   void track(const cv::Mat& img1, const cv::Mat& img2,std::vector<cv::Point2f>& points1,std::vector<cv::Point2f>& points2);  
  147.   void detect(const cv::Mat& frame);  
  148.   void clusterConf(const std::vector<BoundingBox>& dbb,const std::vector<float>& dconf,std::vector<BoundingBox>& cbb,std::vector<float>& cconf);  
  149.   void evaluate();  
  150.   void learn(const cv::Mat& img);  
  151.     
  152.   //Tools
      
  153.   void buildGrid(const cv::Mat& img, const cv::Rect& box);  
  154.   float bbOverlap(const BoundingBox& box1,const BoundingBox& box2);  
  155.   void getOverlappingBoxes(const cv::Rect& box1,int num_closest);  
  156.   void getBBHull();  
  157.   void getPattern(const cv::Mat& img, cv::Mat& pattern,cv::Scalar& mean,cv::Scalar& stdev);  
  158.   void bbPoints(std::vector<cv::Point2f>& points, const BoundingBox& bb);  
  159.   void bbPredict(const std::vector<cv::Point2f>& points1,const std::vector<cv::Point2f>& points2,  
  160.       const BoundingBox& bb1,BoundingBox& bb2);  
  161.   double getVar(const BoundingBox& box,const cv::Mat& sum,const cv::Mat& sqsum);  
  162.   bool bbComp(const BoundingBox& bb1,const BoundingBox& bb2);  
  163.   int clusterBB(const std::vector<BoundingBox>& dbb,std::vector<int>& indexes);  
  164. };  

 

TLD.cpp

  1. /* 
  2.  * TLD.cpp 
  3.  * 
  4.  *  Created on: Jun 9, 2011 
  5.  *      Author: alantrrs 
  6.  */  
  7.   
  8. #include <TLD.h>
      
  9. #include <stdio.h>
      
  10. using namespace cv;  
  11. using namespace std;  
  12.   
  13.   
  14. TLD::TLD()  
  15. {  
  16. }  
  17. TLD::TLD(const FileNode& file){  
  18.   read(file);  
  19. }  
  20.   
  21. void TLD::read(const FileNode& file){  
  22.   ///Bounding Box Parameters
      
  23.   min_win = (int)file["min_win"];  
  24.   ///Genarator Parameters
      
  25.   //initial parameters for positive examples
      
  26.   patch_size = (int)file["patch_size"];  
  27.   num_closest_init = (int)file["num_closest_init"];  
  28.   num_warps_init = (int)file["num_warps_init"];  
  29.   noise_init = (int)file["noise_init"];  
  30.   angle_init = (float)file["angle_init"];  
  31.   shift_init = (float)file["shift_init"];  
  32.   scale_init = (float)file["scale_init"];  
  33.   //update parameters for positive examples
      
  34.   num_closest_update = (int)file["num_closest_update"];  
  35.   num_warps_update = (int)file["num_warps_update"];  
  36.   noise_update = (int)file["noise_update"];  
  37.   angle_update = (float)file["angle_update"];  
  38.   shift_update = (float)file["shift_update"];  
  39.   scale_update = (float)file["scale_update"];  
  40.   //parameters for negative examples
      
  41.   bad_overlap = (float)file["overlap"];  
  42.   bad_patches = (int)file["num_patches"];  
  43.   classifier.read(file);  
  44. }  
  45.   
  46. //此函数完成准备工作
      
  47. void TLD::init(const Mat& frame1, const Rect& box, FILE* bb_file){  
  48.   //bb_file = fopen("bounding_boxes.txt","w");
      
  49.   //Get Bounding Boxes
      
  50.   //此函数根据传入的box(目标边界框)在传入的图像frame1中构建全部的扫描窗口,并计算重叠度
      
  51.     buildGrid(frame1, box);  
  52.     printf("Created %d bounding boxes\n",(int)grid.size());  //vector的成员size()用于获取向量元素的个数
      
  53.       
  54.   ///Preparation
      
  55.   //allocation
      
  56.   //积分图像,用以计算2bitBP特征(类似于haar特征的计算)
      
  57.   //Mat的创建,方式有两种:1.调用create(行,列,类型)2.Mat(行,列,类型(值))。
      
  58.   iisum.create(frame1.rows+1, frame1.cols+1, CV_32F);  
  59.   iisqsum.create(frame1.rows+1, frame1.cols+1, CV_64F);  
  60.     
  61.   //Detector data中定义:std::vector<float> dconf;  检测确信度??
      
  62.   //vector 的reserve增加了vector的capacity,但是它的size没有改变!而resize改变了vector
      
  63.   //的capacity同时也增加了它的size!reserve是容器预留空间,但在空间内不真正创建元素对象,
      
  64.   //所以在没有添加新的对象之前,不能引用容器内的元素。
      
  65.   //不管是调用resize还是reserve,二者对容器原有的元素都没有影响。
      
  66.   //myVec.reserve( 100 );     // 新元素还没有构造, 此时不能用[]访问元素
      
  67.   //myVec.resize( 100 );      // 用元素的默认构造函数构造了100个新的元素,可以直接操作新元素
      
  68.   dconf.reserve(100);  
  69.   dbb.reserve(100);  
  70.   bbox_step =7;  
  71.     
  72.   //以下在Detector data中定义的容器都给其分配grid.size()大小(这个是一幅图像中全部的扫描窗口个数)的容量
      
  73.   //Detector data中定义TempStruct tmp;  
      
  74.   //tmp.conf.reserve(grid.size());
      
  75.   tmp.conf = vector<float>(grid.size());  
  76.   tmp.patt = vector<vector<int> >(grid.size(), vector<int>(10,0));  
  77.   //tmp.patt.reserve(grid.size());
      
  78.   dt.bb.reserve(grid.size());  
  79.   good_boxes.reserve(grid.size());  
  80.   bad_boxes.reserve(grid.size());  
  81.     
  82.   //TLD中定义:cv::Mat pEx;  //positive NN example 大小为15*15图像片
      
  83.   pEx.create(patch_size, patch_size, CV_64F);  
  84.     
  85.   //Init Generator
      
  86.   //TLD中定义:cv::PatchGenerator generator;  //PatchGenerator类用来对图像区域进行仿射变换
      
  87.   /* 
  88.   cv::PatchGenerator::PatchGenerator (     
  89.       double     _backgroundMin, 
  90.       double     _backgroundMax, 
  91.       double     _noiseRange, 
  92.       bool     _randomBlur = true, 
  93.       double     _lambdaMin = 0.6, 
  94.       double     _lambdaMax = 1.5, 
  95.       double     _thetaMin = -CV_PI, 
  96.       double     _thetaMax = CV_PI, 
  97.       double     _phiMin = -CV_PI, 
  98.       double     _phiMax = CV_PI  
  99.    )  
  100.    一般的用法是先初始化一个PatchGenerator的实例,然后RNG一个随机因子,再调用()运算符产生一个变换后的正样本。 
  101.   */  
  102.   generator = PatchGenerator (0,0,noise_init,true,1-scale_init,1+scale_init,-angle_init*CV_PI/180,  
  103.                                 angle_init*CV_PI/180,-angle_init*CV_PI/180,angle_init*CV_PI/180);  
  104.     
  105.   //此函数根据传入的box(目标边界框),在整帧图像中的全部窗口中寻找与该box距离最小(即最相似,
      
  106.   //重叠度最大)的num_closest_init个窗口,然后把这些窗口 归入good_boxes容器
      
  107.   //同时,把重叠度小于0.2的,归入 bad_boxes 容器
      
  108.   //首先根据overlap的比例信息选出重复区域比例大于60%并且前num_closet_init= 10个的最接近box的RectBox,
      
  109.   //相当于对RectBox进行筛选。并通过BBhull函数得到这些RectBox的最大边界。
      
  110.   getOverlappingBoxes(box, num_closest_init);  
  111.   printf("Found %d good boxes, %d bad boxes\n",(int)good_boxes.size(),(int)bad_boxes.size());  
  112.   printf("Best Box: %d %d %d %d\n",best_box.x, best_box.y, best_box.width, best_box.height);  
  113.   printf("Bounding box hull: %d %d %d %d\n", bbhull.x, bbhull.y, bbhull.width, bbhull.height);  
  114.     
  115.   //Correct Bounding Box
      
  116.   lastbox=best_box;  
  117.   lastconf=1;  
  118.   lastvalid=true;  
  119.   //Print
      
  120.   fprintf(bb_file,"%d,%d,%d,%d,%f\n",lastbox.x,lastbox.y,lastbox.br().x,lastbox.br().y,lastconf);  
  121.     
  122.   //Prepare Classifier 准备分类器
      
  123.   //scales容器里是所有扫描窗口的尺度,由buildGrid()函数初始化
      
  124.   classifier.prepare(scales);  
  125.     
  126.   ///Generate Data
      
  127.   // Generate positive data
      
  128.   generatePositiveData(frame1, num_warps_init);  
  129.     
  130.   // Set variance threshold
      
  131.   Scalar stdev, mean;  
  132.   //统计best_box的均值和标准差
      
  133.   ////例如需要提取图像A的某个ROI(感兴趣区域,由矩形框)的话,用Mat类的B=img(ROI)即可提取
      
  134.   //frame1(best_box)就表示在frame1中提取best_box区域(目标区域)的图像片
      
  135.   meanStdDev(frame1(best_box), mean, stdev);  
  136.     
  137.   //利用积分图像去计算每个待检测窗口的方差
      
  138.   //cvIntegral( const CvArr* image, CvArr* sum, CvArr* sqsum=NULL, CvArr* tilted_sum=NULL );
      
  139.   //计算积分图像,输入图像,sum积分图像, W+1×H+1,sqsum对象素值平方的积分图像,tilted_sum旋转45度的积分图像
      
  140.   //利用积分图像,可以计算在某象素的上-右方的或者旋转的矩形区域中进行求和、求均值以及标准方差的计算,
      
  141.   //并且保证运算的复杂度为O(1)。  
      
  142.   integral(frame1, iisum, iisqsum);  
  143.   //级联分类器模块一:方差检测模块,利用积分图计算每个待检测窗口的方差,方差大于var阈值(目标patch方差的50%)的,
      
  144.   //则认为其含有前景目标方差;var 为标准差的平方
      
  145.   var = pow(stdev.val[0],2) * 0.5; //getVar(best_box,iisum,iisqsum);
      
  146.   cout << "variance: " << var << endl;  
  147.     
  148.   //check variance
      
  149.   //getVar函数通过积分图像计算输入的best_box的方差
      
  150.   double vr =  getVar(best_box, iisum, iisqsum)*0.5;  
  151.   cout << "check variance: " << vr << endl;  
  152.     
  153.   // Generate negative data
      
  154.   generateNegativeData(frame1);  
  155.     
  156.   //Split Negative Ferns into Training and Testing sets (they are already shuffled)
      
  157.   //将负样本放进 训练和测试集
      
  158.   int half = (int)nX.size()*0.5f;  
  159.   //vector::assign函数将区间[start, end)中的值赋值给当前的vector.
      
  160.   //将一半的负样本集 作为 测试集
      
  161.   nXT.assign(nX.begin()+half, nX.end());  //nXT; //negative data to Test
      
  162.   //然后将剩下的一半作为训练集
      
  163.   nX.resize(half);  
  164.     
  165.   ///Split Negative NN Examples into Training and Testing sets
      
  166.   half = (int)nEx.size()*0.5f;  
  167.   nExT.assign(nEx.begin()+half,nEx.end());  
  168.   nEx.resize(half);  
  169.     
  170.   //Merge Negative Data with Positive Data and shuffle it
      
  171.   //将负样本和正样本合并,然后打乱
      
  172.   vector<pair<vector<int>,int> > ferns_data(nX.size()+pX.size());  
  173.   vector<int> idx = index_shuffle(0, ferns_data.size());  
  174.   int a=0;  
  175.   for (int i=0;i<pX.size();i++){  
  176.       ferns_data[idx[a]] = pX[i];  
  177.       a++;  
  178.   }  
  179.   for (int i=0;i<nX.size();i++){  
  180.       ferns_data[idx[a]] = nX[i];  
  181.       a++;  
  182.   }  
  183.     
  184.   //Data already have been shuffled, just putting it in the same vector
      
  185.   vector<cv::Mat> nn_data(nEx.size()+1);  
  186.   nn_data[0] = pEx;  
  187.   for (int i=0;i<nEx.size();i++){  
  188.       nn_data[i+1]= nEx[i];  
  189.   }  
  190.     
  191.   ///Training  
      
  192.   //训练 集合分类器(森林) 和 最近邻分类器 
      
  193.   classifier.trainF(ferns_data, 2); //bootstrap = 2
      
  194.   classifier.trainNN(nn_data);  
  195.     
  196.   ///Threshold Evaluation on testing sets
      
  197.   //用样本在上面得到的 集合分类器(森林) 和 最近邻分类器 中分类,评价得到最好的阈值
      
  198.   classifier.evaluateTh(nXT, nExT);  
  199. }  
  200.   
  201. /* Generate Positive data 
  202.  * Inputs: 
  203.  * - good_boxes (bbP) 

抱歉!评论已关闭.