您的位置:首页 > 其它

压缩感知跟踪(二)

2014-04-10 16:05 375 查看
上一篇博客我按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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: