Commit ffa6637b authored by Vadim Pisarevsky's avatar Vadim Pisarevsky

Merge pull request #300 from kurnianggoro:multitracker

parents 60f5e5ef a805f8ba
......@@ -223,3 +223,34 @@ TrackerSampler diagram
}
@enduml
MultiTracker diagram
======================
@startuml{tracking_uml_multiple.png}
package "MultiTracker"
package "Tracker"
MultiTracker -> Tracker: create
note top of Tracker: Several classes can be generated.
@enduml
@startuml{multi_tracker_uml.png}
class MultiTracker{
MultiTracker(const String& trackerType = "" );
~MultiTracker();
+bool add( const Mat& image, const Rect2d& boundingBox );
+bool add( const String& trackerType, const Mat& image, const Rect2d& boundingBox );
+bool add(const String& trackerType, const Mat& image, std::vector<Rect2d> boundingBox);
+bool add(const Mat& image, std::vector<Rect2d> boundingBox);
+bool update( const Mat& image, std::vector<Rect2d> & boundingBox );
+std::vector<Rect2d> objects;
---
#std::vector< Ptr<Tracker> > trackerList;
#String defaultAlgorithm;
}
@enduml
......@@ -1243,6 +1243,118 @@ class CV_EXPORTS_W TrackerKCF : public Tracker
BOILERPLATE_CODE("KCF",TrackerKCF);
};
/************************************ MultiTracker Class ************************************/
/** @brief This class is used to track multiple objects using the specified tracker algorithm.
* The MultiTracker is naive implementation of multiple object tracking.
* It process the tracked objects independently without any optimization accross the tracked objects.
*/
class CV_EXPORTS_W MultiTracker
{
public:
/**
* \brief Constructor.
* In the case of trackerType is given, it will be set as the default algorithm for all trackers.
* @param trackerType the name of the tracker algorithm to be used
*/
MultiTracker(const String& trackerType = "" );
/**
* \brief Destructor
*/
~MultiTracker();
/**
* \brief Add a new object to be tracked.
* The defaultAlgorithm will be used the newly added tracker.
* @param image input image
* @param boundingBox a rectangle represents ROI of the tracked object
*/
bool add( const Mat& image, const Rect2d& boundingBox );
/**
* \brief Add a new object to be tracked.
* @param trackerType the name of the tracker algorithm to be used
* @param image input image
* @param boundingBox a rectangle represents ROI of the tracked object
*/
bool add( const String& trackerType, const Mat& image, const Rect2d& boundingBox );
/**
* \brief Add a set of objects to be tracked.
* @param trackerType the name of the tracker algorithm to be used
* @param image input image
* @param boundingBox list of the tracked objects
*/
bool add(const String& trackerType, const Mat& image, std::vector<Rect2d> boundingBox);
/**
* \brief Add a set of objects to be tracked using the defaultAlgorithm tracker.
* @param image input image
* @param boundingBox list of the tracked objects
*/
bool add(const Mat& image, std::vector<Rect2d> boundingBox);
/**
* \brief Update the current tracking status.
* The result will be saved in the internal storage.
* @param image input image
*/
bool update( const Mat& image);
//!< storage for the tracked objects, each object corresponds to one tracker algorithm.
std::vector<Rect2d> objects;
/**
* \brief Update the current tracking status.
* @param image input image
* @param boundingBox the tracking result, represent a list of ROIs of the tracked objects.
*/
bool update( const Mat& image, std::vector<Rect2d> & boundingBox );
protected:
//!< storage for the tracker algorithms.
std::vector< Ptr<Tracker> > trackerList;
//!< default algorithm for the tracking method.
String defaultAlgorithm;
};
class ROISelector {
public:
Rect2d select(Mat img, bool fromCenter = true);
Rect2d select(const std::string& windowName, Mat img, bool showCrossair = true, bool fromCenter = true);
void select(const std::string& windowName, Mat img, std::vector<Rect2d> & boundingBox, bool fromCenter = true);
struct handlerT{
// basic parameters
bool isDrawing;
Rect2d box;
Mat image;
// parameters for drawing from the center
bool drawFromCenter;
Point2f center;
// initializer list
handlerT(): isDrawing(false), drawFromCenter(true) {};
}selectorParams;
// to store the tracked objects
std::vector<handlerT> objects;
private:
static void mouseHandler(int event, int x, int y, int flags, void *param);
void opencv_mouse_callback( int event, int x, int y, int , void *param );
// save the keypressed characted
int key;
};
Rect2d CV_EXPORTS_W selectROI(Mat img, bool fromCenter = true);
Rect2d CV_EXPORTS_W selectROI(const std::string& windowName, Mat img, bool showCrossair = true, bool fromCenter = true);
void CV_EXPORTS_W selectROI(const std::string& windowName, Mat img, std::vector<Rect2d> & boundingBox, bool fromCenter = true);
//! @}
} /* namespace cv */
......
/*----------------------------------------------
* Usage:
* example_tracking_multitracker <video_name> [algorithm]
*
* example:
* example_tracking_multitracker Bolt/img/%04d.jpg
* example_tracking_multitracker faceocc2.webm KCF
*
* Note: after the OpenCV libary is installed,
* please re-compile this code with "HAVE_OPENCV" parameter activated
* to enable the high precission of fps computation
*--------------------------------------------------*/
/* after the OpenCV libary is installed
* please uncomment the the line below and re-compile this code
* to enable high precission of fps computation
*/
//#define HAVE_OPENCV
#include <opencv2/core/utility.hpp>
#include <opencv2/tracking.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
#include <cstring>
#include <ctime>
#ifdef HAVE_OPENCV
#include <opencv2/flann.hpp>
#endif
#define RESET "\033[0m"
#define RED "\033[31m" /* Red */
#define GREEN "\033[32m" /* Green */
using namespace std;
using namespace cv;
int main( int argc, char** argv ){
// show help
if(argc<2){
cout<<
" Usage: example_tracking_multitracker <video_name> [algorithm]\n"
" examples:\n"
" example_tracking_multitracker Bolt/img/%04d.jpg\n"
" example_tracking_multitracker faceocc2.webm MEDIANFLOW\n"
" \n"
" Note: after the OpenCV libary is installed,\n"
" please re-compile with the HAVE_OPENCV parameter activated\n"
" to enable the high precission of fps computation.\n"
<< endl;
return 0;
}
// timer
#ifdef HAVE_OPENCV
cvflann::StartStopTimer timer;
#else
clock_t timer;
#endif
// for showing the speed
double fps;
std::string text;
char buffer [50];
// set the default tracking algorithm
std::string trackingAlg = "KCF";
// set the tracking algorithm from parameter
if(argc>2)
trackingAlg = argv[2];
// create the tracker
MultiTracker trackers(trackingAlg);
// container of the tracked objects
vector<Rect2d> objects;
// set input video
std::string video = argv[1];
VideoCapture cap(video);
Mat frame;
// get bounding box
cap >> frame;
selectROI("tracker",frame,objects);
//quit when the tracked object(s) is not provided
if(objects.size()<1)
return 0;
// initialize the tracker
trackers.add(frame,objects);
// do the tracking
printf(GREEN "Start the tracking process, press ESC to quit.\n" RESET);
for ( ;; ){
// get frame from the video
cap >> frame;
// stop the program if no more images
if(frame.rows==0 || frame.cols==0)
break;
// start the timer
#ifdef HAVE_OPENCV
timer.start();
#else
timer=clock();
#endif
//update the tracking result
trackers.update(frame);
// calculate the processing speed
#ifdef HAVE_OPENCV
timer.stop();
fps=1.0/timer.value;
timer.reset();
#else
timer=clock();
trackers.update(frame);
timer=clock()-timer;
fps=(double)CLOCKS_PER_SEC/(double)timer;
#endif
// draw the tracked object
for(unsigned i=0;i<trackers.objects.size();i++)
rectangle( frame, trackers.objects[i], Scalar( 255, 0, 0 ), 2, 1 );
// draw the processing speed
sprintf (buffer, "speed: %.0f fps", fps);
text = buffer;
putText(frame, text, Point(20,20), FONT_HERSHEY_PLAIN, 1, Scalar(255,255,255));
// show image with the tracked object
imshow("tracker",frame);
//quit on ESC button
if(waitKey(1)==27)break;
}
}
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "precomp.hpp"
namespace cv {
// constructor
MultiTracker::MultiTracker(const String& trackerType):defaultAlgorithm(trackerType){};
// destructor
MultiTracker::~MultiTracker(){};
// add an object to be tracked, defaultAlgorithm is used
bool MultiTracker::add(const Mat& image, const Rect2d& boundingBox){
// quit if defaultAlgorithm has not been configured
if(defaultAlgorithm==""){
printf("Default algorithm was not defined!\n");
return false;
}
// add a new tracked object
return add(defaultAlgorithm.c_str(), image, boundingBox);
};
// add a new tracked object
bool MultiTracker::add( const String& trackerType, const Mat& image, const Rect2d& boundingBox ){
// declare a new tracker
Ptr<Tracker> newTracker = Tracker::create( trackerType );
// add the created tracker algorithm to the trackers list
trackerList.push_back(newTracker);
// add the ROI to the bounding box list
objects.push_back(boundingBox);
// initialize the created tracker
return trackerList.back()->init(image, boundingBox);
};
// add a set of objects to be tracked
bool MultiTracker::add(const String& trackerType, const Mat& image, std::vector<Rect2d> boundingBox){
// status of the tracker addition
bool stat=false;
// add tracker for all input objects
for(unsigned i =0;i<boundingBox.size();i++){
stat=add(trackerType,image,boundingBox[i]);
if(!stat)break;
}
// return the status
return stat;
};
// add a set of object to be tracked, defaultAlgorithm is used.
bool MultiTracker::add(const Mat& image, std::vector<Rect2d> boundingBox){
// quit if defaultAlgorithm has not been configured
if(defaultAlgorithm==""){
printf("Default algorithm was not defined!\n");
return false;
}
return add(defaultAlgorithm.c_str(), image, boundingBox);
};
// update position of the tracked objects, the result is stored in internal storage
bool MultiTracker::update( const Mat& image){
for(unsigned i=0;i< trackerList.size(); i++){
trackerList[i]->update(image, objects[i]);
}
return true;
};
// update position of the tracked objects, the result is copied to external variable
bool MultiTracker::update( const Mat& image, std::vector<Rect2d> & boundingBox ){
update(image);
boundingBox=objects;
return true;
};
} /* namespace cv */
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "precomp.hpp"
namespace cv {
void ROISelector::mouseHandler(int event, int x, int y, int flags, void *param){
ROISelector *self =static_cast<ROISelector*>(param);
self->opencv_mouse_callback(event,x,y,flags,param);
}
void ROISelector::opencv_mouse_callback( int event, int x, int y, int , void *param ){
handlerT * data = (handlerT*)param;
switch( event ){
// update the selected bounding box
case EVENT_MOUSEMOVE:
if( data->isDrawing ){
if(data->drawFromCenter){
data->box.width = 2*(x-data->center.x)/*data->box.x*/;
data->box.height = 2*(y-data->center.y)/*data->box.y*/;
data->box.x = data->center.x-data->box.width/2.0;
data->box.y = data->center.y-data->box.height/2.0;
}else{
data->box.width = x-data->box.x;
data->box.height = y-data->box.y;
}
}
break;
// start to select the bounding box
case EVENT_LBUTTONDOWN:
data->isDrawing = true;
data->box = cvRect( x, y, 0, 0 );
data->center = Point2f((float)x,(float)y);
break;
// cleaning up the selected bounding box
case EVENT_LBUTTONUP:
data->isDrawing = false;
if( data->box.width < 0 ){
data->box.x += data->box.width;
data->box.width *= -1;
}
if( data->box.height < 0 ){
data->box.y += data->box.height;
data->box.height *= -1;
}
break;
}
}
Rect2d ROISelector::select(Mat img, bool fromCenter){
return select("ROI selector", img, fromCenter);
}
Rect2d ROISelector::select(const std::string& windowName, Mat img, bool showCrossair, bool fromCenter){
key=0;
// set the drawing mode
selectorParams.drawFromCenter = fromCenter;
// show the image and give feedback to user
imshow(windowName,img);
// copy the data, rectangle should be drawn in the fresh image
selectorParams.image=img.clone();
// select the object
setMouseCallback( windowName, mouseHandler, (void *)&selectorParams );
// end selection process on SPACE (32) BACKSPACE (27) or ENTER (13)
while(!(key==32 || key==27 || key==13)){
// draw the selected object
rectangle(
selectorParams.image,
selectorParams.box,
Scalar(255,0,0),2,1
);
// draw cross air in the middle of bounding box
if(showCrossair){
// horizontal line
line(
selectorParams.image,
Point((int)selectorParams.box.x,(int)(selectorParams.box.y+selectorParams.box.height/2)),
Point((int)(selectorParams.box.x+selectorParams.box.width),(int)(selectorParams.box.y+selectorParams.box.height/2)),
Scalar(255,0,0),2,1
);
// vertical line
line(
selectorParams.image,
Point((int)(selectorParams.box.x+selectorParams.box.width/2),(int)selectorParams.box.y),
Point((int)(selectorParams.box.x+selectorParams.box.width/2),(int)(selectorParams.box.y+selectorParams.box.height)),
Scalar(255,0,0),2,1
);
}
// show the image bouding box
imshow(windowName,selectorParams.image);
// reset the image
selectorParams.image=img.clone();
//get keyboard event
key=waitKey(1);
}
return selectorParams.box;
}
void ROISelector::select(const std::string& windowName, Mat img, std::vector<Rect2d> & boundingBox, bool fromCenter){
std::vector<Rect2d> box;
Rect2d temp;
key=0;
// show notice to user
printf("Select an object to track and then press SPACE or ENTER button!\n" );
printf("Finish the selection process by pressing BACKSPACE button!\n" );
// while key is not Backspace
while(key!=27){
temp=select(windowName, img, true, fromCenter);
if(temp.width>0 && temp.height>0)
box.push_back(temp);
}
boundingBox=box;
}
ROISelector _selector;
Rect2d selectROI(Mat img, bool fromCenter){
return _selector.select("ROI selector", img, true, fromCenter);
};
Rect2d selectROI(const std::string& windowName, Mat img, bool showCrossair, bool fromCenter){
printf("Select an object to track and then press SPACE or ENTER button!\n" );
return _selector.select(windowName,img, showCrossair, fromCenter);
};
void selectROI(const std::string& windowName, Mat img, std::vector<Rect2d> & boundingBox, bool fromCenter){
return _selector.select(windowName, img, boundingBox, fromCenter);
}
} /* 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