From 1940c120aca23bc347e9f807b33894019bad9886 Mon Sep 17 00:00:00 2001 From: Alex Leontiev Date: Wed, 2 Jul 2014 22:46:45 +0900 Subject: [PATCH] More abstract tracker declaration This contribution changes the way how trackers should be implemented by programmer. It should be noted first, that from the user prospective, Tracker::create() method still can be called with the same effect. However, there's no more thing as a "constructor" for Tracker, they should be created via static functions, e.g. static Ptr createTracker(const TrackerMIL::Params ¶meters=TrackerMIL::Params()); From the programmer's perspective now for every tracker what is declared in tracker.hpp header is more a "interface", while the real implementation class can (and has to) be implemented in .cpp file. Changes in documentation are also included. --- .../doc/common_interfaces_tracker.rst | 68 ++++++++++++------- modules/tracking/doc/tracker_algorithms.rst | 57 ++++++++-------- modules/tracking/include/opencv2/tracking.hpp | 4 +- .../include/opencv2/tracking/tracker.hpp | 50 +++----------- modules/tracking/src/tracker.cpp | 15 +++- modules/tracking/src/trackerBoosting.cpp | 36 ++++++---- modules/tracking/src/trackerMIL.cpp | 39 +++++++---- modules/tracking/src/tracking_init.cpp | 10 +-- 8 files changed, 148 insertions(+), 131 deletions(-) diff --git a/modules/tracking/doc/common_interfaces_tracker.rst b/modules/tracking/doc/common_interfaces_tracker.rst index a19377f69..73960adba 100644 --- a/modules/tracking/doc/common_interfaces_tracker.rst +++ b/modules/tracking/doc/common_interfaces_tracker.rst @@ -69,35 +69,57 @@ The following detector types are supported: Creating Own Tracker -------------------- -If you want create a new tracker, you should follow some simple rules. - -First, your tracker should be inherit from :ocv:class:`Tracker`, so you must implement two method: - -* Tracker: initImpl, it should be called once in the first frame, here you should initialize all structures. The second argument is the initial bounding box of the target. - -* Tracker:updateImpl, it should be called at the begin of in loop through video frames. Here you should overwrite the bounding box with new location. - -Example of creating specialized Tracker ``TrackerMIL`` : :: - - class CV_EXPORTS_W TrackerMIL : public Tracker - { - public: - TrackerMIL( const TrackerMIL::Params ¶meters = TrackerMIL::Params() ); - virtual ~TrackerMIL(); - ... +If you want create a new tracker, here's what you have to do. First, decide on the name of the class for the tracker (to meet the existing style, +we suggest something with prefix "tracker", e.g. trackerMIL, trackerBoosting) -- we shall refer to this choice as to "classname" in subsequent. Also, +you should decide upon the name of the tracker, is it will be known to user (the current style suggests using all capitals, say MIL or BOOSTING) -- +we'll call it a "name". + +* Declare your tracker in ``include/opencv2/tracking/tracker.hpp``. + Your tracker should inherit from :ocv:class:`Tracker` (please, see the example below). You should declare the specialized ``Param`` + structure, where you probably will want to put the data, needed to initialize your tracker. Also don't forget to put the + BOILERPLATE_CODE(name,classname) macro inside the class declaration. That macro will generate static ``createTracker()`` function, which + we'll talk about later. You should get something similar to :: + + class CV_EXPORTS_W TrackerMIL : public Tracker + { + public: + struct CV_EXPORTS Params + { + Params(); + //parameters for sampler + float samplerInitInRadius; // radius for gathering positive instances during init + int samplerInitMaxNegNum; // # negative samples to use during init + float samplerSearchWinSize; // size of search window + float samplerTrackInRadius; // radius for gathering positive instances during tracking + int samplerTrackMaxPosNum; // # positive samples to use during tracking + int samplerTrackMaxNegNum; // # negative samples to use during tracking + int featureSetNumFeatures; // #features + + void read( const FileNode& fn ); + void write( FileStorage& fs ) const; + }; + + of course, you can also add any additional methods of your choice. It should be pointed out, however, that it is not expected to have a constructor + declared, as creation should be done via the corresponding ``createTracker()`` method. +* In ``src/tracker.cpp`` file add BOILERPLATE_CODE(name,classname) line to the body of ``Tracker::create()`` method you will find there, like :: + + Ptr Tracker::create( const String& trackerType ) + { + BOILERPLATE_CODE("BOOSTING",TrackerBoosting); + BOILERPLATE_CODE("MIL",TrackerMIL); + return Ptr(); + } +* Finally, you should implement the function with signature :: - protected: - bool initImpl( const Mat& image, const Rect2d& boundingBox ); - bool updateImpl( const Mat& image, Rect2d& boundingBox ); - ... - }; + Ptr classname::createTracker(const classname::Params ¶meters){ + ... + } + That function can (and probably will) return a pointer to some derived class of "classname", which will probably have a real constructor. Every tracker has three component :ocv:class:`TrackerSampler`, :ocv:class:`TrackerFeatureSet` and :ocv:class:`TrackerModel`. The first two are instantiated from Tracker base class, instead the last component is abstract, so you must implement your TrackerModel. -Finally add your tracker in the file tracking_init.cpp - TrackerSampler .............. diff --git a/modules/tracking/doc/tracker_algorithms.rst b/modules/tracking/doc/tracker_algorithms.rst index b8fed894a..d20b10607 100644 --- a/modules/tracking/doc/tracker_algorithms.rst +++ b/modules/tracking/doc/tracker_algorithms.rst @@ -20,19 +20,18 @@ The classifier uses the surrounding background as negative examples in update st Implementation of TrackerBoosting from :ocv:class:`Tracker`:: - class CV_EXPORTS_W TrackerBoosting : public Tracker - { - public: - - TrackerBoosting( const TrackerBoosting::Params ¶meters = TrackerBoosting::Params() ); - - virtual ~TrackerBoosting(); - - void read( const FileNode& fn ); - void write( FileStorage& fs ) const; - - - }; + class CV_EXPORTS_W TrackerBoosting : public Tracker + { + public: + void read( const FileNode& fn ); + void write( FileStorage& fs ) const; + static Ptr createTracker(const trackerBoosting::Params ¶meters=trackerBoosting::Params()); + virtual ~trackerBoosting(){}; + + protected: + bool initImpl( const Mat& image, const Rect2d& boundingBox ); + bool updateImpl( const Mat& image, Rect2d& boundingBox ); + }; TrackerBoosting::Params ----------------------------------------------------------------------- @@ -54,12 +53,12 @@ List of BOOSTING parameters:: void write( FileStorage& fs ) const; }; -TrackerBoosting::TrackerBoosting +TrackerBoosting::createTracker ----------------------------------------------------------------------- Constructor -.. ocv:function:: bool TrackerBoosting::TrackerBoosting( const TrackerBoosting::Params ¶meters = TrackerBoosting::Params() ) +.. ocv:function:: Ptr TrackerBoosting::createTracker(const trackerBoosting::Params ¶meters=trackerBoosting::Params()) :param parameters: BOOSTING parameters :ocv:struct:`TrackerBoosting::Params` @@ -74,18 +73,18 @@ Original code can be found here http://vision.ucsd.edu/~bbabenko/project_miltrac Implementation of TrackerMIL from :ocv:class:`Tracker`:: - class CV_EXPORTS_W TrackerMIL : public Tracker - { - public: - - TrackerMIL( const TrackerMIL::Params ¶meters = TrackerMIL::Params() ); + class CV_EXPORTS_W TrackerMIL : public Tracker + { + public: + void read( const FileNode& fn ); + void write( FileStorage& fs ) const; + static Ptr createTracker(const trackerMIL::Params ¶meters=trackerMIL::Params()); + virtual ~trackerMIL(){}; - virtual ~TrackerMIL(); - - void read( const FileNode& fn ); - void write( FileStorage& fs ) const; - - }; + protected: + bool initImpl( const Mat& image, const Rect2d& boundingBox ); + bool updateImpl( const Mat& image, Rect2d& boundingBox ); + }; TrackerMIL::Params ------------------ @@ -111,11 +110,11 @@ List of MIL parameters:: void write( FileStorage& fs ) const; }; -TrackerMIL::TrackerMIL ----------------------- +TrackerMIL::createTracker +------------------------------- Constructor -.. ocv:function:: bool TrackerMIL::TrackerMIL( const TrackerMIL::Params ¶meters = TrackerMIL::Params() ) +.. ocv:function:: Ptr TrackerMIL::createTracker(const trackerMIL::Params ¶meters=trackerMIL::Params()) :param parameters: MIL parameters :ocv:struct:`TrackerMIL::Params` diff --git a/modules/tracking/include/opencv2/tracking.hpp b/modules/tracking/include/opencv2/tracking.hpp index 55fb05d40..1b6ea87ff 100644 --- a/modules/tracking/include/opencv2/tracking.hpp +++ b/modules/tracking/include/opencv2/tracking.hpp @@ -42,11 +42,13 @@ #ifndef __OPENCV_TRACKING_HPP__ #define __OPENCV_TRACKING_HPP__ -#include "opencv2/tracking/tracker.hpp" +#include "opencv2/core/cvdef.h" namespace cv { CV_EXPORTS bool initModule_tracking(void); } +#include "opencv2/tracking/tracker.hpp" + #endif //__OPENCV_TRACKING_HPP__ diff --git a/modules/tracking/include/opencv2/tracking/tracker.hpp b/modules/tracking/include/opencv2/tracking/tracker.hpp index 94933a211..bbbae3431 100644 --- a/modules/tracking/include/opencv2/tracking/tracker.hpp +++ b/modules/tracking/include/opencv2/tracking/tracker.hpp @@ -50,6 +50,10 @@ #include "opencv2/optim.hpp" #include +#define BOILERPLATE_CODE(name,classname) \ + static Ptr createTracker(const classname::Params ¶meters=classname::Params());\ + virtual ~classname(){}; + /* * Partially based on: * ==================================================================================================================== @@ -497,6 +501,9 @@ class CV_EXPORTS_W Tracker : public virtual Algorithm */ static Ptr create( const String& trackerType ); + virtual void read( const FileNode& fn )=0; + virtual void write( FileStorage& fs ) const=0; + protected: virtual bool initImpl( const Mat& image, const Rect2d& boundingBox ) = 0; @@ -507,7 +514,7 @@ class CV_EXPORTS_W Tracker : public virtual Algorithm Ptr featureSet; Ptr sampler; Ptr model; - + virtual AlgorithmInfo* info() const; }; /************************************ Specific TrackerStateEstimator Classes ************************************/ @@ -961,33 +968,13 @@ class CV_EXPORTS_W TrackerMIL : public Tracker float samplerTrackInRadius; // radius for gathering positive instances during tracking int samplerTrackMaxPosNum; // # positive samples to use during tracking int samplerTrackMaxNegNum; // # negative samples to use during tracking - int featureSetNumFeatures; // #features void read( const FileNode& fn ); void write( FileStorage& fs ) const; }; - /** - * \brief TrackerMIL Constructor - * \param parameters TrackerMIL parameters - */ - TrackerMIL( const TrackerMIL::Params ¶meters = TrackerMIL::Params() ); - - virtual ~TrackerMIL(); - - void read( const FileNode& fn ); - void write( FileStorage& fs ) const; - - protected: - - bool initImpl( const Mat& image, const Rect2d& boundingBox ); - bool updateImpl( const Mat& image, Rect2d& boundingBox ); - void compute_integral( const Mat & img, Mat & ii_img ); - - Params params; - AlgorithmInfo* info() const; - + BOILERPLATE_CODE("MIL",TrackerMIL); }; /** @@ -1016,24 +1003,7 @@ class CV_EXPORTS_W TrackerBoosting : public Tracker void write( FileStorage& fs ) const; }; - /** - * \brief TrackerBoosting Constructor - * \param parameters TrackerBoosting parameters - */ - TrackerBoosting( const TrackerBoosting::Params ¶meters = TrackerBoosting::Params() ); - - virtual ~TrackerBoosting(); - - void read( const FileNode& fn ); - void write( FileStorage& fs ) const; - - protected: - - bool initImpl( const Mat& image, const Rect2d& boundingBox ); - bool updateImpl( const Mat& image, Rect2d& boundingBox ); - - Params params; - AlgorithmInfo* info() const; + BOILERPLATE_CODE("BOOSTING",TrackerBoosting); }; } /* namespace cv */ diff --git a/modules/tracking/src/tracker.cpp b/modules/tracking/src/tracker.cpp index 519db0c97..f3b83671a 100644 --- a/modules/tracking/src/tracker.cpp +++ b/modules/tracking/src/tracker.cpp @@ -41,6 +41,12 @@ #include "precomp.hpp" +#undef BOILERPLATE_CODE +#define BOILERPLATE_CODE(name,classname)\ + if(trackerType==name){\ + return classname::createTracker();\ + } + namespace cv { @@ -98,10 +104,15 @@ bool Tracker::update( const Mat& image, Rect2d& boundingBox ) return updateImpl( image, boundingBox ); } +AlgorithmInfo* Tracker::info() const{ + return 0; +} + Ptr Tracker::create( const String& trackerType ) { - - return Algorithm::create( "TRACKER." + trackerType ); + BOILERPLATE_CODE("MIL",TrackerMIL); + BOILERPLATE_CODE("BOOSTING",TrackerBoosting); + return Ptr(); } } /* namespace cv */ diff --git a/modules/tracking/src/trackerBoosting.cpp b/modules/tracking/src/trackerBoosting.cpp index 9b8bcc4ca..071bc297c 100644 --- a/modules/tracking/src/trackerBoosting.cpp +++ b/modules/tracking/src/trackerBoosting.cpp @@ -45,6 +45,21 @@ namespace cv { +class TrackerBoostingImpl : public TrackerBoosting +{ + public: + TrackerBoostingImpl( const TrackerBoosting::Params ¶meters = TrackerBoosting::Params() ); + void read( const FileNode& fn ); + void write( FileStorage& fs ) const; + + protected: + + bool initImpl( const Mat& image, const Rect2d& boundingBox ); + bool updateImpl( const Mat& image, Rect2d& boundingBox ); + + TrackerBoosting::Params params; +}; + /* * TrackerBoosting */ @@ -82,31 +97,26 @@ void TrackerBoosting::Params::write( cv::FileStorage& fs ) const /* * Constructor */ -TrackerBoosting::TrackerBoosting( const TrackerBoosting::Params ¶meters ) : +Ptr TrackerBoosting::createTracker(const TrackerBoosting::Params ¶meters){ + return Ptr(new TrackerBoostingImpl(parameters)); +} +TrackerBoostingImpl::TrackerBoostingImpl( const TrackerBoostingImpl::Params ¶meters ) : params( parameters ) { isInit = false; } -/* - * Destructor - */ -TrackerBoosting::~TrackerBoosting() -{ - -} - -void TrackerBoosting::read( const cv::FileNode& fn ) +void TrackerBoostingImpl::read( const cv::FileNode& fn ) { params.read( fn ); } -void TrackerBoosting::write( cv::FileStorage& fs ) const +void TrackerBoostingImpl::write( cv::FileStorage& fs ) const { params.write( fs ); } -bool TrackerBoosting::initImpl( const Mat& image, const Rect2d& boundingBox ) +bool TrackerBoostingImpl::initImpl( const Mat& image, const Rect2d& boundingBox ) { srand (1); //sampling @@ -190,7 +200,7 @@ bool TrackerBoosting::initImpl( const Mat& image, const Rect2d& boundingBox ) return true; } -bool TrackerBoosting::updateImpl( const Mat& image, Rect2d& boundingBox ) +bool TrackerBoostingImpl::updateImpl( const Mat& image, Rect2d& boundingBox ) { Mat_ intImage; Mat_ intSqImage; diff --git a/modules/tracking/src/trackerMIL.cpp b/modules/tracking/src/trackerMIL.cpp index 725b65c0d..a98c787de 100644 --- a/modules/tracking/src/trackerMIL.cpp +++ b/modules/tracking/src/trackerMIL.cpp @@ -45,6 +45,22 @@ namespace cv { +class TrackerMILImpl : public TrackerMIL +{ + public: + TrackerMILImpl( const TrackerMIL::Params ¶meters = TrackerMIL::Params() ); + void read( const FileNode& fn ); + void write( FileStorage& fs ) const; + + protected: + + bool initImpl( const Mat& image, const Rect2d& boundingBox ); + bool updateImpl( const Mat& image, Rect2d& boundingBox ); + void compute_integral( const Mat & img, Mat & ii_img ); + + TrackerMIL::Params params; +}; + /* * TrackerMIL */ @@ -89,31 +105,26 @@ void TrackerMIL::Params::write( cv::FileStorage& fs ) const /* * Constructor */ -TrackerMIL::TrackerMIL( const TrackerMIL::Params ¶meters ) : +Ptr TrackerMIL::createTracker(const TrackerMIL::Params ¶meters){ + return Ptr(new TrackerMILImpl(parameters)); +} +TrackerMILImpl::TrackerMILImpl( const TrackerMIL::Params ¶meters ) : params( parameters ) { isInit = false; } -/* - * Destructor - */ -TrackerMIL::~TrackerMIL() -{ - -} - -void TrackerMIL::read( const cv::FileNode& fn ) +void TrackerMILImpl::read( const cv::FileNode& fn ) { params.read( fn ); } -void TrackerMIL::write( cv::FileStorage& fs ) const +void TrackerMILImpl::write( cv::FileStorage& fs ) const { params.write( fs ); } -void TrackerMIL::compute_integral( const Mat & img, Mat & ii_img ) +void TrackerMILImpl::compute_integral( const Mat & img, Mat & ii_img ) { Mat ii; std::vector ii_imgs; @@ -122,7 +133,7 @@ void TrackerMIL::compute_integral( const Mat & img, Mat & ii_img ) ii_img = ii_imgs[0]; } -bool TrackerMIL::initImpl( const Mat& image, const Rect2d& boundingBox ) +bool TrackerMILImpl::initImpl( const Mat& image, const Rect2d& boundingBox ) { srand (1); Mat intImage; @@ -184,7 +195,7 @@ bool TrackerMIL::initImpl( const Mat& image, const Rect2d& boundingBox ) return true; } -bool TrackerMIL::updateImpl( const Mat& image, Rect2d& boundingBox ) +bool TrackerMILImpl::updateImpl( const Mat& image, Rect2d& boundingBox ) { Mat intImage; compute_integral( image, intImage ); diff --git a/modules/tracking/src/tracking_init.cpp b/modules/tracking/src/tracking_init.cpp index f203058f3..ffe31dfc4 100644 --- a/modules/tracking/src/tracking_init.cpp +++ b/modules/tracking/src/tracking_init.cpp @@ -45,17 +45,9 @@ namespace cv { -CV_INIT_ALGORITHM(TrackerMIL, "TRACKER.MIL",); - -CV_INIT_ALGORITHM(TrackerBoosting, "TRACKER.BOOSTING",); - bool initModule_tracking(void) { - bool all = true; - all &= !TrackerMIL_info_auto.name().empty(); - all &= !TrackerBoosting_info_auto.name().empty(); - - return all; + return true; } }