blob: b25b18ae6f23e83a166f0d0987ea5f22a31c01d0 [file] [log] [blame]
//-------------------------------------------------------------
// ____ _ _
// / ___|____ _ _ ____ ____| |__ | |
// | | / ___| | | | _ \/ ___| _ \| |
// | |___| | | |_| | | | | |___| | | ||_|
// \____|_| \_____|_| |_|\____|_| |_|(_) Media benchmarks
//
// 2006, Intel Corporation, licensed under Apache 2.0
//
// file : main.cpp
// author : Scott Ettinger - scott.m.ettinger@intel.com
// description : Top level body tracking code. Takes image
// inputs from disk and runs the tracking
// particle filter.
//
// Currently contains 3 versions :
// Single threaded, OpenMP, and Posix threads.
// They are kept separate for readability.
//
// Thread methods supported are selected by the
// #defines USE_OPENMP, USE_THREADS or USE_TBB.
//
// modified :
//--------------------------------------------------------------
#if defined(HAVE_CONFIG_H)
# include "config.h"
#endif
#include <vector>
#include <sstream>
#include <fstream>
#include <iomanip>
//Add defines USE_OPENMP, USE_THREADS or USE_TBB for threaded versions if not using config file (Windows).
//#define USE_OPENMP
//#define USE_THREADS
//#define USE_TBB
#if defined(USE_OPENMP)
#include <omp.h>
#include "ParticleFilterOMP.h"
#include "TrackingModelOMP.h"
#endif //USE_OPENMP
#if defined(USE_THREADS)
#include "threads/Thread.h"
#include "threads/WorkerGroup.h"
#include "ParticleFilterPthread.h"
#include "TrackingModelPthread.h"
#endif //USE_THREADS
#if defined(USE_TBB)
#include "tbb/task_scheduler_init.h"
#include "ParticleFilterTBB.h"
#include "TrackingModelTBB.h"
using namespace tbb;
#endif //USE_TBB
#if defined(ENABLE_PARSEC_HOOKS)
#include <hooks.h>
#endif //ENABLE_PARSEC_HOOKS
#include "ParticleFilter.h"
#include "TrackingModel.h"
#include "system.h"
using namespace std;
//templated conversion from string
template<class T>
bool num(const string s, T &n)
{ istringstream ss(s);
ss >> n;
return !ss.fail();
}
//write a given pose to a stream
inline void WritePose(ostream &f, vector<float> &pose)
{ for(int i = 0; i < (int)pose.size(); i++)
f << pose[i] << " ";
f << endl;
}
bool ProcessCmdLine(int argc, char **argv, string &path, int &cameras, int &frames, int &particles, int &layers, int &threads, int &threadModel, bool &OutputBMP)
{
string usage("Usage : Track (Dataset Path) (# of cameras) (# of frames to process)\n");
usage += string(" (# of particles) (# of annealing layers) \n");
usage += string(" [thread model] [# of threads] [write .bmp output (nonzero = yes)]\n\n");
usage += string(" Thread model : 0 = Auto-select from available models\n");
usage += string(" 1 = Intel TBB ");
#ifdef USE_TBB
usage += string("\n");
#else
usage += string("(unavailable)\n");
#endif
usage += string(" 2 = Posix / Windows threads ");
#ifdef USE_THREADS
usage += string("\n");
#else
usage += string("(unavailable)\n");
#endif
usage += string(" 3 = OpenMP ");
#ifdef USE_OPENMP
usage += string("\n");
#else
usage += string("(unavailable)\n");
#endif
usage += string(" 4 = Serial\n");
string errmsg("Error : invalid argument - ");
if(argc < 6 || argc > 9) //check for valid number of arguments
{ cout << "Error : Invalid number of arguments" << endl << usage << endl;
return false;
}
path = string(argv[1]); //get dataset path and add backslash if needed
if(path[path.size() - 1] != DIR_SEPARATOR[0])
path.push_back(DIR_SEPARATOR[0]);
if(!num(string(argv[2]), cameras)) //parse each argument
{ cout << errmsg << "number of cameras" << endl << usage << endl;
return false;
}
if(!num(string(argv[3]), frames))
{ cout << errmsg << "number of frames" << endl << usage << endl;
return false;
}
if(!num(string(argv[4]), particles))
{ cout << errmsg << "number of particles" << endl << usage << endl;
return false;
}
if(!num(string(argv[5]), layers))
{ cout << errmsg << "number of annealing layers" << endl << usage << endl;
return false;
}
threads = -1;
threadModel = 0;
if(argc < 7) //use default single thread mode if no threading arguments present
return true;
if(!num(string(argv[6]), threadModel))
{ cout << errmsg << "Thread Model" << endl << usage << endl;
return false;
}
if(argc > 7)
if(!num(string(argv[7]), threads))
{ cout << errmsg << "number of threads" << endl << usage << endl;
return false;
}
int n;
OutputBMP = true; //do not output bmp results by default
if(argc > 8)
{ if(!num(string(argv[8]), n))
{ cout << errmsg << "Output BMP flag" << endl << usage << endl;
return false;
}
OutputBMP = (n != 0);
}
return true;
}
//Body tracking threaded with OpenMP
#if defined(USE_OPENMP)
int mainOMP(string path, int cameras, int frames, int particles, int layers, int threads, bool OutputBMP)
{
cout << "Threading with OpenMP" << endl;
if(threads < 1) //Set number of threads used by OpenMP
omp_set_num_threads(omp_get_num_procs()); //use number of processors by default
else
omp_set_num_threads(threads);
cout << "Number of Threads : " << omp_get_max_threads() << endl;
TrackingModelOMP model;
if(!model.Initialize(path, cameras, layers)) //Initialize model parameters
{ cout << endl << "Error loading initialization data." << endl;
return 0;
}
model.SetNumThreads(threads);
model.GetObservation(0); //load data for first frame
ParticleFilterOMP<TrackingModel> pf; //particle filter (OMP threaded) instantiated with body tracking model type
pf.SetModel(model); //set the particle filter model
pf.InitializeParticles(particles); //generate initial set of particles and evaluate the log-likelihoods
cout << "Using dataset : " << path << endl;
cout << particles << " particles with " << layers << " annealing layers" << endl << endl;
ofstream outputFileAvg((path + "poses.txt").c_str());
vector<float> estimate; //expected pose from particle distribution
#if defined(ENABLE_PARSEC_HOOKS)
__parsec_roi_begin();
#endif
for(int i = 0; i < frames; i++) //process each set of frames
{ cout << "Processing frame " << i << endl;
if(!pf.Update((float)i)) //Run particle filter step
{ cout << "Error loading observation data" << endl;
return 0;
}
pf.Estimate(estimate); //get average pose of the particle distribution
WritePose(outputFileAvg, estimate);
if(OutputBMP)
pf.Model().OutputBMP(estimate, i); //save output bitmap file
}
#if defined(ENABLE_PARSEC_HOOKS)
__parsec_roi_end();
#endif
return 1;
}
#endif
#if defined(USE_THREADS)
//Body tracking threaded with explicit Posix threads
int mainPthreads(string path, int cameras, int frames, int particles, int layers, int threads, bool OutputBMP)
{
cout << "Threading with Posix Threads" << endl;
if(threads < 1) {
cout << "Warning: Illegal or unspecified number of threads, using 1 thread" << endl;
threads = 1;
}
cout << "Number of threads : " << threads << endl;
WorkPoolPthread workers(threads); //create thread work pool
TrackingModelPthread model(workers);
//register tracking model commands
workers.RegisterCmd(workers.THREADS_CMD_FILTERROW, model);
workers.RegisterCmd(workers.THREADS_CMD_FILTERCOLUMN, model);
workers.RegisterCmd(workers.THREADS_CMD_GRADIENT, model);
if(!model.Initialize(path, cameras, layers)) //Initialize model parameters
{ cout << endl << "Error loading initialization data." << endl;
return 0;
}
model.SetNumThreads(threads);
model.SetNumFrames(frames);
model.GetObservation(-1); //load data for first frame
ParticleFilterPthread<TrackingModel> pf(workers); //particle filter instantiated with body tracking model type
pf.SetModel(model); //set the particle filter model
workers.RegisterCmd(workers.THREADS_CMD_PARTICLEWEIGHTS, pf); //register particle filter commands
workers.RegisterCmd(workers.THREADS_CMD_NEWPARTICLES, pf); //register
pf.InitializeParticles(particles); //generate initial set of particles and evaluate the log-likelihoods
cout << "Using dataset : " << path << endl;
cout << particles << " particles with " << layers << " annealing layers" << endl << endl;
ofstream outputFileAvg((path + "poses.txt").c_str());
vector<float> estimate; //expected pose from particle distribution
#if defined(ENABLE_PARSEC_HOOKS)
__parsec_roi_begin();
#endif
for(int i = 0; i < frames; i++) //process each set of frames
{ cout << "Processing frame " << i << endl;
if(!pf.Update((float)i)) //Run particle filter step
{ cout << "Error loading observation data" << endl;
workers.JoinAll();
return 0;
}
pf.Estimate(estimate); //get average pose of the particle distribution
WritePose(outputFileAvg, estimate);
if(OutputBMP)
pf.Model().OutputBMP(estimate, i); //save output bitmap file
}
model.close();
workers.JoinAll();
#if defined(ENABLE_PARSEC_HOOKS)
__parsec_roi_end();
#endif
return 1;
}
#endif
#if defined(USE_TBB)
//Body tracking threaded with Intel TBB
int mainTBB(string path, int cameras, int frames, int particles, int layers, int threads, bool OutputBMP)
{
tbb::task_scheduler_init init(task_scheduler_init::deferred);
cout << "Threading with TBB" << endl;
if(threads < 1)
{ init.initialize(task_scheduler_init::automatic);
cout << "Number of Threads configured by task scheduler" << endl;
}
else
{ init.initialize(threads);
cout << "Number of Threads : " << threads << endl;
}
TrackingModelTBB model;
if(!model.Initialize(path, cameras, layers)) //Initialize model parameters
{ cout << endl << "Error loading initialization data." << endl;
return 0;
}
model.SetNumThreads(particles);
model.SetNumFrames(frames);
model.GetObservation(0); //load data for first frame
ParticleFilterTBB<TrackingModelTBB> pf; //particle filter (TBB threaded) instantiated with body tracking model type
pf.SetModel(model); //set the particle filter model
pf.InitializeParticles(particles); //generate initial set of particles and evaluate the log-likelihoods
pf.setOutputBMP(OutputBMP);
cout << "Using dataset : " << path << endl;
cout << particles << " particles with " << layers << " annealing layers" << endl << endl;
pf.setOutputFile((path + "poses.txt").c_str());
ofstream outputFileAvg((path + "poses.txt").c_str());
// Create the TBB pipeline - 1 stage for image processing, one for particle filter update
tbb::pipeline pipeline;
pipeline.add_filter(model);
pipeline.add_filter(pf);
pipeline.run(1);
pipeline.clear();
return 1;
}
#endif
//Body tracking Single Threaded
int mainSingleThread(string path, int cameras, int frames, int particles, int layers, bool OutputBMP)
{
cout << endl << "Running Single Threaded" << endl << endl;
TrackingModel model;
if(!model.Initialize(path, cameras, layers)) //Initialize model parameters
{ cout << endl << "Error loading initialization data." << endl;
return 0;
}
model.GetObservation(0); //load data for first frame
ParticleFilter<TrackingModel> pf; //particle filter instantiated with body tracking model type
pf.SetModel(model); //set the particle filter model
pf.InitializeParticles(particles); //generate initial set of particles and evaluate the log-likelihoods
cout << "Using dataset : " << path << endl;
cout << particles << " particles with " << layers << " annealing layers" << endl << endl;
ofstream outputFileAvg((path + "poses.txt").c_str());
vector<float> estimate; //expected pose from particle distribution
#if defined(ENABLE_PARSEC_HOOKS)
__parsec_roi_begin();
#endif
for(int i = 0; i < frames; i++) //process each set of frames
{ cout << "Processing frame " << i << endl;
if(!pf.Update((float)i)) //Run particle filter step
{ cout << "Error loading observation data" << endl;
return 0;
}
pf.Estimate(estimate); //get average pose of the particle distribution
WritePose(outputFileAvg, estimate);
if(OutputBMP)
pf.Model().OutputBMP(estimate, i); //save output bitmap file
}
#if defined(ENABLE_PARSEC_HOOKS)
__parsec_roi_end();
#endif
return 1;
}
int main(int argc, char **argv)
{
string path;
bool OutputBMP;
int cameras, frames, particles, layers, threads, threadModel; //process command line parameters to get path, cameras, and frames
#ifdef PARSEC_VERSION
#define __PARSEC_STRING(x) #x
#define __PARSEC_XSTRING(x) __PARSEC_STRING(x)
cout << "PARSEC Benchmark Suite Version "__PARSEC_XSTRING(PARSEC_VERSION) << endl << flush;
#else
cout << "PARSEC Benchmark Suite" << endl << flush;
#endif //PARSEC_VERSION
#if defined(ENABLE_PARSEC_HOOKS)
__parsec_bench_begin(__parsec_bodytrack);
#endif
if(!ProcessCmdLine(argc, argv, path, cameras, frames, particles, layers, threads, threadModel, OutputBMP))
return 0;
if(threadModel == 0) {
#if defined(USE_TBB)
threadModel = 1;
#elif defined(USE_THREADS)
threadModel = 2;
#elif defined(USE_OPENMP)
threadModel = 3;
#else
threadModel = 4;
#endif
}
switch(threadModel)
{
case 0 :
//This case should never happen, we auto-select the thread model before this switch
cout << "Internal error. Aborting." << endl;
exit(1);
break;
case 1 :
#if defined(USE_TBB)
mainTBB(path, cameras, frames, particles, layers, threads, OutputBMP); //Intel TBB threads tracking
break;
#else
cout << "Not compiled with Intel TBB support. " << endl;
cout << "If the environment supports it, rebuild with USE_TBB #defined." << endl;
break;
#endif
case 2 :
#if defined(USE_THREADS)
mainPthreads(path, cameras, frames, particles, layers, threads, OutputBMP); //Posix threads tracking
break;
#else
cout << "Not compiled with Posix threads support. " << endl;
cout << "If the environment supports it, rebuild with USE_THREADS #defined." << endl;
break;
#endif
case 3 :
#if defined(USE_OPENMP)
mainOMP(path, cameras, frames, particles, layers, threads, OutputBMP); //OpenMP threaded tracking
break;
#else
cout << "Not compiled with OpenMP support. " << endl;
cout << "If the environment supports OpenMP, rebuild with USE_OPENMP #defined." << endl;
break;
#endif
case 4 :
mainSingleThread(path, cameras, frames, particles, layers, OutputBMP); //single threaded tracking
break;
default :
cout << "Invalid thread model argument. " << endl;
cout << "Thread model : 0 = Auto-select thread model" << endl;
cout << " 1 = Intel TBB" << endl;
cout << " 2 = Posix / Windows Threads" << endl;
cout << " 3 = OpenMP" << endl;
cout << " 4 = Serial" << endl;
break;
}
#if defined(ENABLE_PARSEC_HOOKS)
__parsec_bench_end();
#endif
return 0;
}