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

zouxy09@qq.com

http://blog.csdn.net/zouxy09

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

run_tld.cpp

#include <opencv2/opencv.hpp>
#include <tld_utils.h>
#include <iostream>
#include <sstream>  //c++中的sstream类,提供了程序和string对象之间的I/O,可以通过ostringstream//和instringstream两个类来声明对象,分别对应输出流和输入流
#include <TLD.h>
#include <stdio.h>
using namespace cv;
using namespace std;
//Global variables
Rect box;
bool drawing_box = false;
bool gotBB = false;
bool tl = true;
bool rep = false;
bool fromfile=false;
string video;//读取记录bounding box的文件,获得bounding box的四个参数:左上角坐标x,y和宽高
/*如在\datasets\06_car\init.txt中:记录了初始目标的bounding box,内容如下
142,125,232,164
*/
void readBB(char* file){ifstream bb_file (file);  //以输入方式打开文件string line;//istream& getline ( istream& , string& );//将输入流is中读到的字符存入str中,终结符默认为 '\n'(换行符) getline(bb_file, line);istringstream linestream(line); //istringstream对象可以绑定一行字符串,然后以空格为分隔符把该行分隔开来。string x1,y1,x2,y2;//istream& getline ( istream &is , string &str , char delim ); //将输入流is中读到的字符存入str中,直到遇到终结符delim才结束。getline (linestream,x1, ',');getline (linestream,y1, ',');getline (linestream,x2, ',');getline (linestream,y2, ',');//atoi 功 能: 把字符串转换成整型数int x = atoi(x1.c_str());// = (int)file["bb_x"];int y = atoi(y1.c_str());// = (int)file["bb_y"];int w = atoi(x2.c_str())-x;// = (int)file["bb_w"];int h = atoi(y2.c_str())-y;// = (int)file["bb_h"];box = Rect(x,y,w,h);
}//bounding box mouse callback
//鼠标的响应就是得到目标区域的范围,用鼠标选中bounding box。
void mouseHandler(int event, int x, int y, int flags, void *param){switch( event ){case CV_EVENT_MOUSEMOVE:if (drawing_box){box.width = x-box.x;box.height = y-box.y;}break;case CV_EVENT_LBUTTONDOWN:drawing_box = true;box = Rect( x, y, 0, 0 );break;case CV_EVENT_LBUTTONUP:drawing_box = false;if( box.width < 0 ){box.x += box.width;box.width *= -1;}if( box.height < 0 ){box.y += box.height;box.height *= -1;}gotBB = true;   //已经获得bounding boxbreak;}
}void print_help(char** argv){printf("use:\n     %s -p /path/parameters.yml\n",argv[0]);printf("-s    source video\n-b        bounding box file\n-tl  track and learn\n-r     repeat\n");
}//分析运行程序时的命令行参数
void read_options(int argc, char** argv, VideoCapture& capture, FileStorage &fs){for (int i=0;i<argc;i++){if (strcmp(argv[i],"-b")==0){if (argc>i){readBB(argv[i+1]);  //是否指定初始的bounding boxgotBB = true;}elseprint_help(argv);}if (strcmp(argv[i],"-s")==0){   //从视频文件中读取if (argc>i){video = string(argv[i+1]);capture.open(video);fromfile = true;}elseprint_help(argv);}//Similar in format to XML, Yahoo! Markup Language (YML) provides functionality to Open //Applications in a safe and standardized fashion. You include YML tags in the HTML code//of an Open Application.if (strcmp(argv[i],"-p")==0){   //读取参数文件parameters.ymlif (argc>i){//FileStorage类的读取方式可以是:FileStorage fs(".\\parameters.yml", FileStorage::READ);  fs.open(argv[i+1], FileStorage::READ);}elseprint_help(argv);}if (strcmp(argv[i],"-no_tl")==0){  //To train only in the first frame (no tracking, no learning)tl = false;}if (strcmp(argv[i],"-r")==0){  //Repeat the video, first time learns, second time detectsrep = true;}}
}/*
运行程序时:
%To run from camera
./run_tld -p ../parameters.yml
%To run from file
./run_tld -p ../parameters.yml -s ../datasets/06_car/car.mpg
%To init bounding box from file
./run_tld -p ../parameters.yml -s ../datasets/06_car/car.mpg -b ../datasets/06_car/init.txt
%To train only in the first frame (no tracking, no learning)
./run_tld -p ../parameters.yml -s ../datasets/06_car/car.mpg -b ../datasets/06_car/init.txt -no_tl
%To test the final detector (Repeat the video, first time learns, second time detects)
./run_tld -p ../parameters.yml -s ../datasets/06_car/car.mpg -b ../datasets/06_car/init.txt -r
*/
//感觉就是对起始帧进行初始化工作,然后逐帧读入图片序列,进行算法处理。
int main(int argc, char * argv[]){VideoCapture capture;capture.open(0);//OpenCV的C++接口中,用于保存图像的imwrite只能保存整数数据,且需作为图像格式。当需要保存浮//点数据或XML/YML文件时,OpenCV的C语言接口提供了cvSave函数,但这一函数在C++接口中已经被删除。//取而代之的是FileStorage类。FileStorage fs;//Read optionsread_options(argc, argv, capture, fs);  //分析命令行参数//Init cameraif (!capture.isOpened()){cout << "capture device failed to open!" << endl;return 1;}//Register mouse callback to draw the bounding boxcvNamedWindow("TLD",CV_WINDOW_AUTOSIZE);cvSetMouseCallback( "TLD", mouseHandler, NULL );  //用鼠标选中初始目标的bounding box//TLD frameworkTLD tld;//Read parameters filetld.read(fs.getFirstTopLevelNode());Mat frame;Mat last_gray;Mat first;if (fromfile){  //如果指定为从文件读取capture >> frame;   //读当前帧cvtColor(frame, last_gray, CV_RGB2GRAY);  //转换为灰度图像frame.copyTo(first);  //拷贝作为第一帧}else{   //如果为读取摄像头,则设置获取的图像大小为320x240 capture.set(CV_CAP_PROP_FRAME_WIDTH,340);  //340??capture.set(CV_CAP_PROP_FRAME_HEIGHT,240);}///Initialization
GETBOUNDINGBOX:   //标号:获取bounding boxwhile(!gotBB){if (!fromfile){capture >> frame;}elsefirst.copyTo(frame);cvtColor(frame, last_gray, CV_RGB2GRAY);drawBox(frame,box);  //把bounding box 画出来imshow("TLD", frame);if (cvWaitKey(33) == 'q')return 0;}//由于图像片(min_win 为15x15像素)是在bounding box中采样得到的,所以box必须比min_win要大if (min(box.width, box.height)<(int)fs.getFirstTopLevelNode()["min_win"]){cout << "Bounding box too small, try again." << endl;gotBB = false;goto GETBOUNDINGBOX;}//Remove callbackcvSetMouseCallback( "TLD", NULL, NULL );  //如果已经获得第一帧用户框定的box了,就取消鼠标响应printf("Initial Bounding Box = x:%d y:%d h:%d w:%d\n",box.x,box.y,box.width,box.height);//Output fileFILE  *bb_file = fopen("bounding_boxes.txt","w");//TLD initializationtld.init(last_gray, box, bb_file);///Run-timeMat current_gray;BoundingBox pbox;vector<Point2f> pts1;vector<Point2f> pts2;bool status=true;  //记录跟踪成功与否的状态 lastbox been foundint frames = 1;  //记录已过去帧数int detections = 1;  //记录成功检测到的目标box数目REPEAT:while(capture.read(frame)){//get framecvtColor(frame, current_gray, CV_RGB2GRAY);//Process Frametld.processFrame(last_gray, current_gray, pts1, pts2, pbox, status, tl, bb_file);//Draw Pointsif (status){  //如果跟踪成功drawPoints(frame,pts1);drawPoints(frame,pts2,Scalar(0,255,0));  //当前的特征点用蓝色点表示drawBox(frame,pbox);detections++;}//Displayimshow("TLD", frame);//swap points and imagesswap(last_gray, current_gray);  //STL函数swap()用来交换两对象的值。其泛型化版本定义于<algorithm>;pts1.clear();pts2.clear();frames++;printf("Detection rate: %d/%d\n", detections, frames);if (cvWaitKey(33) == 'q')break;}if (rep){rep = false;tl = false;fclose(bb_file);bb_file = fopen("final_detector.txt","w");//capture.set(CV_CAP_PROP_POS_AVI_RATIO,0);capture.release();capture.open(video);goto REPEAT;}fclose(bb_file);return 0;
}

tld_utils.cpp

#include <tld_utils.h>
using namespace cv;
using namespace std;/*vector是C++标准模板库STL中的部分内容,它是一个多功能的,能够操作多种数据结构和算法的
模板类和函数库。vector之所以被认为是一个容器,是因为它能够像容器一样存放各种类型的对象,
简单地说,vector是一个能够存放任意类型的动态数组,能够增加和压缩数据。
为了可以使用vector,必须在你的头文件中包含下面的代码:
#include <vector>
vector属于std命名域的,因此需要通过命名限定,如下完成你的代码:
using std::vector;
*/void drawBox(Mat& image, CvRect box, Scalar color, int thick){rectangle( image, cvPoint(box.x, box.y), cvPoint(box.x+box.width,box.y+box.height),color, thick);
} //函数 cvRound, cvFloor, cvCeil 用一种舍入方法将输入浮点数转换成整数。
//cvRound 返回和参数最接近的整数值。 cvFloor 返回不大于参数的最大整数值。
//cvCeil 返回不小于参数的最小整数值。
void drawPoints(Mat& image, vector<Point2f> points,Scalar color){for( vector<Point2f>::const_iterator i = points.begin(), ie = points.end(); i != ie; ++i ){Point center( cvRound(i->x ), cvRound(i->y));  //类似于int i(3)的初始化,但center为何没用到?circle(image,*i,2,color,1);}
}Mat createMask(const Mat& image, CvRect box){Mat mask = Mat::zeros(image.rows,image.cols,CV_8U);drawBox(mask,box,Scalar::all(255),CV_FILLED);return mask;
}//STL中的nth_element()方法找出一个数列中排名第n的那个数。
//对于序列a[0:len-1]将第n大的数字,排在a[n],同时a[0:n-1]都小于a[n],a[n+1:]都大于a[n],
//但a[n]左右的这两个序列不一定有序。
//用在中值流跟踪算法中,寻找中值
float median(vector<float> v)
{int n = floor(v.size() / 2);nth_element(v.begin(), v.begin()+n, v.end());return v[n];
}//<algorithm> //random_shuffle的头文件
//shuffle 洗牌  首先简单的介绍一个扑克牌洗牌的方法,假设一个数组 poker[52] 中存有一副扑克
//牌1-52的牌点值,使用一个for循环遍历这个数组,每次循环都生成一个[0,52)之间的随机数RandNum,
//以RandNum为数组下标,把当前下标对应的值和RandNum对应位置的值交换,循环结束,每个牌都与某个
//位置交换了一次,这样一副牌就被打乱了。 理解代码如下:
/*
for (int i = 0; i < 52; ++i)
{  int RandNum = rand() % 52;    int tmp = poker[i];  poker[i] = poker[RandNum];  poker[RandNum] = tmp;
}
*/
//需要指定范围内的随机数,传统的方法是使用ANSI C的函数random(),然后格式化结果以便结果是落在
//指定的范围内。但是,使用这个方法至少有两个缺点。做格式化时,结果常常是扭曲的,且只支持整型数。
//C++中提供了更好的解决方法,那就是STL中的random_shuffle()算法。产生指定范围内的随机元素集的最佳方法
//是创建一个顺序序列(也就是向量或者内置数组),在这个顺序序列中含有指定范围的所有值。
//例如,如果你需要产生100个0-99之间的数,那么就创建一个向量并用100个按升序排列的数填充向量.
//填充完向量之后,用random_shuffle()算法打乱元素排列顺序。
//默认的random_shuffle中, 被操作序列的index 与 rand() % N 两个位置的值交换,来达到乱序的目的。
//index_shuffle()用于产生指定范围[begin:end]的随机数,返回随机数数组
vector<int> index_shuffle(int begin,int end){vector<int> indexes(end-begin);for (int i=begin;i<end;i++){indexes[i]=i;}random_shuffle(indexes.begin(),indexes.end());return indexes;
}

TLD(Tracking-Learning-Detection)学习与源码理解之(四)相关推荐

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

    TLD(Tracking-Learning-Detection)学习与源码理解之(六) zouxy09@qq.com http://blog.csdn.net/zouxy09 下面是自己在看论文和这些 ...

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

    TLD(Tracking-Learning-Detection)学习与源码理解之(二) zouxy09@qq.com http://blog.csdn.net/zouxy09 OpenTLD下载与编译 ...

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

    TLD(Tracking-Learning-Detection)学习与源码理解之(五)   zouxy09@qq.com http://blog.csdn.net/zouxy09 下面是自己在看论文和 ...

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

    TLD(Tracking-Learning-Detection)学习与源码理解之(三) zouxy09@qq.com http://blog.csdn.net/zouxy09 下面是自己在看论文和这些 ...

  5. 学习common-upload源码,理解上传原理

    之前介绍了只使用一段代码实现上传文件的方法.最近又试了几次,才发现这个是有问题的. 例如,要上传原文件如下的文件: 使用jsp上传后发现文件变成了下面这个样子,图片下面的像素没有了. 然后我又用com ...

  6. 压缩跟踪Compressive Tracking源码理解

    压缩跟踪Compressive Tracking源码理解 zouxy09@qq.com http://blog.csdn.net/zouxy09 在前面一个介绍<Real-Time Compre ...

  7. React深入学习与源码解析笔记

    ***当前阶段的笔记 *** 「面向实习生阶段」https://www.aliyundrive.com/s/VTME123M4T9 提取码: 8s6v 点击链接保存,或者复制本段内容,打开「阿里云盘」 ...

  8. 小白学习pytorch源码(二):setup.py最详细解读

    小白学习pytorch源码(二) pytorch setup.py最全解析 setup.py与setuptools setup.py最详细解读 setup.py 环境检查 setup.py setup ...

  9. vue filter对象_学习vue源码(3) 手写Vue.directive、Vue.filter、Vue.component方法

    一.Vue.directive Vue.directive(id,[definition]); 1)参数 { string } id{ Function | Object } [ definition ...

最新文章

  1. IoT 、5G与边缘计算将会擦出怎样的火花?
  2. 从Spring-Session源码看Session机制的实现细节
  3. 个人博客 SEO 优化(2):站内优化
  4. 081_html5地理定位
  5. Go实战--golang中使用redis(redigo和go-redis/redis这个已测试)
  6. SAP Gateway 类型为multipart mixed的请求处理逻辑
  7. 更多核心、更大内存、更低成本 AMD皓龙6000欲成云计算基石
  8. 基于CSE的微服务工程实践-Native API先行
  9. 匿名内部类 可以访问外部类_Java 内部类与外部类的互访使用小结
  10. 2021密码应用技术白皮书
  11. 发布uubox.net客户端工具及其源代码
  12. Linux内核抢占机制(preempt)
  13. Streaming Telemetry翻译学习
  14. C语言基础入门48篇_30_二维数组的定义与使用(二维数组的定义:type 数组名[行][列]、二维数组的初始化、二维数组的引用)
  15. 重写equals()方法
  16. python split()函数
  17. EOJ - 我决不会TLE (一个智障的题目)
  18. Java解决角谷定理。输入一个自然数,若为偶数,则把它除以2,若为奇数,则把它乘以3加1。经过如此有限次运算后,总可以得到自然数值1。求经过多少次可得到自然数1。
  19. 喝一碗孟婆汤nbsp;走一遍奈何桥
  20. node.js Stream(流) 和 EJS 模板引擎——0822

热门文章

  1. 易开发创始人潘俊勇:这些年我遇到的那些坑
  2. 顶级风投First Round Capital对创业者的30个建议
  3. 比较简单的c语言编辑器,大佬们,小菜鸟想问一问用vc编译器做简易画图软件
  4. MySQL - 使用trace工具来窥探MySQL是如何选择执行计划的
  5. 白话Elasticsearch04- 结构化搜索之使用terms query搜索多个值以及多值搜索结果优化
  6. opencv三维重建_基于OpenCV和C++的多视图三维重建
  7. Typora最好用的Markdown编辑器
  8. linux 插件 概念,服务端概念功能介绍
  9. matlab 直方图_MATLAB作图实例:19:用二元直方图分析图片颜色
  10. 在vue项目中对axios进行封装