压缩感知跟踪(二)

   上一篇博客我按matlab的执行顺序贴上了matlab版本的代码,这次准备在这里贴上CT的C++代码,希望可以对比学学。事实上我通过运行两个版本的代码,发现matlab比C++版本的代码要快,这个和TLD类似哦。

平台: VS2010 + OpenCV2.4.6

先上一些图,下面是论文中的图。







接着,下面是论文中公式:



         





下面是论文的算法流程



最后,我还是贴上C++代码吧,我注释了。

CompressiveTracker.h头文件,定义了CompressiveTracker类

/************************************************************************
* File:	CompressiveTracker.h
* Brief: C++ demo for paper: Kaihua Zhang, Lei Zhang, Ming-Hsuan Yang,"Real-Time Compressive Tracking," ECCV 2012.
* Version: 1.0
* Author: Yang Xian
* Email: yang_xian521@163.com
* Date:	2012/08/03
* History:
* Revised by Kaihua Zhang on 14/8/2012, 23/8/2012
* Email: zhkhua@gmail.com
* Homepage: http://www4.comp.polyu.edu.hk/~cskhzhang/
* Project Website: http://www4.comp.polyu.edu.hk/~cslzhang/CT/CT.htm
************************************************************************/
#pragma once
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <vector>

using std::vector;
using namespace cv;
//---------------------------------------------------
// 压缩感知跟踪器类
class CompressiveTracker
{
public:
	CompressiveTracker(void);
	~CompressiveTracker(void);

private:
	int featureMinNumRect;
	int featureMaxNumRect;
	int featureNum;                 //特征数目,这里我们设定了50个特征
	vector<vector<Rect>> features;  //特征:[x,y,w,h]
	vector<vector<float>> featuresWeight; //特征的权重
	int rOuterPositive; //初始正样本采集半径
	vector<Rect> samplePositiveBox;  //正样本集
	vector<Rect> sampleNegativeBox;  //负样本集
	int rSearchWindow;  //搜索窗口
	Mat imageIntegral;  //积分图
	Mat samplePositiveFeatureValue; //正样本特征集
	Mat sampleNegativeFeatureValue; //负样本特征集
	vector<float> muPositive;    //正样本的均值
	vector<float> sigmaPositive; //负样本的标准差
	vector<float> muNegative;    //负样本的均值
	vector<float> sigmaNegative; //负样本的标准差
	float learnRate;  //学习率
	vector<Rect> detectBox;  //检测窗口 
	Mat detectFeatureValue;  //检测窗口的特征集合
	RNG rng;

private:
	//计算haar窗口(特征)
	void HaarFeature(Rect& _objectBox, int _numFeature);
	//采集样本
	void sampleRect(Mat& _image, Rect& _objectBox, float _rInner, float _rOuter, int _maxSampleNum, vector<Rect>& _sampleBox);
	//采集样本
	void sampleRect(Mat& _image, Rect& _objectBox, float _srw, vector<Rect>& _sampleBox);
	//计算采集到的样本的特征集合
	void getFeatureValue(Mat& _imageIntegral, vector<Rect>& _sampleBox, Mat& _sampleFeatureValue);
	//更新均值和标准差
	void classifierUpdate(Mat& _sampleFeatureValue, vector<float>& _mu, vector<float>& _sigma, float _learnRate);
	//计算比例,相对于相识度(匹配。。)
	void radioClassifier(vector<float>& _muPos, vector<float>& _sigmaPos, vector<float>& _muNeg, vector<float>& _sigmaNeg,
						Mat& _sampleFeatureValue, float& _radioMax, int& _radioMaxIndex);
public:
	//处理函数(除第一帧以外的视频帧(图像))
	void processFrame(Mat& _frame, Rect& _objectBox);
	//初始化函数(第一帧)
	void init(Mat& _frame, Rect& _objectBox);
};

CompressiveTracker.cpp是CompressiveTracker类实现

#include "CompressiveTracker.h"
#include <math.h>
#include <iostream>
using namespace cv;
using namespace std;

//------------------------------------------------
//CT框架的构造函数,初始化相关参数
CompressiveTracker::CompressiveTracker(void)
{
	//特征参数
	featureMinNumRect = 2;
	featureMaxNumRect = 4;	// number of rectangle from 2 to 4
	//弱分类器个数,haar特征的个数为50
	featureNum = 50;	// number of all weaker classifiers, i.e,feature pool
	//%正样本搜索半径,设置为4~8,目的是要采集正样本
	rOuterPositive = 4;	// radical scope of positive samples
	//%新的一帧中的搜索窗口的半径,通常设置为15~35
	rSearchWindow = 25; // size of search window

	//均值,方差矢量容器
	//均值
	muPositive = vector<float>(featureNum, 0.0f);
	muNegative = vector<float>(featureNum, 0.0f);
	//方差
	sigmaPositive = vector<float>(featureNum, 1.0f);
	sigmaNegative = vector<float>(featureNum, 1.0f);

	//学习速率,通常设置为0.7~0.95
	learnRate = 0.85f;	// Learning rate parameter
}

//析构函数
CompressiveTracker::~CompressiveTracker(void)
{
}

// 计算haar特征
void CompressiveTracker::HaarFeature(Rect& _objectBox, int _numFeature)
/*Description: compute Haar features
  Arguments:
  -_objectBox: [x y width height] object rectangle
  -_numFeature: total number of features.The default is 50.
*/
{
	//创建矢量容器
	//特征矢量容器
	features = vector<vector<Rect>>(_numFeature, vector<Rect>());
	//特征权重矢量容器
	featuresWeight = vector<vector<float>>(_numFeature, vector<float>());
	
	int numRect;
	Rect rectTemp;
	float weightTemp;

    //for i=1:M
	for (int i=0; i<_numFeature; i++)
	{
		//生成一个产生均匀分布的数[2,4]之间
		numRect = cvFloor(rng.uniform((double)featureMinNumRect, (double)featureMaxNumRect));
	
		for (int j=0; j<numRect; j++)
		{
			
			rectTemp.x = cvFloor(rng.uniform(0.0, (double)(_objectBox.width - 3)));
			rectTemp.y = cvFloor(rng.uniform(0.0, (double)(_objectBox.height - 3)));
			rectTemp.width = cvCeil(rng.uniform(0.0, (double)(_objectBox.width - rectTemp.x - 2)));
			rectTemp.height = cvCeil(rng.uniform(0.0, (double)(_objectBox.height - rectTemp.y - 2)));
			//将[x,y,w,h]放入矢量容器features中
			features[i].push_back(rectTemp);

			weightTemp = (float)pow(-1.0, cvFloor(rng.uniform(0.0, 2.0))) / sqrt(float(numRect));
			//将权重放入矢量容器中
			featuresWeight[i].push_back(weightTemp);
           
		}
	}
}

// 计算正负样本图像模板的坐标(取样本)
void CompressiveTracker::sampleRect(Mat& _image, Rect& _objectBox, float _rInner, float _rOuter, int _maxSampleNum, vector<Rect>& _sampleBox)
/* Description: compute the coordinate of positive and negative sample image templates
   Arguments:
   -_image:        processing frame
   -_objectBox:    recent object position  [x y width height] 
   -_rInner:       inner sampling radius
   -_rOuter:       Outer sampling radius
   -_maxSampleNum: maximal number of sampled images 样本总数
   返回值
   -_sampleBox:    Storing the rectangle coordinates of the sampled images. 存储样本图像坐标[sx,sy,sw,sh]
*/
{
	int rowsz = _image.rows - _objectBox.height - 1; //行
	int colsz = _image.cols - _objectBox.width - 1;  //列
	float inradsq = _rInner*_rInner;
	float outradsq = _rOuter*_rOuter;

  	
	int dist;

	int minrow = max(0,(int)_objectBox.y-(int)_rInner);              //最小行
	int maxrow = min((int)rowsz-1,(int)_objectBox.y+(int)_rInner);   //最大行
	int mincol = max(0,(int)_objectBox.x-(int)_rInner);              //最小列
	int maxcol = min((int)colsz-1,(int)_objectBox.x+(int)_rInner);   //最大列
    
	
	
	int i = 0;

	float prob = ((float)(_maxSampleNum))/(maxrow-minrow+1)/(maxcol-mincol+1);

	int r;
	int c;
    //清空矢量容器,_sampleBox是返回值
    _sampleBox.clear();//important
    Rect rec(0,0,0,0);

	for( r=minrow; r<=(int)maxrow; r++ ) 
		for( c=mincol; c<=(int)maxcol; c++ ){ //先列,后行
			dist = (_objectBox.y-r)*(_objectBox.y-r) + (_objectBox.x-c)*(_objectBox.x-c);

			if( rng.uniform(0.,1.)<prob && dist < inradsq && dist >= outradsq ){

                rec.x = c; //x
				rec.y = r; //y
				rec.width = _objectBox.width;
				rec.height= _objectBox.height;
				//将满足条件的[x,y,w,h]保存到矢量先来_sampleBox
                _sampleBox.push_back(rec);				
				
				i++;
			}
		}
	
		_sampleBox.resize(i);
		
}

void CompressiveTracker::sampleRect(Mat& _image, Rect& _objectBox, float _srw, vector<Rect>& _sampleBox)
/* Description: Compute the coordinate of samples when detecting the object.*/
{
	int rowsz = _image.rows - _objectBox.height - 1;
	int colsz = _image.cols - _objectBox.width - 1;
	float inradsq = _srw*_srw;	
	

	int dist;

	int minrow = max(0,(int)_objectBox.y-(int)_srw);
	int maxrow = min((int)rowsz-1,(int)_objectBox.y+(int)_srw);
	int mincol = max(0,(int)_objectBox.x-(int)_srw);
	int maxcol = min((int)colsz-1,(int)_objectBox.x+(int)_srw);

	int i = 0;

	int r;
	int c;

	Rect rec(0,0,0,0);
    _sampleBox.clear();//important

	for( r=minrow; r<=(int)maxrow; r++ )
		for( c=mincol; c<=(int)maxcol; c++ ){
			dist = (_objectBox.y-r)*(_objectBox.y-r) + (_objectBox.x-c)*(_objectBox.x-c);

			if( dist < inradsq ){

				rec.x = c;
				rec.y = r;
				rec.width = _objectBox.width;
				rec.height= _objectBox.height;

				_sampleBox.push_back(rec);				

				i++;
			}
		}
	
		_sampleBox.resize(i);

}
// Compute the features of samples
// 计算样本的特征值
void CompressiveTracker::getFeatureValue(Mat& _imageIntegral, vector<Rect>& _sampleBox, Mat& _sampleFeatureValue)
{
	//样本个数
	int sampleBoxSize = _sampleBox.size();
	//开辟一个空间,用来存放每个样本的特征值,特征个数为featureNum
	//一个样本用50个特征来表示
	_sampleFeatureValue.create(featureNum, sampleBoxSize, CV_32F);
	float tempValue;
	int xMin;
	int xMax;
	int yMin;
	int yMax;
	//对于每一个样本,计算他的每一个特征的特征值
	for (int i=0; i<featureNum; i++)  //每一个特征
	{
		for (int j=0; j<sampleBoxSize; j++) //每一个样本
		{
 			tempValue = 0.0f;
			for (size_t k=0; k<features[i].size(); k++)
			{
				xMin = _sampleBox[j].x + features[i][k].x;                         //x
				xMax = _sampleBox[j].x + features[i][k].x + features[i][k].width;  //x
				yMin = _sampleBox[j].y + features[i][k].y;                         //y
				yMax = _sampleBox[j].y + features[i][k].y + features[i][k].height; //y
				//通过积分图像计算特征值。按特征值的权重进行累计得到样本的每个特征值
				tempValue += featuresWeight[i][k] * 
					(_imageIntegral.at<float>(yMin, xMin) +
					_imageIntegral.at<float>(yMax, xMax) -
					_imageIntegral.at<float>(yMin, xMax) -
					_imageIntegral.at<float>(yMax, xMin));
			}
			_sampleFeatureValue.at<float>(i,j) = tempValue; //特征值
		}
	}
}

// Update the mean and variance of the gaussian classifier
void CompressiveTracker::classifierUpdate(Mat& _sampleFeatureValue, vector<float>& _mu, vector<float>& _sigma, float _learnRate)
{
	Scalar muTemp;
	Scalar sigmaTemp;
    //45个样本,每个样本50个特征
	for (int i=0; i<featureNum; i++) //对应每一个特征
	{
		//计算均值和标准差
		meanStdDev(_sampleFeatureValue.row(i), muTemp, sigmaTemp);
	    //更新:sigma = sqrt(beta*sigma1^2 + (1-beta)*sigma2^2)
		_sigma[i] = (float)sqrt( _learnRate*_sigma[i]*_sigma[i]	+ (1.0f-_learnRate)*sigmaTemp.val[0]*sigmaTemp.val[0] 
		+ _learnRate*(1.0f-_learnRate)*(_mu[i]-muTemp.val[0])*(_mu[i]-muTemp.val[0]));	// equation 6 in paper
		//更新均值
		_mu[i] = _mu[i]*_learnRate + (1.0f-_learnRate)*muTemp.val[0];	// equation 6 in paper
	}
}

// Compute the ratio classifier 
// 这函数的返回值_radioMax,_radioMaxIndex
void CompressiveTracker::radioClassifier(vector<float>& _muPos, vector<float>& _sigmaPos, vector<float>& _muNeg, vector<float>& _sigmaNeg,
										 Mat& _sampleFeatureValue, float& _radioMax, int& _radioMaxIndex)
{
	float sumRadio;
	_radioMax = -FLT_MAX;
	_radioMaxIndex = 0;
	float pPos;
	float pNeg;

	//采集到的样本个数
	int sampleBoxNum = _sampleFeatureValue.cols;

	for (int j=0; j<sampleBoxNum; j++)
	{
		sumRadio = 0.0f;
		for (int i=0; i<featureNum; i++)
		{
			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);
			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);
			//公式4
			sumRadio += log(pPos+1e-30) - log(pNeg+1e-30);	// equation 4
		}
		if (_radioMax < sumRadio)
		{
			_radioMax = sumRadio;
			_radioMaxIndex = j;
		}
	}
}

//对第一帧进行一些初始化操作
void CompressiveTracker::init(Mat& _frame, Rect& _objectBox)
{
	// compute feature template
	// 计算特征模板
	HaarFeature(_objectBox, featureNum);

	// compute sample templates
	// 计算样本模板
	//取正样本(采集正训练样本)
	sampleRect(_frame, _objectBox, rOuterPositive, 0, 1000000, samplePositiveBox);
	//取负样本(采集负训练样本)
	sampleRect(_frame, _objectBox, rSearchWindow*1.5, rOuterPositive+4.0, 100, sampleNegativeBox);
	//opencv的函数,求图像的积分图像,返回:imageIntegral
	integral(_frame, imageIntegral, CV_32F);

	//正样本的特征集合samplePositiveFeatureValue,每个样本具有50个特征
	getFeatureValue(imageIntegral, samplePositiveBox, samplePositiveFeatureValue);
	//负样本的特征集合sampleNegativeFeatureValue,每个样本具有50个特征
	getFeatureValue(imageIntegral, sampleNegativeBox, sampleNegativeFeatureValue);
	
	//正样本,更新均值和标准差
	classifierUpdate(samplePositiveFeatureValue, muPositive, sigmaPositive, learnRate);
	//负样本,更新均值和标准差
	classifierUpdate(sampleNegativeFeatureValue, muNegative, sigmaNegative, learnRate);
}
void CompressiveTracker::processFrame(Mat& _frame, Rect& _objectBox)
{
	// predict
	// 对当前视频帧(图像)进行采样,采样的结果返回到detectBox中([x,y,w,h])
	sampleRect(_frame, _objectBox, rSearchWindow,detectBox);
	// 计算当前视频帧(图像)的积分图像
	integral(_frame, imageIntegral, CV_32F);
	// 计算采样的所有矩形框特征集合detectFeatureValue
	getFeatureValue(imageIntegral, detectBox, detectFeatureValue);
	int radioMaxIndex;
	float radioMax;
	//这个函数相当于要判断目标在当前帧中的位置(几何角度:比较距离;概率角度:可能性大)
	//muPositive, sigmaPositive, muNegative, sigmaNegative,这些是前一帧(张)图像的均值和标准差
	//这函数的返回值_radioMax,_radioMaxIndex
	radioClassifier(muPositive, sigmaPositive, muNegative, sigmaNegative, detectFeatureValue, radioMax, radioMaxIndex);
	//选择检测窗口中的第_radioMaxIndex-1个窗口作为目标
	_objectBox = detectBox[radioMaxIndex];

	// update
	// 在当前帧中,采集正样本samplePositiveBox
	sampleRect(_frame, _objectBox, rOuterPositive, 0.0, 1000000, samplePositiveBox);
	// 在当前帧中,采集负样本sampleNegativeBox
	sampleRect(_frame, _objectBox, rSearchWindow*1.5, rOuterPositive+4.0, 100, sampleNegativeBox);
	
	// 由于上面已经计算得到了积分图像,所有就直接拿来使用
	// 计算正样本和负样本的特征集合samplePositiveFeatureValue,sampleNegativeFeatureValue
	getFeatureValue(imageIntegral, samplePositiveBox, samplePositiveFeatureValue);
	getFeatureValue(imageIntegral, sampleNegativeBox, sampleNegativeFeatureValue);

	// 更新正负样本的均值和标准差
	classifierUpdate(samplePositiveFeatureValue, muPositive, sigmaPositive, learnRate);
	classifierUpdate(sampleNegativeFeatureValue, muNegative, sigmaNegative, learnRate);
}

RunTracker.cpp是CT的主文件,用于运行跟踪器

/************************************************************************
* File:	RunTracker.cpp
* Brief: C++ demo for paper: Kaihua Zhang, Lei Zhang, Ming-Hsuan Yang,"Real-Time Compressive Tracking," ECCV 2012.
* Version: 1.0
* Author: Yang Xian
* Email: yang_xian521@163.com
* Date:	2012/08/03
* History:
* Revised by Kaihua Zhang on 14/8/2012, 23/8/2012
* Email: zhkhua@gmail.com
* Homepage: http://www4.comp.polyu.edu.hk/~cskhzhang/
* Project Website: http://www4.comp.polyu.edu.hk/~cslzhang/CT/CT.htm
************************************************************************/
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include <fstream>
#include <sstream>
#include <stdio.h>
#include <string.h>
#include "CompressiveTracker.h"
#include <Windows.h>     /*这个是我添加上去的*/


using namespace cv;
using namespace std;

//读取配置文件,实际上就是要读取初始帧的目标状态[x,y,w,h]
void readConfig(char* configFileName, char* imgFilePath, Rect &box);
/*  Description: read the tracking information from file "config.txt"
    Arguments:	
	-configFileName: config file name
	-ImgFilePath:    Path of the storing image sequences
	-box:            [x y width height] intial tracking position
	History: Created by Kaihua Zhang on 15/8/2012
*/
//读取图像数据
void readImageSequenceFiles(char* ImgFilePath,vector <string> &imgNames);
/*  Description: search the image names in the image sequences 
    Arguments:
	-ImgFilePath: path of the image sequence
	-imgNames:  vector that stores image name
	History: Created by Kaihua Zhang on 15/8/2012
*/

