Commit f77a4616 authored by Kurnianggoro's avatar Kurnianggoro

Updated the support for color-names features and fixing some typos

parent df9adff5
...@@ -1189,8 +1189,8 @@ class CV_EXPORTS_W TrackerTLD : public Tracker ...@@ -1189,8 +1189,8 @@ class CV_EXPORTS_W TrackerTLD : public Tracker
BOILERPLATE_CODE("TLD",TrackerTLD); BOILERPLATE_CODE("TLD",TrackerTLD);
}; };
/** @brief KCF is a novel tracking framework that utilize properties of circulant matrix to enhance the processing speed. /** @brief KCF is a novel tracking framework that utilizes properties of circulant matrix to enhance the processing speed.
* This tracking method is implementation of @cite KCF_ECCV which is extended to KFC with color-names features (@cite KCF_CN). * This tracking method is an implementation of @cite KCF_ECCV which is extended to KFC with color-names features (@cite KCF_CN).
* The original paper of KCF is available at <http://home.isr.uc.pt/~henriques/circulant/index.html> * The original paper of KCF is available at <http://home.isr.uc.pt/~henriques/circulant/index.html>
* as well as the matlab implementation. For more information about KCF with color-names features, please refer to * as well as the matlab implementation. For more information about KCF with color-names features, please refer to
* <http://www.cvl.isy.liu.se/research/objrec/visualtracking/colvistrack/index.html>. * <http://www.cvl.isy.liu.se/research/objrec/visualtracking/colvistrack/index.html>.
......
...@@ -88,8 +88,11 @@ namespace cv{ ...@@ -88,8 +88,11 @@ namespace cv{
* KCF functions and vars * KCF functions and vars
*/ */
void createHanningWindow(OutputArray _dst, const cv::Size winSize, const int type) const; void createHanningWindow(OutputArray _dst, const cv::Size winSize, const int type) const;
void inline fft2(const Mat src, std::vector<Mat> & dest) const;
void inline fft2(const Mat src, Mat & dest) const; void inline fft2(const Mat src, Mat & dest) const;
void inline ifft2(const Mat src, Mat & dest) const ; void inline ifft2(const Mat src, Mat & dest) const ;
void inline pixelWiseMult(const std::vector<Mat> src1, const std::vector<Mat> src2, std::vector<Mat> & dest, const int flags, const bool conjB=false) const;
void inline sumChannels(std::vector<Mat> src, Mat & dest) const;
bool getSubWindow(const Mat img, const Rect roi, Mat& patch) const; bool getSubWindow(const Mat img, const Rect roi, Mat& patch) const;
void extractCN(Mat _patch, Mat & cnFeatures) const; void extractCN(Mat _patch, Mat & cnFeatures) const;
void denseGaussKernel(const double sigma, const Mat _x, const Mat _y, Mat & _k) const; void denseGaussKernel(const double sigma, const Mat _x, const Mat _y, Mat & _k) const;
...@@ -127,6 +130,8 @@ namespace cv{ ...@@ -127,6 +130,8 @@ namespace cv{
{ {
isInit = false; isInit = false;
resizeImage = false; resizeImage = false;
CV_Assert(params.descriptor == GRAY || params.descriptor == CN /*|| params.descriptor == CN2*/);
} }
void TrackerKCFImpl::read( const cv::FileNode& fn ){ void TrackerKCFImpl::read( const cv::FileNode& fn ){
...@@ -163,7 +168,7 @@ namespace cv{ ...@@ -163,7 +168,7 @@ namespace cv{
// add padding to the roi // add padding to the roi
roi.x-=roi.width/2; roi.x-=roi.width/2;
roi.y-=roi.height/2+1; roi.y-=roi.height/2;
roi.width*=2; roi.width*=2;
roi.height*=2; roi.height*=2;
...@@ -173,7 +178,6 @@ namespace cv{ ...@@ -173,7 +178,6 @@ namespace cv{
Mat layers[] = {hann, hann, hann, hann, hann, hann, hann, hann, hann, hann}; Mat layers[] = {hann, hann, hann, hann, hann, hann, hann, hann, hann, hann};
merge(layers, 10, hann); merge(layers, 10, hann);
} }
if(params.descriptor != GRAY){printf("The choosen descriptor mode is not available! Please use GRAY descriptor, other descriptors will be avaiable soon.\n");return false;}//temporary, will be updated soon
// create gaussian response // create gaussian response
y=Mat::zeros((int)roi.height,(int)roi.width,CV_64F); y=Mat::zeros((int)roi.height,(int)roi.width,CV_64F);
...@@ -229,18 +233,19 @@ namespace cv{ ...@@ -229,18 +233,19 @@ namespace cv{
// Kernel Regularized Least-Squares, calculate alphas // Kernel Regularized Least-Squares, calculate alphas
denseGaussKernel(params.sigma,x,x,k); denseGaussKernel(params.sigma,x,x,k);
fft2(k,kf); fft2(k,kf);
kf=kf+params.lambda; kf=kf+params.lambda;
/* TODO: optimize this element-wise division /* TODO: optimize this element-wise division
* new_alphaf=yf./kf * new_alphaf=yf./kf
* z=[(ax+bd)+i(bc-ad)]/(c^2+d^2) * z=(a+bi)/(c+di)[(ac+bd)+i(bc-ad)]/(c^2+d^2)
*/ */
new_alphaf=Mat_<Vec2d >(yf.rows, yf.cols); new_alphaf=Mat_<Vec2d >(yf.rows, yf.cols);
std::complex<double> temp; std::complex<double> temp;
for(int i=0;i<yf.rows;i++){ for(int i=0;i<yf.rows;i++){
for(int j=0;j<yf.cols;j++){ for(int j=0;j<yf.cols;j++){
temp=std::complex<double>(yf.at<Vec2d>(i,j)[0],yf.at<Vec2d>(i,j)[1])/(std::complex<double>(kf.at<Vec2d>(i,j)[0],kf.at<Vec2d>(i,j)[1])/*+complex<float>(0.0000000001,0.0000000001)*/); temp=std::complex<double>(yf.at<Vec2d>(i,j)[0],yf.at<Vec2d>(i,j)[1])/(std::complex<double>(kf.at<Vec2d>(i,j)[0],kf.at<Vec2d>(i,j)[1])/*+std::complex<double>(0.0000000001,0.0000000001)*/);
new_alphaf.at<Vec2d >(i,j)[0]=temp.real(); new_alphaf.at<Vec2d >(i,j)[0]=temp.real();
new_alphaf.at<Vec2d >(i,j)[1]=temp.imag(); new_alphaf.at<Vec2d >(i,j)[1]=temp.imag();
} }
...@@ -250,7 +255,7 @@ namespace cv{ ...@@ -250,7 +255,7 @@ namespace cv{
new_z=x.clone(); new_z=x.clone();
if(frame==0){ if(frame==0){
alphaf=new_alphaf.clone(); alphaf=new_alphaf.clone();
z=x; z=x.clone();
}else{ }else{
alphaf=(1.0-params.interp_factor)*alphaf+params.interp_factor*new_alphaf; alphaf=(1.0-params.interp_factor)*alphaf+params.interp_factor*new_alphaf;
z=(1.0-params.interp_factor)*z+params.interp_factor*new_z; z=(1.0-params.interp_factor)*z+params.interp_factor*new_z;
...@@ -309,21 +314,62 @@ namespace cv{ ...@@ -309,21 +314,62 @@ namespace cv{
} }
/* /*
* simplification of fourier transoform function in opencv * simplification of fourier transform function in opencv
*/ */
void inline TrackerKCFImpl::fft2(const Mat src, Mat & dest)const { void inline TrackerKCFImpl::fft2(const Mat src, Mat & dest)const {
Mat planes[] = {Mat_<double>(src), Mat::zeros(src.size(), CV_64F)}; std::vector<Mat> layers(src.channels());
merge(planes, 2, dest); std::vector<Mat> outputs(src.channels());
dft(dest,dest,DFT_COMPLEX_OUTPUT);
split(src, layers);
for(int i=0;i<src.channels();i++){
dft(layers[i],outputs[i],DFT_COMPLEX_OUTPUT);
}
merge(outputs,dest);
}
void inline TrackerKCFImpl::fft2(const Mat src, std::vector<Mat> & dest) const{
std::vector<Mat> layers(src.channels());
dest.clear();
dest.resize(src.channels());
split(src, layers);
for(int i=0;i<src.channels();i++){
dft(layers[i],dest[i],DFT_COMPLEX_OUTPUT);
}
} }
/* /*
* simplification of inverse fourier transoform function in opencv * simplification of inverse fourier transform function in opencv
*/ */
void inline TrackerKCFImpl::ifft2(const Mat src, Mat & dest)const { void inline TrackerKCFImpl::ifft2(const Mat src, Mat & dest)const {
idft(src,dest,DFT_SCALE+DFT_REAL_OUTPUT); idft(src,dest,DFT_SCALE+DFT_REAL_OUTPUT);
} }
/*
* Point-wise multiplication of two Multichannel Mat data
*/
void inline TrackerKCFImpl::pixelWiseMult(const std::vector<Mat> src1, const std::vector<Mat> src2, std::vector<Mat> & dest, const int flags, const bool conjB) const{
dest.clear();
dest.resize(src1.size());
for(unsigned i=0;i<src1.size();i++){
mulSpectrums(src1[i], src2[i], dest[i],flags,conjB);
}
}
/*
* Combines all channels in a multi-channels Mat data into a single channel
*/
void inline TrackerKCFImpl::sumChannels(std::vector<Mat> src, Mat & dest) const{
dest=src[0].clone();
for(unsigned i=1;i<src.size();i++){
dest+=src[i];
}
}
/* /*
* obtain the patch and apply hann window filter to it * obtain the patch and apply hann window filter to it
*/ */
...@@ -356,24 +402,24 @@ namespace cv{ ...@@ -356,24 +402,24 @@ namespace cv{
addRight=(_roi.width+_roi.x>img.cols?_roi.width+_roi.x-img.cols:0); addRight=(_roi.width+_roi.x>img.cols?_roi.width+_roi.x-img.cols:0);
copyMakeBorder(patch,patch,addTop,addBottom,addLeft,addRight,BORDER_REPLICATE); copyMakeBorder(patch,patch,addTop,addBottom,addLeft,addRight,BORDER_REPLICATE);
if(patch.rows==0 || patch.cols==0)return false;
// extract the desired descriptors // extract the desired descriptors
switch(params.descriptor){ switch(params.descriptor){
case GRAY: case GRAY:
if(img.channels()>1)cvtColor(patch,patch, CV_BGR2GRAY); if(img.channels()>1)cvtColor(patch,patch, CV_BGR2GRAY);
patch.convertTo(patch,CV_64F);
patch=patch/255.0-0.5; // normalize to range -0.5 .. 0.5
break; break;
case CN: case CN:
CV_Assert(img.channels() == 3); CV_Assert(img.channels() == 3);
extractCN(patch,patch); extractCN(patch,patch);
break; break;
default: case CN2:
if(patch.channels()>1)cvtColor(patch,patch, CV_BGR2GRAY); if(patch.channels()>1)cvtColor(patch,patch, CV_BGR2GRAY);
break; break;
} }
patch.convertTo(patch,CV_64F);
patch=patch/255.0-0.5; // normalize to range -0.5 .. 0.5
patch=patch.mul(hann); // hann window filter patch=patch.mul(hann); // hann window filter
return true; return true;
...@@ -407,25 +453,26 @@ namespace cv{ ...@@ -407,25 +453,26 @@ namespace cv{
* dense gauss kernel function * dense gauss kernel function
*/ */
void TrackerKCFImpl::denseGaussKernel(const double sigma, const Mat _x, const Mat _y, Mat & _k)const{ void TrackerKCFImpl::denseGaussKernel(const double sigma, const Mat _x, const Mat _y, Mat & _k)const{
Mat _xf, _yf, xyf,xy; std::vector<Mat> _xf,_yf,xyf_v;
Mat xy,xyf;
double normX, normY; double normX, normY;
fft2(_x,_xf); fft2(_x,_xf);
fft2(_y,_yf); fft2(_y,_yf);
normX=norm(_x); normX=norm(_x);
normX*=normX; normX*=normX;
normY=norm(_y); normY=norm(_y);
normY*=normY; normY*=normY;
mulSpectrums(_xf,_yf,xyf,0,true); pixelWiseMult(_xf,_yf,xyf_v,0,true);
sumChannels(xyf_v,xyf);
ifft2(xyf,xyf); ifft2(xyf,xyf);
shiftRows(xyf, _x.rows/2); // shiftRows(xyf, _x.rows/2);
shiftCols(xyf,_x.cols/2); // shiftCols(xyf, _x.cols/2);
//(xx + yy - 2 * xy) / numel(x) //(xx + yy - 2 * xy) / numel(x)
xy=(normX+normY-2*xyf)/(_x.rows*_x.cols); xy=(normX+normY-2*xyf)/(_x.rows*_x.cols*_x.channels());
// TODO: check wether we really need thresholding or not // TODO: check wether we really need thresholding or not
//threshold(xy,xy,0.0,0.0,THRESH_TOZERO);//max(0, (xx + yy - 2 * xy) / numel(x)) //threshold(xy,xy,0.0,0.0,THRESH_TOZERO);//max(0, (xx + yy - 2 * xy) / numel(x))
...@@ -441,7 +488,7 @@ namespace cv{ ...@@ -441,7 +488,7 @@ namespace cv{
} }
/* CIRCULAR SHIT Function /* CIRCULAR SHIFT Function
* http://stackoverflow.com/questions/10420454/shift-like-matlab-function-rows-or-columns-of-a-matrix-in-opencv * http://stackoverflow.com/questions/10420454/shift-like-matlab-function-rows-or-columns-of-a-matrix-in-opencv
*/ */
// circular shift one row from up to down // circular shift one row from up to down
...@@ -523,16 +570,12 @@ namespace cv{ ...@@ -523,16 +570,12 @@ namespace cv{
interp_factor=0.075; interp_factor=0.075;
output_sigma_factor=1.0/16.0; output_sigma_factor=1.0/16.0;
resize=true; resize=true;
max_patch_size=80*80; max_patch_size=100*100;
descriptor=GRAY; descriptor=CN;
} }
void TrackerKCF::Params::read( const cv::FileNode& /*fn*/ ){ void TrackerKCF::Params::read( const cv::FileNode& /*fn*/ ){}
}
void TrackerKCF::Params::write( cv::FileStorage& /*fs*/ ) const{ void TrackerKCF::Params::write( cv::FileStorage& /*fs*/ ) const{}
}
} /* namespace cv */ } /* namespace cv */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment