Commit 4fa8b2de authored by Vadim Pisarevsky's avatar Vadim Pisarevsky

Merge pull request #55 from nailbiter/luca

TLD
parents 3322aeed eee3e052
...@@ -9,6 +9,10 @@ The following algorithms are implemented at the moment. ...@@ -9,6 +9,10 @@ The following algorithms are implemented at the moment.
.. [OLB] H Grabner, M Grabner, and H Bischof, Real-time tracking via on-line boosting, In Proc. BMVC, volume 1, pages 47– 56, 2006 .. [OLB] H Grabner, M Grabner, and H Bischof, Real-time tracking via on-line boosting, In Proc. BMVC, volume 1, pages 47– 56, 2006
.. [MedianFlow] Z. Kalal, K. Mikolajczyk, and J. Matas, “Forward-Backward Error: Automatic Detection of Tracking Failures,” International Conference on Pattern Recognition, 2010, pp. 23-26.
.. [TLD] Z. Kalal, K. Mikolajczyk, and J. Matas, “Tracking-Learning-Detection,” Pattern Analysis and Machine Intelligence 2011.
TrackerBoosting TrackerBoosting
--------------- ---------------
...@@ -63,7 +67,7 @@ Constructor ...@@ -63,7 +67,7 @@ Constructor
:param parameters: BOOSTING parameters :ocv:struct:`TrackerBoosting::Params` :param parameters: BOOSTING parameters :ocv:struct:`TrackerBoosting::Params`
TrackerMIL TrackerMIL
---------- ----------------------
The MIL algorithm trains a classifier in an online manner to separate the object from the background. Multiple Instance Learning avoids the drift problem for a robust tracking. The implementation is based on [MIL]_. The MIL algorithm trains a classifier in an online manner to separate the object from the background. Multiple Instance Learning avoids the drift problem for a robust tracking. The implementation is based on [MIL]_.
...@@ -118,3 +122,105 @@ Constructor ...@@ -118,3 +122,105 @@ Constructor
.. ocv:function:: Ptr<trackerMIL> TrackerMIL::createTracker(const trackerMIL::Params &parameters=trackerMIL::Params()) .. ocv:function:: Ptr<trackerMIL> TrackerMIL::createTracker(const trackerMIL::Params &parameters=trackerMIL::Params())
:param parameters: MIL parameters :ocv:struct:`TrackerMIL::Params` :param parameters: MIL parameters :ocv:struct:`TrackerMIL::Params`
TrackerMedianFlow
----------------------
Implementation of a paper "Forward-Backward Error: Automatic Detection of Tracking Failures" by Z. Kalal, K. Mikolajczyk
and Jiri Matas. The implementation is based on [MedianFlow]_.
The tracker is suitable for very smooth and predictable movements when object is visible throughout the whole sequence. It's quite and
accurate for this type of problems (in particular, it was shown by authors to outperform MIL). During the implementation period the code at
http://www.aonsquared.co.uk/node/5, the courtesy of the author Arthur Amarra, was used for the reference purpose.
.. ocv:class:: TrackerMedianFlow
Implementation of TrackerMedianFlow from :ocv:class:`Tracker`::
class CV_EXPORTS_W TrackerMedianFlow : public Tracker
{
public:
void read( const FileNode& fn );
void write( FileStorage& fs ) const;
static Ptr<trackerMedianFlow> createTracker(const trackerMedianFlow::Params &parameters=trackerMedianFlow::Params());
virtual ~trackerMedianFlow(){};
protected:
bool initImpl( const Mat& image, const Rect2d& boundingBox );
bool updateImpl( const Mat& image, Rect2d& boundingBox );
};
TrackerMedianFlow::Params
------------------------------------
.. ocv:struct:: TrackerMedianFlow::Params
List of MedianFlow parameters::
struct CV_EXPORTS Params
{
Params();
int pointsInGrid; //square root of number of keypoints used; increase it to trade
//accurateness for speed; default value is sensible and recommended
void read( const FileNode& fn );
void write( FileStorage& fs ) const;
};
TrackerMedianFlow::createTracker
-----------------------------------
Constructor
.. ocv:function:: Ptr<trackerMedianFlow> TrackerMedianFlow::createTracker(const trackerMedianFlow::Params &parameters=trackerMedianFlow::Params())
:param parameters: Median Flow parameters :ocv:struct:`TrackerMedianFlow::Params`
TrackerTLD
----------------------
TLD is a novel tracking framework that explicitly decomposes the long-term tracking task into tracking, learning and detection. The tracker follows the object from frame to frame. The detector localizes all appearances that have been observed so far and corrects the tracker if necessary. The learning estimates detector’s errors and updates it to avoid these errors in the future. The implementation is based on [TLD]_.
The Median Flow algorithm (see above) was chosen as a tracking component in this implementation, following authors. Tracker is supposed to be able
to handle rapid motions, partial occlusions, object absence etc.
.. ocv:class:: TrackerTLD
Implementation of TrackerTLD from :ocv:class:`Tracker`::
class CV_EXPORTS_W TrackerTLD : public Tracker
{
public:
void read( const FileNode& fn );
void write( FileStorage& fs ) const;
static Ptr<trackerTLD> createTracker(const trackerTLD::Params &parameters=trackerTLD::Params());
virtual ~trackerTLD(){};
protected:
bool initImpl( const Mat& image, const Rect2d& boundingBox );
bool updateImpl( const Mat& image, Rect2d& boundingBox );
};
TrackerTLD::Params
------------------------
.. ocv:struct:: TrackerTLD::Params
List of TLD parameters::
struct CV_EXPORTS Params
{
Params();
void read( const FileNode& fn );
void write( FileStorage& fs ) const;
};
TrackerTLD::createTracker
-------------------------------
Constructor
.. ocv:function:: Ptr<trackerTLD> TrackerTLD::createTracker(const trackerTLD::Params &parameters=trackerTLD::Params())
:param parameters: TLD parameters :ocv:struct:`TrackerTLD::Params`
...@@ -1017,7 +1017,8 @@ class CV_EXPORTS_W TrackerMedianFlow : public Tracker ...@@ -1017,7 +1017,8 @@ class CV_EXPORTS_W TrackerMedianFlow : public Tracker
struct CV_EXPORTS Params struct CV_EXPORTS Params
{ {
Params(); Params();
int pointsInGrid; int pointsInGrid; //square root of number of keypoints used; increase it to trade
//accurateness for speed; default value is sensible and recommended
void read( const FileNode& /*fn*/ ); void read( const FileNode& /*fn*/ );
void write( FileStorage& /*fs*/ ) const; void write( FileStorage& /*fs*/ ) const;
}; };
......
...@@ -7,9 +7,9 @@ ...@@ -7,9 +7,9 @@
#include <cstring> #include <cstring>
#include <climits> #include <climits>
#define CMDLINEMAX 10 const int CMDLINEMAX = 30;
#define ASSESS_TILL 100 const int ASSESS_TILL = 100;
#define LINEMAX 40 const int LINEMAX = 40;
using namespace std; using namespace std;
using namespace cv; using namespace cv;
...@@ -20,7 +20,8 @@ using namespace cv; ...@@ -20,7 +20,8 @@ using namespace cv;
static Mat image; static Mat image;
static bool paused; static bool paused;
vector<Scalar> palette; static bool saveImageKey;
static vector<Scalar> palette;
void print_table(char* videos[],int videoNum,char* algorithms[],int algNum,const vector<vector<char*> >& results,char* tableName); void print_table(char* videos[],int videoNum,char* algorithms[],int algNum,const vector<vector<char*> >& results,char* tableName);
...@@ -67,20 +68,15 @@ static void help(){ ...@@ -67,20 +68,15 @@ static void help(){
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
static void parseCommandLineArgs(int argc, char** argv,char* videos[],char* gts[], static void parseCommandLineArgs(int argc, char** argv,char* videos[],char* gts[],
int* vc,char* algorithms[],char* initBoxes[][CMDLINEMAX],int* ac){ int* vc,char* algorithms[],char* initBoxes[][CMDLINEMAX],int* ac,char keys[CMDLINEMAX][LINEMAX]){
*ac=*vc=0; *ac=*vc=0;
for(int i=1;i<argc;i++){ for(int i=1;i<argc;i++){
if(argv[i][0]=='-'){ if(argv[i][0]=='-'){
char *key=(argv[i]+1),*argument=NULL; for(int j=0;j<CMDLINEMAX;j++){
if(std::strcmp("h",key)==0||std::strcmp("help",key)==0){ if(!strcmp(argv[i],keys[j])){
help(); keys[j][0]='\0';
} }
if((argument=strchr(argv[i],'='))==NULL){
i++;
argument=argv[i];
}else{
argument++;
} }
continue; continue;
} }
...@@ -193,6 +189,8 @@ static AssessmentRes assessment(char* video,char* gt_str, char* algorithms[],cha ...@@ -193,6 +189,8 @@ static AssessmentRes assessment(char* video,char* gt_str, char* algorithms[],cha
int linecount=0; int linecount=0;
Rect2d boundingBox; Rect2d boundingBox;
vector<double> averageMillisPerFrame(algnum,0.0); vector<double> averageMillisPerFrame(algnum,0.0);
static int videoNum=0;
videoNum++;
FILE* gt=fopen(gt_str,"r"); FILE* gt=fopen(gt_str,"r");
if(gt==NULL){ if(gt==NULL){
...@@ -312,6 +310,11 @@ static AssessmentRes assessment(char* video,char* gt_str, char* algorithms[],cha ...@@ -312,6 +310,11 @@ static AssessmentRes assessment(char* video,char* gt_str, char* algorithms[],cha
res.results[i][j]->assess(boundingBox,initBoxes[i]); res.results[i][j]->assess(boundingBox,initBoxes[i]);
} }
imshow( "Tracking API", image ); imshow( "Tracking API", image );
if(saveImageKey){
char inbuf[LINEMAX];
sprintf(inbuf,"image%d_%d.jpg",videoNum,frameCounter);
imwrite(inbuf,image);
}
if((frameCounter+1)>=ASSESS_TILL){ if((frameCounter+1)>=ASSESS_TILL){
break; break;
...@@ -342,7 +345,11 @@ int main( int argc, char** argv ){ ...@@ -342,7 +345,11 @@ int main( int argc, char** argv ){
palette.push_back(Scalar(0,255,255)); palette.push_back(Scalar(0,255,255));
int vcount=0,acount=0; int vcount=0,acount=0;
char* videos[CMDLINEMAX],*gts[CMDLINEMAX],*algorithms[CMDLINEMAX],*initBoxes[CMDLINEMAX][CMDLINEMAX]; char* videos[CMDLINEMAX],*gts[CMDLINEMAX],*algorithms[CMDLINEMAX],*initBoxes[CMDLINEMAX][CMDLINEMAX];
parseCommandLineArgs(argc,argv,videos,gts,&vcount,algorithms,initBoxes,&acount); char keys[CMDLINEMAX][LINEMAX];
strcpy(keys[0],"-s");
parseCommandLineArgs(argc,argv,videos,gts,&vcount,algorithms,initBoxes,&acount,keys);
saveImageKey=(keys[0][0]=='\0');
CV_Assert(acount<CMDLINEMAX && vcount<CMDLINEMAX); CV_Assert(acount<CMDLINEMAX && vcount<CMDLINEMAX);
printf("videos and gts\n"); printf("videos and gts\n");
for(int i=0;i<vcount;i++){ for(int i=0;i<vcount;i++){
...@@ -361,7 +368,7 @@ int main( int argc, char** argv ){ ...@@ -361,7 +368,7 @@ int main( int argc, char** argv ){
for(int i=0;i<vcount;i++){ for(int i=0;i<vcount;i++){
results.push_back(assessment(videos[i],gts[i],algorithms,((char**)initBoxes)+i,acount)); results.push_back(assessment(videos[i],gts[i],algorithms,((char**)initBoxes)+i,acount));
} }
CV_Assert(results[0].results[0].size()<CMDLINEMAX); CV_Assert( (int)results[0].results[0].size() < CMDLINEMAX );
printf("\n\n"); printf("\n\n");
char buf[CMDLINEMAX*CMDLINEMAX*LINEMAX], buf2[CMDLINEMAX*40]; char buf[CMDLINEMAX*CMDLINEMAX*LINEMAX], buf2[CMDLINEMAX*40];
......
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
...@@ -42,8 +42,8 @@ ...@@ -42,8 +42,8 @@
#include "precomp.hpp" #include "precomp.hpp"
#include "opencv2/video/tracking.hpp" #include "opencv2/video/tracking.hpp"
#include "opencv2/imgproc.hpp" #include "opencv2/imgproc.hpp"
#include <algorithm> #include<algorithm>
#include <limits.h> #include<limits.h>
namespace cv {namespace tld namespace cv {namespace tld
{ {
...@@ -57,53 +57,68 @@ namespace cv {namespace tld ...@@ -57,53 +57,68 @@ namespace cv {namespace tld
#define dfprintf(x) #define dfprintf(x)
#define dprintf(x) #define dprintf(x)
#endif #endif
#define MEASURE_TIME(a) {\ #define MEASURE_TIME(a)\
clock_t start;float milisec=0.0;\ {\
start=clock();{a} milisec=1000.0*(clock()-start)/CLOCKS_PER_SEC;\ clock_t start; float milisec = 0.0; \
dprintf(("%-90s took %f milis\n",#a,milisec)); } start = clock(); {a} milisec = 1000.0 * (clock() - start) / CLOCKS_PER_SEC; \
#define HERE dprintf(("%d\n",__LINE__));fflush(stderr); dprintf(("%-90s took %f milis\n", #a, milisec));\
#define START_TICK(name) { clock_t start;double milisec=0.0; start=clock(); }
#define END_TICK(name) milisec=1000.0*(clock()-start)/CLOCKS_PER_SEC;\ #define HERE dprintf(("line %d\n", __LINE__)); fflush(stderr);
dprintf(("%s took %f milis\n",name,milisec)); } #define START_TICK(name)\
{ \
clock_t start; double milisec = 0.0; start = clock();
#define END_TICK(name) milisec = 1000.0 * (clock() - start) / CLOCKS_PER_SEC; \
dprintf(("%s took %f milis\n", name, milisec)); \
}
extern Rect2d etalon; extern Rect2d etalon;
void myassert(const Mat& img); void myassert(const Mat& img);
void printPatch(const Mat_<uchar>& standardPatch); void printPatch(const Mat_<uchar>& standardPatch);
std::string type2str(const Mat& mat); std::string type2str(const Mat& mat);
void drawWithRects(const Mat& img,std::vector<Rect2d>& blackOnes,Rect2d whiteOne=Rect2d(-1.0,-1.0,-1.0,-1.0)); void drawWithRects(const Mat& img, std::vector<Rect2d>& blackOnes, Rect2d whiteOne = Rect2d(-1.0, -1.0, -1.0, -1.0));
void drawWithRects(const Mat& img,std::vector<Rect2d>& blackOnes,std::vector<Rect2d>& whiteOnes); void drawWithRects(const Mat& img, std::vector<Rect2d>& blackOnes, std::vector<Rect2d>& whiteOnes, String fileName = "");
//aux functions and variables //aux functions and variables
//#define CLIP(x,a,b) MIN(MAX((x),(a)),(b)) template<typename T> inline T CLIP(T x, T a, T b){ return std::min(std::max(x, a), b); }
template<typename T> inline T CLIP(T x,T a,T b){return MIN(MAX(x,a),b);} /** Computes overlap between the two given rectangles. Overlap is computed as ratio of rectangles' intersection to that
double overlap(const Rect2d& r1,const Rect2d& r2); * of their union.*/
void resample(const Mat& img,const RotatedRect& r2,Mat_<uchar>& samples); double overlap(const Rect2d& r1, const Rect2d& r2);
void resample(const Mat& img,const Rect2d& r2,Mat_<uchar>& samples); /** Resamples the area surrounded by r2 in img so it matches the size of samples, where it is written.*/
void resample(const Mat& img, const RotatedRect& r2, Mat_<uchar>& samples);
/** Specialization of resample() for rectangles without retation for better performance and simplicity.*/
void resample(const Mat& img, const Rect2d& r2, Mat_<uchar>& samples);
/** Computes the variance of single given image.*/
double variance(const Mat& img); double variance(const Mat& img);
double variance(Mat_<double>& intImgP,Mat_<double>& intImgP2,Rect box); /** Computes normalized corellation coefficient between the two patches (they should be
double NCC(Mat_<uchar> patch1,Mat_<uchar> patch2); * of the same size).*/
void getClosestN(std::vector<Rect2d>& scanGrid,Rect2d bBox,int n,std::vector<Rect2d>& res); double NCC(const Mat_<uchar>& patch1, const Mat_<uchar>& patch2);
double scaleAndBlur(const Mat& originalImg,int scale,Mat& scaledImg,Mat& blurredImg,Size GaussBlurKernelSize); void getClosestN(std::vector<Rect2d>& scanGrid, Rect2d bBox, int n, std::vector<Rect2d>& res);
unsigned int getMedian(const std::vector<unsigned int>& values, int size=-1); double scaleAndBlur(const Mat& originalImg, int scale, Mat& scaledImg, Mat& blurredImg, Size GaussBlurKernelSize, double scaleStep);
int getMedian(const std::vector<int>& values, int size = -1);
class TLDEnsembleClassifier{ class TLDEnsembleClassifier
{
public: public:
TLDEnsembleClassifier(int ordinal,Size size,int measurePerClassifier); static int makeClassifiers(Size size, int measurePerClassifier, int gridSize, std::vector<TLDEnsembleClassifier>& classifiers);
void integrate(Mat_<uchar> patch,bool isPositive); void integrate(const Mat_<uchar>& patch, bool isPositive);
double posteriorProbability(const uchar* data,int rowstep)const; double posteriorProbability(const uchar* data, int rowstep) const;
static int getMaxOrdinal(); double posteriorProbabilityFast(const uchar* data) const;
void prepareClassifier(int rowstep);
private: private:
static int getGridSize(); TLDEnsembleClassifier(const std::vector<Vec4b>& meas, int beg, int end);
inline void stepPrefSuff(std::vector<uchar>& arr,int len); static void stepPrefSuff(std::vector<Vec4b> & arr, int pos, int len, int gridSize);
void preinit(int ordinal); int code(const uchar* data, int rowstep) const;
unsigned short int code(const uchar* data,int rowstep)const; int codeFast(const uchar* data) const;
std::vector<unsigned int> pos,neg; std::vector<Point2i> posAndNeg;
std::vector<uchar> x1,y1,x2,y2; std::vector<Vec4b> measurements;
std::vector<Point2i> offset;
int lastStep_;
}; };
class TrackerProxy{ class TrackerProxy
{
public: public:
virtual bool init( const Mat& image, const Rect2d& boundingBox)=0; virtual bool init(const Mat& image, const Rect2d& boundingBox) = 0;
virtual bool update(const Mat& image, Rect2d& boundingBox)=0; virtual bool update(const Mat& image, Rect2d& boundingBox) = 0;
virtual ~TrackerProxy(){} virtual ~TrackerProxy(){}
}; };
......
This diff is collapsed.
This diff is collapsed.
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