int main(int argc, char * argv[])
{

	char imgFilePath[100];
    char  conf[100];
	strcpy(conf,"./config.txt");

	char tmpDirPath[MAX_PATH+1];
	
	Rect box; // [x y width height] tracking position

	//矢量容器
	vector <string> imgNames;
    //读取配置文件初始帧的数据[x,y,w,h]
	readConfig(conf,imgFilePath,box);
	//读取图像数据
	readImageSequenceFiles(imgFilePath,imgNames);

	// CT framework
	// 这里把压缩感知跟踪写成了一个C++类
	CompressiveTracker ct;

	Mat frame;
	Mat grayImg;

	//格式化字符串
	sprintf(tmpDirPath, "%s/", imgFilePath);
	imgNames[0].insert(0,tmpDirPath);
	
	//读取第一张图像
	frame = imread(imgNames[0]);
	
	//转换为灰度图
    cvtColor(frame, grayImg, CV_RGB2GRAY);    
	ct.init(grayImg, box);    

	char strFrame[20];

    FILE* resultStream;
	//打开文件,用来写
	resultStream = fopen("TrackingResults.txt", "w");
	//格式化字符串
	fprintf (resultStream,"%i %i %i %i\n",(int)box.x,(int)box.y,(int)box.width,(int)box.height);

	/*******************************************************/
	/*                       运行时                        */
	/*******************************************************/
	//从第二张(帧)图像开始进行跟踪了
	for(int i = 1; i < imgNames.size()-1; i ++)
	{
		//形成图像路径
		sprintf(tmpDirPath, "%s/", imgFilePath);
        imgNames[i].insert(0,tmpDirPath);

        //读取第i图像		
		frame = imread(imgNames[i]);// get frame
		//转化为灰度图像
		cvtColor(frame, grayImg, CV_RGB2GRAY);
		
		ct.processFrame(grayImg, box);// Process frame
		
		rectangle(frame, box, Scalar(200,0,0),2);// Draw rectangle

		fprintf (resultStream,"%i %i %i %i\n",(int)box.x,(int)box.y,(int)box.width,(int)box.height);

		sprintf(strFrame, "#%d ",i) ;

		putText(frame,strFrame,cvPoint(0,20),2,1,CV_RGB(25,200,25));
		
		imshow("CT", frame);// Display
		waitKey(1);		
	}
	fclose(resultStream);

	return 0;
}

//读取配置文件
void readConfig(char* configFileName, char* imgFilePath, Rect &box)	
{
	int x;
	int y;
	int w;
	int h;

	fstream f;
	char cstring[1000];
	int readS=0;
	//打开
	f.open(configFileName, fstream::in);

	char param1[200]; strcpy(param1,"");
	char param2[200]; strcpy(param2,"");
	char param3[200]; strcpy(param3,"");

	f.getline(cstring, sizeof(cstring));
	readS=sscanf (cstring, "%s %s %s", param1,param2, param3);

	strcpy(imgFilePath,param3);

	f.getline(cstring, sizeof(cstring)); 
	f.getline(cstring, sizeof(cstring)); 
	f.getline(cstring, sizeof(cstring));


	readS=sscanf (cstring, "%s %s %i %i %i %i", param1,param2, &x, &y, &w, &h);
	//初始帧目标状态
	box = Rect(x, y, w, h);
	
}

void readImageSequenceFiles(char* imgFilePath,vector <string> &imgNames)
{	
	//清空矢量容器
	imgNames.clear();

	char tmpDirSpec[MAX_PATH+1];
	//格式化字符串
	sprintf (tmpDirSpec, "%s/*", imgFilePath);

	WIN32_FIND_DATA f;
	HANDLE h = FindFirstFile(tmpDirSpec , &f);
	if(h != INVALID_HANDLE_VALUE)
	{
		FindNextFile(h, &f);	//read ..
		FindNextFile(h, &f);	//read .
		do
		{
			//将图像名称放进矢量容器imgNames中
			imgNames.push_back(f.cFileName);
		} while(FindNextFile(h, &f));

	}
	FindClose(h);	
}





评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值