1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-31 08:13:04 +04:00

Merge pull request #18838 from alalek:video_tracking_api

Tracking API: move to video/tracking.hpp

* video(tracking): moved code from opencv_contrib/tracking module

- Tracker API
- MIL, GOTURN trackers
- applied clang-format

* video(tracking): cleanup unused code

* samples: add tracker.py sample

* video(tracking): avoid div by zero

* static analyzer
This commit is contained in:
Alexander Alekhin
2020-11-18 14:04:15 +03:00
committed by GitHub
parent 94e8a08d1d
commit aab6362705
31 changed files with 3843 additions and 4 deletions
@@ -0,0 +1,25 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "../../precomp.hpp"
#include "opencv2/video/detail/tracking.private.hpp"
namespace cv {
namespace detail {
inline namespace tracking {
TrackerFeature::~TrackerFeature()
{
// nothing
}
void TrackerFeature::compute(const std::vector<Mat>& images, Mat& response)
{
if (images.empty())
return;
computeImpl(images, response);
}
}}} // namespace cv::detail::tracking
@@ -0,0 +1,121 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "../../precomp.hpp"
#include "opencv2/video/detail/tracking.private.hpp"
#include "opencv2/video/detail/tracking_feature.private.hpp"
namespace cv {
namespace detail {
inline namespace tracking {
inline namespace internal {
class TrackerFeatureHAAR : public TrackerFeature
{
public:
struct Params
{
Params();
int numFeatures; //!< # of rects
Size rectSize; //!< rect size
bool isIntegral; //!< true if input images are integral, false otherwise
};
TrackerFeatureHAAR(const TrackerFeatureHAAR::Params& parameters = TrackerFeatureHAAR::Params());
virtual ~TrackerFeatureHAAR() CV_OVERRIDE {}
protected:
bool computeImpl(const std::vector<Mat>& images, Mat& response) CV_OVERRIDE;
private:
Params params;
Ptr<CvHaarEvaluator> featureEvaluator;
};
/**
* Parameters
*/
TrackerFeatureHAAR::Params::Params()
{
numFeatures = 250;
rectSize = Size(100, 100);
isIntegral = false;
}
TrackerFeatureHAAR::TrackerFeatureHAAR(const TrackerFeatureHAAR::Params& parameters)
: params(parameters)
{
CvHaarFeatureParams haarParams;
haarParams.numFeatures = params.numFeatures;
haarParams.isIntegral = params.isIntegral;
featureEvaluator = makePtr<CvHaarEvaluator>();
featureEvaluator->init(&haarParams, 1, params.rectSize);
}
class Parallel_compute : public cv::ParallelLoopBody
{
private:
Ptr<CvHaarEvaluator> featureEvaluator;
std::vector<Mat> images;
Mat response;
//std::vector<CvHaarEvaluator::FeatureHaar> features;
public:
Parallel_compute(Ptr<CvHaarEvaluator>& fe, const std::vector<Mat>& img, Mat& resp)
: featureEvaluator(fe)
, images(img)
, response(resp)
{
//features = featureEvaluator->getFeatures();
}
virtual void operator()(const cv::Range& r) const CV_OVERRIDE
{
for (int jf = r.start; jf != r.end; ++jf)
{
int cols = images[jf].cols;
int rows = images[jf].rows;
for (int j = 0; j < featureEvaluator->getNumFeatures(); j++)
{
float res = 0;
featureEvaluator->getFeatures()[j].eval(images[jf], Rect(0, 0, cols, rows), &res);
(Mat_<float>(response))(j, jf) = res;
}
}
}
};
bool TrackerFeatureHAAR::computeImpl(const std::vector<Mat>& images, Mat& response)
{
if (images.empty())
{
return false;
}
int numFeatures = featureEvaluator->getNumFeatures();
response = Mat_<float>(Size((int)images.size(), numFeatures));
std::vector<CvHaarEvaluator::FeatureHaar> f = featureEvaluator->getFeatures();
//for each sample compute #n_feature -> put each feature (n Rect) in response
parallel_for_(Range(0, (int)images.size()), Parallel_compute(featureEvaluator, images, response));
/*for ( size_t i = 0; i < images.size(); i++ )
{
int c = images[i].cols;
int r = images[i].rows;
for ( int j = 0; j < numFeatures; j++ )
{
float res = 0;
featureEvaluator->getFeatures( j ).eval( images[i], Rect( 0, 0, c, r ), &res );
( Mat_<float>( response ) )( j, i ) = res;
}
}*/
return true;
}
}}}} // namespace cv::detail::tracking::internal
@@ -0,0 +1,60 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "../../precomp.hpp"
#include "opencv2/video/detail/tracking.private.hpp"
namespace cv {
namespace detail {
inline namespace tracking {
TrackerFeatureSet::TrackerFeatureSet()
{
blockAddTrackerFeature = false;
}
TrackerFeatureSet::~TrackerFeatureSet()
{
// nothing
}
void TrackerFeatureSet::extraction(const std::vector<Mat>& images)
{
blockAddTrackerFeature = true;
clearResponses();
responses.resize(features.size());
for (size_t i = 0; i < features.size(); i++)
{
CV_DbgAssert(features[i]);
features[i]->compute(images, responses[i]);
}
}
bool TrackerFeatureSet::addTrackerFeature(const Ptr<TrackerFeature>& feature)
{
CV_Assert(!blockAddTrackerFeature);
CV_Assert(feature);
features.push_back(feature);
return true;
}
const std::vector<Ptr<TrackerFeature>>& TrackerFeatureSet::getTrackerFeatures() const
{
return features;
}
const std::vector<Mat>& TrackerFeatureSet::getResponses() const
{
return responses;
}
void TrackerFeatureSet::clearResponses()
{
responses.clear();
}
}}} // namespace cv::detail::tracking
@@ -0,0 +1,85 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "../../precomp.hpp"
#include "tracker_mil_model.hpp"
/**
* TrackerMILModel
*/
namespace cv {
inline namespace tracking {
namespace impl {
TrackerMILModel::TrackerMILModel(const Rect& boundingBox)
{
currentSample.clear();
mode = MODE_POSITIVE;
width = boundingBox.width;
height = boundingBox.height;
Ptr<TrackerStateEstimatorMILBoosting::TrackerMILTargetState> initState = Ptr<TrackerStateEstimatorMILBoosting::TrackerMILTargetState>(
new TrackerStateEstimatorMILBoosting::TrackerMILTargetState(Point2f((float)boundingBox.x, (float)boundingBox.y), boundingBox.width, boundingBox.height,
true, Mat()));
trajectory.push_back(initState);
}
void TrackerMILModel::responseToConfidenceMap(const std::vector<Mat>& responses, ConfidenceMap& confidenceMap)
{
if (currentSample.empty())
{
CV_Error(-1, "The samples in Model estimation are empty");
}
for (size_t i = 0; i < responses.size(); i++)
{
//for each column (one sample) there are #num_feature
//get informations from currentSample
for (int j = 0; j < responses.at(i).cols; j++)
{
Size currentSize;
Point currentOfs;
currentSample.at(j).locateROI(currentSize, currentOfs);
bool foreground = false;
if (mode == MODE_POSITIVE || mode == MODE_ESTIMATON)
{
foreground = true;
}
else if (mode == MODE_NEGATIVE)
{
foreground = false;
}
//get the column of the HAAR responses
Mat singleResponse = responses.at(i).col(j);
//create the state
Ptr<TrackerStateEstimatorMILBoosting::TrackerMILTargetState> currentState = Ptr<TrackerStateEstimatorMILBoosting::TrackerMILTargetState>(
new TrackerStateEstimatorMILBoosting::TrackerMILTargetState(currentOfs, width, height, foreground, singleResponse));
confidenceMap.push_back(std::make_pair(currentState, 0.0f));
}
}
}
void TrackerMILModel::modelEstimationImpl(const std::vector<Mat>& responses)
{
responseToConfidenceMap(responses, currentConfidenceMap);
}
void TrackerMILModel::modelUpdateImpl()
{
}
void TrackerMILModel::setMode(int trainingMode, const std::vector<Mat>& samples)
{
currentSample.clear();
currentSample = samples;
mode = trainingMode;
}
}}} // namespace cv::tracking::impl
@@ -0,0 +1,67 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef __OPENCV_TRACKER_MIL_MODEL_HPP__
#define __OPENCV_TRACKER_MIL_MODEL_HPP__
#include "opencv2/video/detail/tracking.private.hpp"
#include "tracker_mil_state.hpp"
namespace cv {
inline namespace tracking {
namespace impl {
using namespace cv::detail::tracking;
/**
* \brief Implementation of TrackerModel for MIL algorithm
*/
class TrackerMILModel : public detail::TrackerModel
{
public:
enum
{
MODE_POSITIVE = 1, // mode for positive features
MODE_NEGATIVE = 2, // mode for negative features
MODE_ESTIMATON = 3 // mode for estimation step
};
/**
* \brief Constructor
* \param boundingBox The first boundingBox
*/
TrackerMILModel(const Rect& boundingBox);
/**
* \brief Destructor
*/
~TrackerMILModel() {};
/**
* \brief Set the mode
*/
void setMode(int trainingMode, const std::vector<Mat>& samples);
/**
* \brief Create the ConfidenceMap from a list of responses
* \param responses The list of the responses
* \param confidenceMap The output
*/
void responseToConfidenceMap(const std::vector<Mat>& responses, ConfidenceMap& confidenceMap);
protected:
void modelEstimationImpl(const std::vector<Mat>& responses) CV_OVERRIDE;
void modelUpdateImpl() CV_OVERRIDE;
private:
int mode;
std::vector<Mat> currentSample;
int width; //initial width of the boundingBox
int height; //initial height of the boundingBox
};
}}} // namespace cv::tracking::impl
#endif
@@ -0,0 +1,159 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "../../precomp.hpp"
#include "opencv2/video/detail/tracking.private.hpp"
#include "tracker_mil_state.hpp"
namespace cv {
namespace detail {
inline namespace tracking {
/**
* TrackerStateEstimatorMILBoosting::TrackerMILTargetState
*/
TrackerStateEstimatorMILBoosting::TrackerMILTargetState::TrackerMILTargetState(const Point2f& position, int width, int height, bool foreground,
const Mat& features)
{
setTargetPosition(position);
setTargetWidth(width);
setTargetHeight(height);
setTargetFg(foreground);
setFeatures(features);
}
void TrackerStateEstimatorMILBoosting::TrackerMILTargetState::setTargetFg(bool foreground)
{
isTarget = foreground;
}
void TrackerStateEstimatorMILBoosting::TrackerMILTargetState::setFeatures(const Mat& features)
{
targetFeatures = features;
}
bool TrackerStateEstimatorMILBoosting::TrackerMILTargetState::isTargetFg() const
{
return isTarget;
}
Mat TrackerStateEstimatorMILBoosting::TrackerMILTargetState::getFeatures() const
{
return targetFeatures;
}
TrackerStateEstimatorMILBoosting::TrackerStateEstimatorMILBoosting(int nFeatures)
{
className = "BOOSTING";
trained = false;
numFeatures = nFeatures;
}
TrackerStateEstimatorMILBoosting::~TrackerStateEstimatorMILBoosting()
{
}
void TrackerStateEstimatorMILBoosting::setCurrentConfidenceMap(ConfidenceMap& confidenceMap)
{
currentConfidenceMap.clear();
currentConfidenceMap = confidenceMap;
}
uint TrackerStateEstimatorMILBoosting::max_idx(const std::vector<float>& v)
{
const float* findPtr = &(*std::max_element(v.begin(), v.end()));
const float* beginPtr = &(*v.begin());
return (uint)(findPtr - beginPtr);
}
Ptr<TrackerTargetState> TrackerStateEstimatorMILBoosting::estimateImpl(const std::vector<ConfidenceMap>& /*confidenceMaps*/)
{
//run ClfMilBoost classify in order to compute next location
if (currentConfidenceMap.empty())
return Ptr<TrackerTargetState>();
Mat positiveStates;
Mat negativeStates;
prepareData(currentConfidenceMap, positiveStates, negativeStates);
std::vector<float> prob = boostMILModel.classify(positiveStates);
int bestind = max_idx(prob);
//float resp = prob[bestind];
return currentConfidenceMap.at(bestind).first;
}
void TrackerStateEstimatorMILBoosting::prepareData(const ConfidenceMap& confidenceMap, Mat& positive, Mat& negative)
{
int posCounter = 0;
int negCounter = 0;
for (size_t i = 0; i < confidenceMap.size(); i++)
{
Ptr<TrackerMILTargetState> currentTargetState = confidenceMap.at(i).first.staticCast<TrackerMILTargetState>();
CV_DbgAssert(currentTargetState);
if (currentTargetState->isTargetFg())
posCounter++;
else
negCounter++;
}
positive.create(posCounter, numFeatures, CV_32FC1);
negative.create(negCounter, numFeatures, CV_32FC1);
//TODO change with mat fast access
//initialize trainData (positive and negative)
int pc = 0;
int nc = 0;
for (size_t i = 0; i < confidenceMap.size(); i++)
{
Ptr<TrackerMILTargetState> currentTargetState = confidenceMap.at(i).first.staticCast<TrackerMILTargetState>();
Mat stateFeatures = currentTargetState->getFeatures();
if (currentTargetState->isTargetFg())
{
for (int j = 0; j < stateFeatures.rows; j++)
{
//fill the positive trainData with the value of the feature j for sample i
positive.at<float>(pc, j) = stateFeatures.at<float>(j, 0);
}
pc++;
}
else
{
for (int j = 0; j < stateFeatures.rows; j++)
{
//fill the negative trainData with the value of the feature j for sample i
negative.at<float>(nc, j) = stateFeatures.at<float>(j, 0);
}
nc++;
}
}
}
void TrackerStateEstimatorMILBoosting::updateImpl(std::vector<ConfidenceMap>& confidenceMaps)
{
if (!trained)
{
//this is the first time that the classifier is built
//init MIL
boostMILModel.init();
trained = true;
}
ConfidenceMap lastConfidenceMap = confidenceMaps.back();
Mat positiveStates;
Mat negativeStates;
prepareData(lastConfidenceMap, positiveStates, negativeStates);
//update MIL
boostMILModel.update(positiveStates, negativeStates);
}
}}} // namespace cv::detail::tracking
@@ -0,0 +1,87 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef OPENCV_VIDEO_DETAIL_TRACKING_MIL_STATE_HPP
#define OPENCV_VIDEO_DETAIL_TRACKING_MIL_STATE_HPP
#include "opencv2/video/detail/tracking.private.hpp"
#include "tracking_online_mil.hpp"
namespace cv {
namespace detail {
inline namespace tracking {
/** @brief TrackerStateEstimator based on Boosting
*/
class CV_EXPORTS TrackerStateEstimatorMILBoosting : public TrackerStateEstimator
{
public:
/**
* Implementation of the target state for TrackerStateEstimatorMILBoosting
*/
class TrackerMILTargetState : public TrackerTargetState
{
public:
/**
* \brief Constructor
* \param position Top left corner of the bounding box
* \param width Width of the bounding box
* \param height Height of the bounding box
* \param foreground label for target or background
* \param features features extracted
*/
TrackerMILTargetState(const Point2f& position, int width, int height, bool foreground, const Mat& features);
~TrackerMILTargetState() {};
/** @brief Set label: true for target foreground, false for background
@param foreground Label for background/foreground
*/
void setTargetFg(bool foreground);
/** @brief Set the features extracted from TrackerFeatureSet
@param features The features extracted
*/
void setFeatures(const Mat& features);
/** @brief Get the label. Return true for target foreground, false for background
*/
bool isTargetFg() const;
/** @brief Get the features extracted
*/
Mat getFeatures() const;
private:
bool isTarget;
Mat targetFeatures;
};
/** @brief Constructor
@param nFeatures Number of features for each sample
*/
TrackerStateEstimatorMILBoosting(int nFeatures = 250);
~TrackerStateEstimatorMILBoosting();
/** @brief Set the current confidenceMap
@param confidenceMap The current :cConfidenceMap
*/
void setCurrentConfidenceMap(ConfidenceMap& confidenceMap);
protected:
Ptr<TrackerTargetState> estimateImpl(const std::vector<ConfidenceMap>& confidenceMaps) CV_OVERRIDE;
void updateImpl(std::vector<ConfidenceMap>& confidenceMaps) CV_OVERRIDE;
private:
uint max_idx(const std::vector<float>& v);
void prepareData(const ConfidenceMap& confidenceMap, Mat& positive, Mat& negative);
ClfMilBoost boostMILModel;
bool trained;
int numFeatures;
ConfidenceMap currentConfidenceMap;
};
}}} // namespace cv::detail::tracking
#endif
@@ -0,0 +1,132 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "../../precomp.hpp"
#include "opencv2/video/detail/tracking.private.hpp"
namespace cv {
namespace detail {
inline namespace tracking {
TrackerModel::TrackerModel()
{
stateEstimator = Ptr<TrackerStateEstimator>();
maxCMLength = 10;
}
TrackerModel::~TrackerModel()
{
// nothing
}
bool TrackerModel::setTrackerStateEstimator(Ptr<TrackerStateEstimator> trackerStateEstimator)
{
if (stateEstimator.get())
{
return false;
}
stateEstimator = trackerStateEstimator;
return true;
}
Ptr<TrackerStateEstimator> TrackerModel::getTrackerStateEstimator() const
{
return stateEstimator;
}
void TrackerModel::modelEstimation(const std::vector<Mat>& responses)
{
modelEstimationImpl(responses);
}
void TrackerModel::clearCurrentConfidenceMap()
{
currentConfidenceMap.clear();
}
void TrackerModel::modelUpdate()
{
modelUpdateImpl();
if (maxCMLength != -1 && (int)confidenceMaps.size() >= maxCMLength - 1)
{
int l = maxCMLength / 2;
confidenceMaps.erase(confidenceMaps.begin(), confidenceMaps.begin() + l);
}
if (maxCMLength != -1 && (int)trajectory.size() >= maxCMLength - 1)
{
int l = maxCMLength / 2;
trajectory.erase(trajectory.begin(), trajectory.begin() + l);
}
confidenceMaps.push_back(currentConfidenceMap);
stateEstimator->update(confidenceMaps);
clearCurrentConfidenceMap();
}
bool TrackerModel::runStateEstimator()
{
if (!stateEstimator)
{
CV_Error(-1, "Tracker state estimator is not setted");
}
Ptr<TrackerTargetState> targetState = stateEstimator->estimate(confidenceMaps);
if (!targetState)
return false;
setLastTargetState(targetState);
return true;
}
void TrackerModel::setLastTargetState(const Ptr<TrackerTargetState>& lastTargetState)
{
trajectory.push_back(lastTargetState);
}
Ptr<TrackerTargetState> TrackerModel::getLastTargetState() const
{
return trajectory.back();
}
const std::vector<ConfidenceMap>& TrackerModel::getConfidenceMaps() const
{
return confidenceMaps;
}
const ConfidenceMap& TrackerModel::getLastConfidenceMap() const
{
return confidenceMaps.back();
}
Point2f TrackerTargetState::getTargetPosition() const
{
return targetPosition;
}
void TrackerTargetState::setTargetPosition(const Point2f& position)
{
targetPosition = position;
}
int TrackerTargetState::getTargetWidth() const
{
return targetWidth;
}
void TrackerTargetState::setTargetWidth(int width)
{
targetWidth = width;
}
int TrackerTargetState::getTargetHeight() const
{
return targetHeight;
}
void TrackerTargetState::setTargetHeight(int height)
{
targetHeight = height;
}
}}} // namespace cv::detail::tracking
@@ -0,0 +1,68 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "../../precomp.hpp"
#include "opencv2/video/detail/tracking.private.hpp"
namespace cv {
namespace detail {
inline namespace tracking {
TrackerSampler::TrackerSampler()
{
blockAddTrackerSampler = false;
}
TrackerSampler::~TrackerSampler()
{
// nothing
}
void TrackerSampler::sampling(const Mat& image, Rect boundingBox)
{
clearSamples();
for (size_t i = 0; i < samplers.size(); i++)
{
CV_DbgAssert(samplers[i]);
std::vector<Mat> current_samples;
samplers[i]->sampling(image, boundingBox, current_samples);
//push in samples all current_samples
for (size_t j = 0; j < current_samples.size(); j++)
{
std::vector<Mat>::iterator it = samples.end();
samples.insert(it, current_samples.at(j));
}
}
blockAddTrackerSampler = true;
}
bool TrackerSampler::addTrackerSamplerAlgorithm(const Ptr<TrackerSamplerAlgorithm>& sampler)
{
CV_Assert(!blockAddTrackerSampler);
CV_Assert(sampler);
samplers.push_back(sampler);
return true;
}
const std::vector<Ptr<TrackerSamplerAlgorithm>>& TrackerSampler::getSamplers() const
{
return samplers;
}
const std::vector<Mat>& TrackerSampler::getSamples() const
{
return samples;
}
void TrackerSampler::clearSamples()
{
samples.clear();
}
}}} // namespace cv::detail::tracking
@@ -0,0 +1,124 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "../../precomp.hpp"
#include "opencv2/video/detail/tracking.private.hpp"
namespace cv {
namespace detail {
inline namespace tracking {
TrackerSamplerAlgorithm::~TrackerSamplerAlgorithm()
{
// nothing
}
TrackerSamplerCSC::Params::Params()
{
initInRad = 3;
initMaxNegNum = 65;
searchWinSize = 25;
trackInPosRad = 4;
trackMaxNegNum = 65;
trackMaxPosNum = 100000;
}
TrackerSamplerCSC::TrackerSamplerCSC(const TrackerSamplerCSC::Params& parameters)
: params(parameters)
{
mode = MODE_INIT_POS;
rng = theRNG();
}
TrackerSamplerCSC::~TrackerSamplerCSC()
{
// nothing
}
bool TrackerSamplerCSC::sampling(const Mat& image, const Rect& boundingBox, std::vector<Mat>& sample)
{
CV_Assert(!image.empty());
float inrad = 0;
float outrad = 0;
int maxnum = 0;
switch (mode)
{
case MODE_INIT_POS:
inrad = params.initInRad;
sample = sampleImage(image, boundingBox.x, boundingBox.y, boundingBox.width, boundingBox.height, inrad);
break;
case MODE_INIT_NEG:
inrad = 2.0f * params.searchWinSize;
outrad = 1.5f * params.initInRad;
maxnum = params.initMaxNegNum;
sample = sampleImage(image, boundingBox.x, boundingBox.y, boundingBox.width, boundingBox.height, inrad, outrad, maxnum);
break;
case MODE_TRACK_POS:
inrad = params.trackInPosRad;
outrad = 0;
maxnum = params.trackMaxPosNum;
sample = sampleImage(image, boundingBox.x, boundingBox.y, boundingBox.width, boundingBox.height, inrad, outrad, maxnum);
break;
case MODE_TRACK_NEG:
inrad = 1.5f * params.searchWinSize;
outrad = params.trackInPosRad + 5;
maxnum = params.trackMaxNegNum;
sample = sampleImage(image, boundingBox.x, boundingBox.y, boundingBox.width, boundingBox.height, inrad, outrad, maxnum);
break;
case MODE_DETECT:
inrad = params.searchWinSize;
sample = sampleImage(image, boundingBox.x, boundingBox.y, boundingBox.width, boundingBox.height, inrad);
break;
default:
inrad = params.initInRad;
sample = sampleImage(image, boundingBox.x, boundingBox.y, boundingBox.width, boundingBox.height, inrad);
break;
}
return false;
}
void TrackerSamplerCSC::setMode(int samplingMode)
{
mode = samplingMode;
}
std::vector<Mat> TrackerSamplerCSC::sampleImage(const Mat& img, int x, int y, int w, int h, float inrad, float outrad, int maxnum)
{
int rowsz = img.rows - h - 1;
int colsz = img.cols - w - 1;
float inradsq = inrad * inrad;
float outradsq = outrad * outrad;
int dist;
uint minrow = max(0, (int)y - (int)inrad);
uint maxrow = min((int)rowsz - 1, (int)y + (int)inrad);
uint mincol = max(0, (int)x - (int)inrad);
uint maxcol = min((int)colsz - 1, (int)x + (int)inrad);
//fprintf(stderr,"inrad=%f minrow=%d maxrow=%d mincol=%d maxcol=%d\n",inrad,minrow,maxrow,mincol,maxcol);
std::vector<Mat> samples;
samples.resize((maxrow - minrow + 1) * (maxcol - mincol + 1));
int i = 0;
float prob = ((float)(maxnum)) / samples.size();
for (int r = minrow; r <= int(maxrow); r++)
for (int c = mincol; c <= int(maxcol); c++)
{
dist = (y - r) * (y - r) + (x - c) * (x - c);
if (float(rng.uniform(0.f, 1.f)) < prob && dist < inradsq && dist >= outradsq)
{
samples[i] = img(Rect(c, r, w, h));
i++;
}
}
samples.resize(min(i, maxnum));
return samples;
}
}}} // namespace cv::detail::tracking
@@ -0,0 +1,37 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "../../precomp.hpp"
#include "opencv2/video/detail/tracking.private.hpp"
namespace cv {
namespace detail {
inline namespace tracking {
TrackerStateEstimator::~TrackerStateEstimator()
{
}
Ptr<TrackerTargetState> TrackerStateEstimator::estimate(const std::vector<ConfidenceMap>& confidenceMaps)
{
if (confidenceMaps.empty())
return Ptr<TrackerTargetState>();
return estimateImpl(confidenceMaps);
}
void TrackerStateEstimator::update(std::vector<ConfidenceMap>& confidenceMaps)
{
if (confidenceMaps.empty())
return;
return updateImpl(confidenceMaps);
}
String TrackerStateEstimator::getClassName() const
{
return className;
}
}}} // namespace cv::detail::tracking
@@ -0,0 +1,582 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "../../precomp.hpp"
#include "opencv2/video/detail/tracking.private.hpp"
#include "opencv2/video/detail/tracking_feature.private.hpp"
namespace cv {
namespace detail {
inline namespace tracking {
/*
* TODO This implementation is based on apps/traincascade/
* TODO Changed CvHaarEvaluator based on ADABOOSTING implementation (Grabner et al.)
*/
CvParams::CvParams()
{
// nothing
}
//---------------------------- FeatureParams --------------------------------------
CvFeatureParams::CvFeatureParams()
: maxCatCount(0)
, featSize(1)
, numFeatures(1)
{
// nothing
}
//------------------------------------- FeatureEvaluator ---------------------------------------
void CvFeatureEvaluator::init(const CvFeatureParams* _featureParams, int _maxSampleCount, Size _winSize)
{
CV_Assert(_featureParams);
CV_Assert(_maxSampleCount > 0);
featureParams = (CvFeatureParams*)_featureParams;
winSize = _winSize;
numFeatures = _featureParams->numFeatures;
cls.create((int)_maxSampleCount, 1, CV_32FC1);
generateFeatures();
}
void CvFeatureEvaluator::setImage(const Mat& img, uchar clsLabel, int idx)
{
winSize.width = img.cols;
winSize.height = img.rows;
//CV_Assert( img.cols == winSize.width );
//CV_Assert( img.rows == winSize.height );
CV_Assert(idx < cls.rows);
cls.ptr<float>(idx)[0] = clsLabel;
}
CvHaarFeatureParams::CvHaarFeatureParams()
{
isIntegral = false;
}
//--------------------- HaarFeatureEvaluator ----------------
void CvHaarEvaluator::init(const CvFeatureParams* _featureParams, int /*_maxSampleCount*/, Size _winSize)
{
CV_Assert(_featureParams);
int cols = (_winSize.width + 1) * (_winSize.height + 1);
sum.create((int)1, cols, CV_32SC1);
isIntegral = ((CvHaarFeatureParams*)_featureParams)->isIntegral;
CvFeatureEvaluator::init(_featureParams, 1, _winSize);
}
void CvHaarEvaluator::setImage(const Mat& img, uchar /*clsLabel*/, int /*idx*/)
{
CV_DbgAssert(!sum.empty());
winSize.width = img.cols;
winSize.height = img.rows;
CvFeatureEvaluator::setImage(img, 1, 0);
if (!isIntegral)
{
std::vector<Mat_<float>> ii_imgs;
compute_integral(img, ii_imgs);
_ii_img = ii_imgs[0];
}
else
{
_ii_img = img;
}
}
void CvHaarEvaluator::generateFeatures()
{
generateFeatures(featureParams->numFeatures);
}
void CvHaarEvaluator::generateFeatures(int nFeatures)
{
for (int i = 0; i < nFeatures; i++)
{
CvHaarEvaluator::FeatureHaar feature(Size(winSize.width, winSize.height));
features.push_back(feature);
}
}
#define INITSIGMA(numAreas) (static_cast<float>(sqrt(256.0f * 256.0f / 12.0f * (numAreas))));
CvHaarEvaluator::FeatureHaar::FeatureHaar(Size patchSize)
{
try
{
generateRandomFeature(patchSize);
}
catch (...)
{
// FIXIT
throw;
}
}
void CvHaarEvaluator::FeatureHaar::generateRandomFeature(Size patchSize)
{
cv::Point2i position;
Size baseDim;
Size sizeFactor;
int area;
CV_Assert(!patchSize.empty());
//Size minSize = Size( 3, 3 );
int minArea = 9;
bool valid = false;
while (!valid)
{
//choose position and scale
position.y = rand() % (patchSize.height);
position.x = rand() % (patchSize.width);
baseDim.width = (int)((1 - sqrt(1 - (float)rand() * (float)(1.0 / RAND_MAX))) * patchSize.width);
baseDim.height = (int)((1 - sqrt(1 - (float)rand() * (float)(1.0 / RAND_MAX))) * patchSize.height);
//select types
//float probType[11] = {0.0909f, 0.0909f, 0.0909f, 0.0909f, 0.0909f, 0.0909f, 0.0909f, 0.0909f, 0.0909f, 0.0909f, 0.0950f};
float probType[11] = { 0.2f, 0.2f, 0.2f, 0.2f, 0.2f, 0.2f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
float prob = (float)rand() * (float)(1.0 / RAND_MAX);
if (prob < probType[0])
{
//check if feature is valid
sizeFactor.height = 2;
sizeFactor.width = 1;
if (position.y + baseDim.height * sizeFactor.height >= patchSize.height || position.x + baseDim.width * sizeFactor.width >= patchSize.width)
continue;
area = baseDim.height * sizeFactor.height * baseDim.width * sizeFactor.width;
if (area < minArea)
continue;
m_type = 1;
m_numAreas = 2;
m_weights.resize(m_numAreas);
m_weights[0] = 1;
m_weights[1] = -1;
m_areas.resize(m_numAreas);
m_areas[0].x = position.x;
m_areas[0].y = position.y;
m_areas[0].height = baseDim.height;
m_areas[0].width = baseDim.width;
m_areas[1].x = position.x;
m_areas[1].y = position.y + baseDim.height;
m_areas[1].height = baseDim.height;
m_areas[1].width = baseDim.width;
m_initMean = 0;
m_initSigma = INITSIGMA(m_numAreas);
valid = true;
}
else if (prob < probType[0] + probType[1])
{
//check if feature is valid
sizeFactor.height = 1;
sizeFactor.width = 2;
if (position.y + baseDim.height * sizeFactor.height >= patchSize.height || position.x + baseDim.width * sizeFactor.width >= patchSize.width)
continue;
area = baseDim.height * sizeFactor.height * baseDim.width * sizeFactor.width;
if (area < minArea)
continue;
m_type = 2;
m_numAreas = 2;
m_weights.resize(m_numAreas);
m_weights[0] = 1;
m_weights[1] = -1;
m_areas.resize(m_numAreas);
m_areas[0].x = position.x;
m_areas[0].y = position.y;
m_areas[0].height = baseDim.height;
m_areas[0].width = baseDim.width;
m_areas[1].x = position.x + baseDim.width;
m_areas[1].y = position.y;
m_areas[1].height = baseDim.height;
m_areas[1].width = baseDim.width;
m_initMean = 0;
m_initSigma = INITSIGMA(m_numAreas);
valid = true;
}
else if (prob < probType[0] + probType[1] + probType[2])
{
//check if feature is valid
sizeFactor.height = 4;
sizeFactor.width = 1;
if (position.y + baseDim.height * sizeFactor.height >= patchSize.height || position.x + baseDim.width * sizeFactor.width >= patchSize.width)
continue;
area = baseDim.height * sizeFactor.height * baseDim.width * sizeFactor.width;
if (area < minArea)
continue;
m_type = 3;
m_numAreas = 3;
m_weights.resize(m_numAreas);
m_weights[0] = 1;
m_weights[1] = -2;
m_weights[2] = 1;
m_areas.resize(m_numAreas);
m_areas[0].x = position.x;
m_areas[0].y = position.y;
m_areas[0].height = baseDim.height;
m_areas[0].width = baseDim.width;
m_areas[1].x = position.x;
m_areas[1].y = position.y + baseDim.height;
m_areas[1].height = 2 * baseDim.height;
m_areas[1].width = baseDim.width;
m_areas[2].y = position.y + 3 * baseDim.height;
m_areas[2].x = position.x;
m_areas[2].height = baseDim.height;
m_areas[2].width = baseDim.width;
m_initMean = 0;
m_initSigma = INITSIGMA(m_numAreas);
valid = true;
}
else if (prob < probType[0] + probType[1] + probType[2] + probType[3])
{
//check if feature is valid
sizeFactor.height = 1;
sizeFactor.width = 4;
if (position.y + baseDim.height * sizeFactor.height >= patchSize.height || position.x + baseDim.width * sizeFactor.width >= patchSize.width)
continue;
area = baseDim.height * sizeFactor.height * baseDim.width * sizeFactor.width;
if (area < minArea)
continue;
m_type = 3;
m_numAreas = 3;
m_weights.resize(m_numAreas);
m_weights[0] = 1;
m_weights[1] = -2;
m_weights[2] = 1;
m_areas.resize(m_numAreas);
m_areas[0].x = position.x;
m_areas[0].y = position.y;
m_areas[0].height = baseDim.height;
m_areas[0].width = baseDim.width;
m_areas[1].x = position.x + baseDim.width;
m_areas[1].y = position.y;
m_areas[1].height = baseDim.height;
m_areas[1].width = 2 * baseDim.width;
m_areas[2].y = position.y;
m_areas[2].x = position.x + 3 * baseDim.width;
m_areas[2].height = baseDim.height;
m_areas[2].width = baseDim.width;
m_initMean = 0;
m_initSigma = INITSIGMA(m_numAreas);
valid = true;
}
else if (prob < probType[0] + probType[1] + probType[2] + probType[3] + probType[4])
{
//check if feature is valid
sizeFactor.height = 2;
sizeFactor.width = 2;
if (position.y + baseDim.height * sizeFactor.height >= patchSize.height || position.x + baseDim.width * sizeFactor.width >= patchSize.width)
continue;
area = baseDim.height * sizeFactor.height * baseDim.width * sizeFactor.width;
if (area < minArea)
continue;
m_type = 5;
m_numAreas = 4;
m_weights.resize(m_numAreas);
m_weights[0] = 1;
m_weights[1] = -1;
m_weights[2] = -1;
m_weights[3] = 1;
m_areas.resize(m_numAreas);
m_areas[0].x = position.x;
m_areas[0].y = position.y;
m_areas[0].height = baseDim.height;
m_areas[0].width = baseDim.width;
m_areas[1].x = position.x + baseDim.width;
m_areas[1].y = position.y;
m_areas[1].height = baseDim.height;
m_areas[1].width = baseDim.width;
m_areas[2].y = position.y + baseDim.height;
m_areas[2].x = position.x;
m_areas[2].height = baseDim.height;
m_areas[2].width = baseDim.width;
m_areas[3].y = position.y + baseDim.height;
m_areas[3].x = position.x + baseDim.width;
m_areas[3].height = baseDim.height;
m_areas[3].width = baseDim.width;
m_initMean = 0;
m_initSigma = INITSIGMA(m_numAreas);
valid = true;
}
else if (prob < probType[0] + probType[1] + probType[2] + probType[3] + probType[4] + probType[5])
{
//check if feature is valid
sizeFactor.height = 3;
sizeFactor.width = 3;
if (position.y + baseDim.height * sizeFactor.height >= patchSize.height || position.x + baseDim.width * sizeFactor.width >= patchSize.width)
continue;
area = baseDim.height * sizeFactor.height * baseDim.width * sizeFactor.width;
if (area < minArea)
continue;
m_type = 6;
m_numAreas = 2;
m_weights.resize(m_numAreas);
m_weights[0] = 1;
m_weights[1] = -9;
m_areas.resize(m_numAreas);
m_areas[0].x = position.x;
m_areas[0].y = position.y;
m_areas[0].height = 3 * baseDim.height;
m_areas[0].width = 3 * baseDim.width;
m_areas[1].x = position.x + baseDim.width;
m_areas[1].y = position.y + baseDim.height;
m_areas[1].height = baseDim.height;
m_areas[1].width = baseDim.width;
m_initMean = -8 * 128;
m_initSigma = INITSIGMA(m_numAreas);
valid = true;
}
else if (prob < probType[0] + probType[1] + probType[2] + probType[3] + probType[4] + probType[5] + probType[6])
{
//check if feature is valid
sizeFactor.height = 3;
sizeFactor.width = 1;
if (position.y + baseDim.height * sizeFactor.height >= patchSize.height || position.x + baseDim.width * sizeFactor.width >= patchSize.width)
continue;
area = baseDim.height * sizeFactor.height * baseDim.width * sizeFactor.width;
if (area < minArea)
continue;
m_type = 7;
m_numAreas = 3;
m_weights.resize(m_numAreas);
m_weights[0] = 1;
m_weights[1] = -2;
m_weights[2] = 1;
m_areas.resize(m_numAreas);
m_areas[0].x = position.x;
m_areas[0].y = position.y;
m_areas[0].height = baseDim.height;
m_areas[0].width = baseDim.width;
m_areas[1].x = position.x;
m_areas[1].y = position.y + baseDim.height;
m_areas[1].height = baseDim.height;
m_areas[1].width = baseDim.width;
m_areas[2].y = position.y + baseDim.height * 2;
m_areas[2].x = position.x;
m_areas[2].height = baseDim.height;
m_areas[2].width = baseDim.width;
m_initMean = 0;
m_initSigma = INITSIGMA(m_numAreas);
valid = true;
}
else if (prob < probType[0] + probType[1] + probType[2] + probType[3] + probType[4] + probType[5] + probType[6] + probType[7])
{
//check if feature is valid
sizeFactor.height = 1;
sizeFactor.width = 3;
if (position.y + baseDim.height * sizeFactor.height >= patchSize.height || position.x + baseDim.width * sizeFactor.width >= patchSize.width)
continue;
area = baseDim.height * sizeFactor.height * baseDim.width * sizeFactor.width;
if (area < minArea)
continue;
m_type = 8;
m_numAreas = 3;
m_weights.resize(m_numAreas);
m_weights[0] = 1;
m_weights[1] = -2;
m_weights[2] = 1;
m_areas.resize(m_numAreas);
m_areas[0].x = position.x;
m_areas[0].y = position.y;
m_areas[0].height = baseDim.height;
m_areas[0].width = baseDim.width;
m_areas[1].x = position.x + baseDim.width;
m_areas[1].y = position.y;
m_areas[1].height = baseDim.height;
m_areas[1].width = baseDim.width;
m_areas[2].y = position.y;
m_areas[2].x = position.x + 2 * baseDim.width;
m_areas[2].height = baseDim.height;
m_areas[2].width = baseDim.width;
m_initMean = 0;
m_initSigma = INITSIGMA(m_numAreas);
valid = true;
}
else if (prob < probType[0] + probType[1] + probType[2] + probType[3] + probType[4] + probType[5] + probType[6] + probType[7] + probType[8])
{
//check if feature is valid
sizeFactor.height = 3;
sizeFactor.width = 3;
if (position.y + baseDim.height * sizeFactor.height >= patchSize.height || position.x + baseDim.width * sizeFactor.width >= patchSize.width)
continue;
area = baseDim.height * sizeFactor.height * baseDim.width * sizeFactor.width;
if (area < minArea)
continue;
m_type = 9;
m_numAreas = 2;
m_weights.resize(m_numAreas);
m_weights[0] = 1;
m_weights[1] = -2;
m_areas.resize(m_numAreas);
m_areas[0].x = position.x;
m_areas[0].y = position.y;
m_areas[0].height = 3 * baseDim.height;
m_areas[0].width = 3 * baseDim.width;
m_areas[1].x = position.x + baseDim.width;
m_areas[1].y = position.y + baseDim.height;
m_areas[1].height = baseDim.height;
m_areas[1].width = baseDim.width;
m_initMean = 0;
m_initSigma = INITSIGMA(m_numAreas);
valid = true;
}
else if (prob
< probType[0] + probType[1] + probType[2] + probType[3] + probType[4] + probType[5] + probType[6] + probType[7] + probType[8] + probType[9])
{
//check if feature is valid
sizeFactor.height = 3;
sizeFactor.width = 1;
if (position.y + baseDim.height * sizeFactor.height >= patchSize.height || position.x + baseDim.width * sizeFactor.width >= patchSize.width)
continue;
area = baseDim.height * sizeFactor.height * baseDim.width * sizeFactor.width;
if (area < minArea)
continue;
m_type = 10;
m_numAreas = 3;
m_weights.resize(m_numAreas);
m_weights[0] = 1;
m_weights[1] = -1;
m_weights[2] = 1;
m_areas.resize(m_numAreas);
m_areas[0].x = position.x;
m_areas[0].y = position.y;
m_areas[0].height = baseDim.height;
m_areas[0].width = baseDim.width;
m_areas[1].x = position.x;
m_areas[1].y = position.y + baseDim.height;
m_areas[1].height = baseDim.height;
m_areas[1].width = baseDim.width;
m_areas[2].y = position.y + baseDim.height * 2;
m_areas[2].x = position.x;
m_areas[2].height = baseDim.height;
m_areas[2].width = baseDim.width;
m_initMean = 128;
m_initSigma = INITSIGMA(m_numAreas);
valid = true;
}
else if (prob
< probType[0] + probType[1] + probType[2] + probType[3] + probType[4] + probType[5] + probType[6] + probType[7] + probType[8] + probType[9]
+ probType[10])
{
//check if feature is valid
sizeFactor.height = 1;
sizeFactor.width = 3;
if (position.y + baseDim.height * sizeFactor.height >= patchSize.height || position.x + baseDim.width * sizeFactor.width >= patchSize.width)
continue;
area = baseDim.height * sizeFactor.height * baseDim.width * sizeFactor.width;
if (area < minArea)
continue;
m_type = 11;
m_numAreas = 3;
m_weights.resize(m_numAreas);
m_weights[0] = 1;
m_weights[1] = -1;
m_weights[2] = 1;
m_areas.resize(m_numAreas);
m_areas[0].x = position.x;
m_areas[0].y = position.y;
m_areas[0].height = baseDim.height;
m_areas[0].width = baseDim.width;
m_areas[1].x = position.x + baseDim.width;
m_areas[1].y = position.y;
m_areas[1].height = baseDim.height;
m_areas[1].width = baseDim.width;
m_areas[2].y = position.y;
m_areas[2].x = position.x + 2 * baseDim.width;
m_areas[2].height = baseDim.height;
m_areas[2].width = baseDim.width;
m_initMean = 128;
m_initSigma = INITSIGMA(m_numAreas);
valid = true;
}
else
CV_Error(Error::StsAssert, "");
}
m_initSize = patchSize;
m_curSize = m_initSize;
m_scaleFactorWidth = m_scaleFactorHeight = 1.0f;
m_scaleAreas.resize(m_numAreas);
m_scaleWeights.resize(m_numAreas);
for (int curArea = 0; curArea < m_numAreas; curArea++)
{
m_scaleAreas[curArea] = m_areas[curArea];
m_scaleWeights[curArea] = (float)m_weights[curArea] / (float)(m_areas[curArea].width * m_areas[curArea].height);
}
}
bool CvHaarEvaluator::FeatureHaar::eval(const Mat& image, Rect /*ROI*/, float* result) const
{
*result = 0.0f;
for (int curArea = 0; curArea < m_numAreas; curArea++)
{
*result += (float)getSum(image, Rect(m_areas[curArea].x, m_areas[curArea].y, m_areas[curArea].width, m_areas[curArea].height))
* m_scaleWeights[curArea];
}
/*
if( image->getUseVariance() )
{
float variance = (float) image->getVariance( ROI );
*result /= variance;
}
*/
return true;
}
float CvHaarEvaluator::FeatureHaar::getSum(const Mat& image, Rect imageROI) const
{
// left upper Origin
int OriginX = imageROI.x;
int OriginY = imageROI.y;
// Check and fix width and height
int Width = imageROI.width;
int Height = imageROI.height;
if (OriginX + Width >= image.cols - 1)
Width = (image.cols - 1) - OriginX;
if (OriginY + Height >= image.rows - 1)
Height = (image.rows - 1) - OriginY;
float value = 0;
int depth = image.depth();
if (depth == CV_8U || depth == CV_32S)
value = static_cast<float>(image.at<int>(OriginY + Height, OriginX + Width) + image.at<int>(OriginY, OriginX) - image.at<int>(OriginY, OriginX + Width)
- image.at<int>(OriginY + Height, OriginX));
else if (depth == CV_64F)
value = static_cast<float>(image.at<double>(OriginY + Height, OriginX + Width) + image.at<double>(OriginY, OriginX)
- image.at<double>(OriginY, OriginX + Width) - image.at<double>(OriginY + Height, OriginX));
else if (depth == CV_32F)
value = static_cast<float>(image.at<float>(OriginY + Height, OriginX + Width) + image.at<float>(OriginY, OriginX) - image.at<float>(OriginY, OriginX + Width)
- image.at<float>(OriginY + Height, OriginX));
return value;
}
}}} // namespace cv::detail::tracking
@@ -0,0 +1,356 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "../../precomp.hpp"
#include "tracking_online_mil.hpp"
namespace cv {
namespace detail {
inline namespace tracking {
#define sign(s) ((s > 0) ? 1 : ((s < 0) ? -1 : 0))
template <class T>
class SortableElementRev
{
public:
T _val;
int _ind;
SortableElementRev()
: _val(), _ind(0)
{
}
SortableElementRev(T val, int ind)
{
_val = val;
_ind = ind;
}
bool operator<(SortableElementRev<T>& b)
{
return (_val < b._val);
};
};
static bool CompareSortableElementRev(const SortableElementRev<float>& i, const SortableElementRev<float>& j)
{
return i._val < j._val;
}
template <class T>
void sort_order_des(std::vector<T>& v, std::vector<int>& order)
{
uint n = (uint)v.size();
std::vector<SortableElementRev<T>> v2;
v2.resize(n);
order.clear();
order.resize(n);
for (uint i = 0; i < n; i++)
{
v2[i]._ind = i;
v2[i]._val = v[i];
}
//std::sort( v2.begin(), v2.end() );
std::sort(v2.begin(), v2.end(), CompareSortableElementRev);
for (uint i = 0; i < n; i++)
{
order[i] = v2[i]._ind;
v[i] = v2[i]._val;
}
};
//implementations for strong classifier
ClfMilBoost::Params::Params()
{
_numSel = 50;
_numFeat = 250;
_lRate = 0.85f;
}
ClfMilBoost::ClfMilBoost()
: _numsamples(0)
, _counter(0)
{
_myParams = ClfMilBoost::Params();
_numsamples = 0;
}
ClfMilBoost::~ClfMilBoost()
{
_selectors.clear();
for (size_t i = 0; i < _weakclf.size(); i++)
delete _weakclf.at(i);
}
void ClfMilBoost::init(const ClfMilBoost::Params& parameters)
{
_myParams = parameters;
_numsamples = 0;
//_ftrs = Ftr::generate( _myParams->_ftrParams, _myParams->_numFeat );
// if( params->_storeFtrHistory )
// Ftr::toViz( _ftrs, "haarftrs" );
_weakclf.resize(_myParams._numFeat);
for (int k = 0; k < _myParams._numFeat; k++)
{
_weakclf[k] = new ClfOnlineStump(k);
_weakclf[k]->_lRate = _myParams._lRate;
}
_counter = 0;
}
void ClfMilBoost::update(const Mat& posx, const Mat& negx)
{
int numneg = negx.rows;
int numpos = posx.rows;
// compute ftrs
//if( !posx.ftrsComputed() )
// Ftr::compute( posx, _ftrs );
//if( !negx.ftrsComputed() )
// Ftr::compute( negx, _ftrs );
// initialize H
static std::vector<float> Hpos, Hneg;
Hpos.clear();
Hneg.clear();
Hpos.resize(posx.rows, 0.0f), Hneg.resize(negx.rows, 0.0f);
_selectors.clear();
std::vector<float> posw(posx.rows), negw(negx.rows);
std::vector<std::vector<float>> pospred(_weakclf.size()), negpred(_weakclf.size());
// train all weak classifiers without weights
#ifdef _OPENMP
#pragma omp parallel for
#endif
for (int m = 0; m < _myParams._numFeat; m++)
{
_weakclf[m]->update(posx, negx);
pospred[m] = _weakclf[m]->classifySetF(posx);
negpred[m] = _weakclf[m]->classifySetF(negx);
}
// pick the best features
for (int s = 0; s < _myParams._numSel; s++)
{
// compute errors/likl for all weak clfs
std::vector<float> poslikl(_weakclf.size(), 1.0f), neglikl(_weakclf.size()), likl(_weakclf.size());
#ifdef _OPENMP
#pragma omp parallel for
#endif
for (int w = 0; w < (int)_weakclf.size(); w++)
{
float lll = 1.0f;
for (int j = 0; j < numpos; j++)
lll *= (1 - sigmoid(Hpos[j] + pospred[w][j]));
poslikl[w] = (float)-log(1 - lll + 1e-5);
lll = 0.0f;
for (int j = 0; j < numneg; j++)
lll += (float)-log(1e-5f + 1 - sigmoid(Hneg[j] + negpred[w][j]));
neglikl[w] = lll;
likl[w] = poslikl[w] / numpos + neglikl[w] / numneg;
}
// pick best weak clf
std::vector<int> order;
sort_order_des(likl, order);
// find best weakclf that isn't already included
for (uint k = 0; k < order.size(); k++)
if (std::count(_selectors.begin(), _selectors.end(), order[k]) == 0)
{
_selectors.push_back(order[k]);
break;
}
// update H = H + h_m
#ifdef _OPENMP
#pragma omp parallel for
#endif
for (int k = 0; k < posx.rows; k++)
Hpos[k] += pospred[_selectors[s]][k];
#ifdef _OPENMP
#pragma omp parallel for
#endif
for (int k = 0; k < negx.rows; k++)
Hneg[k] += negpred[_selectors[s]][k];
}
//if( _myParams->_storeFtrHistory )
//for ( uint j = 0; j < _selectors.size(); j++ )
// _ftrHist( _selectors[j], _counter ) = 1.0f / ( j + 1 );
_counter++;
/* */
return;
}
std::vector<float> ClfMilBoost::classify(const Mat& x, bool logR)
{
int numsamples = x.rows;
std::vector<float> res(numsamples);
std::vector<float> tr;
for (uint w = 0; w < _selectors.size(); w++)
{
tr = _weakclf[_selectors[w]]->classifySetF(x);
#ifdef _OPENMP
#pragma omp parallel for
#endif
for (int j = 0; j < numsamples; j++)
{
res[j] += tr[j];
}
}
// return probabilities or log odds ratio
if (!logR)
{
#ifdef _OPENMP
#pragma omp parallel for
#endif
for (int j = 0; j < (int)res.size(); j++)
{
res[j] = sigmoid(res[j]);
}
}
return res;
}
//implementations for weak classifier
ClfOnlineStump::ClfOnlineStump()
: _mu0(0), _mu1(0), _sig0(0), _sig1(0)
, _q(0)
, _s(0)
, _log_n1(0), _log_n0(0)
, _e1(0), _e0(0)
, _lRate(0)
{
_trained = false;
_ind = -1;
init();
}
ClfOnlineStump::ClfOnlineStump(int ind)
: _mu0(0), _mu1(0), _sig0(0), _sig1(0)
, _q(0)
, _s(0)
, _log_n1(0), _log_n0(0)
, _e1(0), _e0(0)
, _lRate(0)
{
_trained = false;
_ind = ind;
init();
}
void ClfOnlineStump::init()
{
_mu0 = 0;
_mu1 = 0;
_sig0 = 1;
_sig1 = 1;
_lRate = 0.85f;
_trained = false;
}
void ClfOnlineStump::update(const Mat& posx, const Mat& negx, const Mat_<float>& /*posw*/, const Mat_<float>& /*negw*/)
{
//std::cout << " ClfOnlineStump::update" << _ind << std::endl;
float posmu = 0.0, negmu = 0.0;
if (posx.cols > 0)
posmu = float(mean(posx.col(_ind))[0]);
if (negx.cols > 0)
negmu = float(mean(negx.col(_ind))[0]);
if (_trained)
{
if (posx.cols > 0)
{
_mu1 = (_lRate * _mu1 + (1 - _lRate) * posmu);
cv::Mat diff = posx.col(_ind) - _mu1;
_sig1 = _lRate * _sig1 + (1 - _lRate) * float(mean(diff.mul(diff))[0]);
}
if (negx.cols > 0)
{
_mu0 = (_lRate * _mu0 + (1 - _lRate) * negmu);
cv::Mat diff = negx.col(_ind) - _mu0;
_sig0 = _lRate * _sig0 + (1 - _lRate) * float(mean(diff.mul(diff))[0]);
}
_q = (_mu1 - _mu0) / 2;
_s = sign(_mu1 - _mu0);
_log_n0 = std::log(float(1.0f / pow(_sig0, 0.5f)));
_log_n1 = std::log(float(1.0f / pow(_sig1, 0.5f)));
//_e1 = -1.0f/(2.0f*_sig1+1e-99f);
//_e0 = -1.0f/(2.0f*_sig0+1e-99f);
_e1 = -1.0f / (2.0f * _sig1 + std::numeric_limits<float>::min());
_e0 = -1.0f / (2.0f * _sig0 + std::numeric_limits<float>::min());
}
else
{
_trained = true;
if (posx.cols > 0)
{
_mu1 = posmu;
cv::Scalar scal_mean, scal_std_dev;
cv::meanStdDev(posx.col(_ind), scal_mean, scal_std_dev);
_sig1 = float(scal_std_dev[0]) * float(scal_std_dev[0]) + 1e-9f;
}
if (negx.cols > 0)
{
_mu0 = negmu;
cv::Scalar scal_mean, scal_std_dev;
cv::meanStdDev(negx.col(_ind), scal_mean, scal_std_dev);
_sig0 = float(scal_std_dev[0]) * float(scal_std_dev[0]) + 1e-9f;
}
_q = (_mu1 - _mu0) / 2;
_s = sign(_mu1 - _mu0);
_log_n0 = std::log(float(1.0f / pow(_sig0, 0.5f)));
_log_n1 = std::log(float(1.0f / pow(_sig1, 0.5f)));
//_e1 = -1.0f/(2.0f*_sig1+1e-99f);
//_e0 = -1.0f/(2.0f*_sig0+1e-99f);
_e1 = -1.0f / (2.0f * _sig1 + std::numeric_limits<float>::min());
_e0 = -1.0f / (2.0f * _sig0 + std::numeric_limits<float>::min());
}
}
bool ClfOnlineStump::classify(const Mat& x, int i)
{
float xx = x.at<float>(i, _ind);
double log_p0 = (xx - _mu0) * (xx - _mu0) * _e0 + _log_n0;
double log_p1 = (xx - _mu1) * (xx - _mu1) * _e1 + _log_n1;
return log_p1 > log_p0;
}
float ClfOnlineStump::classifyF(const Mat& x, int i)
{
float xx = x.at<float>(i, _ind);
double log_p0 = (xx - _mu0) * (xx - _mu0) * _e0 + _log_n0;
double log_p1 = (xx - _mu1) * (xx - _mu1) * _e1 + _log_n1;
return float(log_p1 - log_p0);
}
inline std::vector<float> ClfOnlineStump::classifySetF(const Mat& x)
{
std::vector<float> res(x.rows);
#ifdef _OPENMP
#pragma omp parallel for
#endif
for (int k = 0; k < (int)res.size(); k++)
{
res[k] = classifyF(x, k);
}
return res;
}
}}} // namespace cv::detail::tracking
@@ -0,0 +1,79 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef OPENCV_VIDEO_DETAIL_TRACKING_ONLINE_MIL_HPP
#define OPENCV_VIDEO_DETAIL_TRACKING_ONLINE_MIL_HPP
#include <limits>
namespace cv {
namespace detail {
inline namespace tracking {
//! @addtogroup tracking_detail
//! @{
//TODO based on the original implementation
//http://vision.ucsd.edu/~bbabenko/project_miltrack.shtml
class ClfOnlineStump;
class CV_EXPORTS ClfMilBoost
{
public:
struct CV_EXPORTS Params
{
Params();
int _numSel;
int _numFeat;
float _lRate;
};
ClfMilBoost();
~ClfMilBoost();
void init(const ClfMilBoost::Params& parameters = ClfMilBoost::Params());
void update(const Mat& posx, const Mat& negx);
std::vector<float> classify(const Mat& x, bool logR = true);
inline float sigmoid(float x)
{
return 1.0f / (1.0f + exp(-x));
}
private:
uint _numsamples;
ClfMilBoost::Params _myParams;
std::vector<int> _selectors;
std::vector<ClfOnlineStump*> _weakclf;
uint _counter;
};
class ClfOnlineStump
{
public:
float _mu0, _mu1, _sig0, _sig1;
float _q;
int _s;
float _log_n1, _log_n0;
float _e1, _e0;
float _lRate;
ClfOnlineStump();
ClfOnlineStump(int ind);
void init();
void update(const Mat& posx, const Mat& negx, const cv::Mat_<float>& posw = cv::Mat_<float>(), const cv::Mat_<float>& negw = cv::Mat_<float>());
bool classify(const Mat& x, int i);
float classifyF(const Mat& x, int i);
std::vector<float> classifySetF(const Mat& x);
private:
bool _trained;
int _ind;
};
//! @}
}}} // namespace cv::detail::tracking
#endif
+19
View File
@@ -0,0 +1,19 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "../precomp.hpp"
namespace cv {
Tracker::Tracker()
{
// nothing
}
Tracker::~Tracker()
{
// nothing
}
} // namespace cv
@@ -0,0 +1,140 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "../precomp.hpp"
#ifdef HAVE_OPENCV_DNN
#include "opencv2/dnn.hpp"
#endif
namespace cv {
TrackerGOTURN::TrackerGOTURN()
{
// nothing
}
TrackerGOTURN::~TrackerGOTURN()
{
// nothing
}
TrackerGOTURN::Params::Params()
{
modelTxt = "goturn.prototxt";
modelBin = "goturn.caffemodel";
}
#ifdef HAVE_OPENCV_DNN
class TrackerGOTURNImpl : public TrackerGOTURN
{
public:
TrackerGOTURNImpl(const TrackerGOTURN::Params& parameters)
: params(parameters)
{
// Load GOTURN architecture from *.prototxt and pretrained weights from *.caffemodel
net = dnn::readNetFromCaffe(params.modelTxt, params.modelBin);
CV_Assert(!net.empty());
}
void init(InputArray image, const Rect& boundingBox) CV_OVERRIDE;
bool update(InputArray image, Rect& boundingBox) CV_OVERRIDE;
void setBoudingBox(Rect boundingBox)
{
if (image_.empty())
CV_Error(Error::StsInternal, "Set image first");
boundingBox_ = boundingBox & Rect(Point(0, 0), image_.size());
}
TrackerGOTURN::Params params;
dnn::Net net;
Rect boundingBox_;
Mat image_;
};
void TrackerGOTURNImpl::init(InputArray image, const Rect& boundingBox)
{
image_ = image.getMat().clone();
setBoudingBox(boundingBox);
}
bool TrackerGOTURNImpl::update(InputArray image, Rect& boundingBox)
{
int INPUT_SIZE = 227;
//Using prevFrame & prevBB from model and curFrame GOTURN calculating curBB
InputArray curFrame = image;
Mat prevFrame = image_;
Rect2d prevBB = boundingBox_;
Rect curBB;
float padTargetPatch = 2.0;
Rect2f searchPatchRect, targetPatchRect;
Point2f currCenter, prevCenter;
Mat prevFramePadded, curFramePadded;
Mat searchPatch, targetPatch;
prevCenter.x = (float)(prevBB.x + prevBB.width / 2);
prevCenter.y = (float)(prevBB.y + prevBB.height / 2);
targetPatchRect.width = (float)(prevBB.width * padTargetPatch);
targetPatchRect.height = (float)(prevBB.height * padTargetPatch);
targetPatchRect.x = (float)(prevCenter.x - prevBB.width * padTargetPatch / 2.0 + targetPatchRect.width);
targetPatchRect.y = (float)(prevCenter.y - prevBB.height * padTargetPatch / 2.0 + targetPatchRect.height);
targetPatchRect.width = std::min(targetPatchRect.width, (float)prevFrame.cols);
targetPatchRect.height = std::min(targetPatchRect.height, (float)prevFrame.rows);
targetPatchRect.x = std::max(-prevFrame.cols * 0.5f, std::min(targetPatchRect.x, prevFrame.cols * 1.5f));
targetPatchRect.y = std::max(-prevFrame.rows * 0.5f, std::min(targetPatchRect.y, prevFrame.rows * 1.5f));
copyMakeBorder(prevFrame, prevFramePadded, (int)targetPatchRect.height, (int)targetPatchRect.height, (int)targetPatchRect.width, (int)targetPatchRect.width, BORDER_REPLICATE);
targetPatch = prevFramePadded(targetPatchRect).clone();
copyMakeBorder(curFrame, curFramePadded, (int)targetPatchRect.height, (int)targetPatchRect.height, (int)targetPatchRect.width, (int)targetPatchRect.width, BORDER_REPLICATE);
searchPatch = curFramePadded(targetPatchRect).clone();
// Preprocess
// Resize
resize(targetPatch, targetPatch, Size(INPUT_SIZE, INPUT_SIZE), 0, 0, INTER_LINEAR_EXACT);
resize(searchPatch, searchPatch, Size(INPUT_SIZE, INPUT_SIZE), 0, 0, INTER_LINEAR_EXACT);
// Convert to Float type and subtract mean
Mat targetBlob = dnn::blobFromImage(targetPatch, 1.0f, Size(), Scalar::all(128), false);
Mat searchBlob = dnn::blobFromImage(searchPatch, 1.0f, Size(), Scalar::all(128), false);
net.setInput(targetBlob, "data1");
net.setInput(searchBlob, "data2");
Mat resMat = net.forward("scale").reshape(1, 1);
curBB.x = cvRound(targetPatchRect.x + (resMat.at<float>(0) * targetPatchRect.width / INPUT_SIZE) - targetPatchRect.width);
curBB.y = cvRound(targetPatchRect.y + (resMat.at<float>(1) * targetPatchRect.height / INPUT_SIZE) - targetPatchRect.height);
curBB.width = cvRound((resMat.at<float>(2) - resMat.at<float>(0)) * targetPatchRect.width / INPUT_SIZE);
curBB.height = cvRound((resMat.at<float>(3) - resMat.at<float>(1)) * targetPatchRect.height / INPUT_SIZE);
// Predicted BB
boundingBox = curBB & Rect(Point(0, 0), image_.size());
// Set new model image and BB from current frame
image_ = image.getMat().clone();
setBoudingBox(curBB);
return true;
}
Ptr<TrackerGOTURN> TrackerGOTURN::create(const TrackerGOTURN::Params& parameters)
{
return makePtr<TrackerGOTURNImpl>(parameters);
}
#else // OPENCV_HAVE_DNN
Ptr<TrackerGOTURN> TrackerGOTURN::create(const TrackerGOTURN::Params& parameters)
{
(void)(parameters);
CV_Error(cv::Error::StsNotImplemented, "to use GOTURN, the tracking module needs to be built with opencv_dnn !");
}
#endif // OPENCV_HAVE_DNN
} // namespace cv
+227
View File
@@ -0,0 +1,227 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "../precomp.hpp"
#include "detail/tracker_mil_model.hpp"
#include "detail/tracker_feature_haar.impl.hpp"
namespace cv {
inline namespace tracking {
namespace impl {
using cv::detail::tracking::internal::TrackerFeatureHAAR;
class TrackerMILImpl CV_FINAL : public TrackerMIL
{
public:
TrackerMILImpl(const TrackerMIL::Params& parameters);
virtual void init(InputArray image, const Rect& boundingBox) CV_OVERRIDE;
virtual bool update(InputArray image, Rect& boundingBox) CV_OVERRIDE;
void compute_integral(const Mat& img, Mat& ii_img);
TrackerMIL::Params params;
Ptr<TrackerMILModel> model;
Ptr<TrackerSampler> sampler;
Ptr<TrackerFeatureSet> featureSet;
};
TrackerMILImpl::TrackerMILImpl(const TrackerMIL::Params& parameters)
: params(parameters)
{
// nothing
}
void TrackerMILImpl::compute_integral(const Mat& img, Mat& ii_img)
{
Mat ii;
std::vector<Mat> ii_imgs;
integral(img, ii, CV_32F); // FIXIT split first
split(ii, ii_imgs);
ii_img = ii_imgs[0];
}
void TrackerMILImpl::init(InputArray image, const Rect& boundingBox)
{
sampler = makePtr<TrackerSampler>();
featureSet = makePtr<TrackerFeatureSet>();
Mat intImage;
compute_integral(image.getMat(), intImage);
TrackerSamplerCSC::Params CSCparameters;
CSCparameters.initInRad = params.samplerInitInRadius;
CSCparameters.searchWinSize = params.samplerSearchWinSize;
CSCparameters.initMaxNegNum = params.samplerInitMaxNegNum;
CSCparameters.trackInPosRad = params.samplerTrackInRadius;
CSCparameters.trackMaxPosNum = params.samplerTrackMaxPosNum;
CSCparameters.trackMaxNegNum = params.samplerTrackMaxNegNum;
Ptr<TrackerSamplerAlgorithm> CSCSampler = makePtr<TrackerSamplerCSC>(CSCparameters);
CV_Assert(sampler->addTrackerSamplerAlgorithm(CSCSampler));
//or add CSC sampler with default parameters
//sampler->addTrackerSamplerAlgorithm( "CSC" );
//Positive sampling
CSCSampler.staticCast<TrackerSamplerCSC>()->setMode(TrackerSamplerCSC::MODE_INIT_POS);
sampler->sampling(intImage, boundingBox);
std::vector<Mat> posSamples = sampler->getSamples();
//Negative sampling
CSCSampler.staticCast<TrackerSamplerCSC>()->setMode(TrackerSamplerCSC::MODE_INIT_NEG);
sampler->sampling(intImage, boundingBox);
std::vector<Mat> negSamples = sampler->getSamples();
CV_Assert(!posSamples.empty());
CV_Assert(!negSamples.empty());
//compute HAAR features
TrackerFeatureHAAR::Params HAARparameters;
HAARparameters.numFeatures = params.featureSetNumFeatures;
HAARparameters.rectSize = Size((int)boundingBox.width, (int)boundingBox.height);
HAARparameters.isIntegral = true;
Ptr<TrackerFeature> trackerFeature = makePtr<TrackerFeatureHAAR>(HAARparameters);
featureSet->addTrackerFeature(trackerFeature);
featureSet->extraction(posSamples);
const std::vector<Mat> posResponse = featureSet->getResponses();
featureSet->extraction(negSamples);
const std::vector<Mat> negResponse = featureSet->getResponses();
model = makePtr<TrackerMILModel>(boundingBox);
Ptr<TrackerStateEstimatorMILBoosting> stateEstimator = makePtr<TrackerStateEstimatorMILBoosting>(params.featureSetNumFeatures);
model->setTrackerStateEstimator(stateEstimator);
//Run model estimation and update
model.staticCast<TrackerMILModel>()->setMode(TrackerMILModel::MODE_POSITIVE, posSamples);
model->modelEstimation(posResponse);
model.staticCast<TrackerMILModel>()->setMode(TrackerMILModel::MODE_NEGATIVE, negSamples);
model->modelEstimation(negResponse);
model->modelUpdate();
}
bool TrackerMILImpl::update(InputArray image, Rect& boundingBox)
{
Mat intImage;
compute_integral(image.getMat(), intImage);
//get the last location [AAM] X(k-1)
Ptr<TrackerTargetState> lastLocation = model->getLastTargetState();
Rect lastBoundingBox((int)lastLocation->getTargetPosition().x, (int)lastLocation->getTargetPosition().y, lastLocation->getTargetWidth(),
lastLocation->getTargetHeight());
//sampling new frame based on last location
auto& samplers = sampler->getSamplers();
CV_Assert(!samplers.empty());
CV_Assert(samplers[0]);
samplers[0].staticCast<TrackerSamplerCSC>()->setMode(TrackerSamplerCSC::MODE_DETECT);
sampler->sampling(intImage, lastBoundingBox);
std::vector<Mat> detectSamples = sampler->getSamples();
if (detectSamples.empty())
return false;
/*//TODO debug samples
Mat f;
image.copyTo(f);
for( size_t i = 0; i < detectSamples.size(); i=i+10 )
{
Size sz;
Point off;
detectSamples.at(i).locateROI(sz, off);
rectangle(f, Rect(off.x,off.y,detectSamples.at(i).cols,detectSamples.at(i).rows), Scalar(255,0,0), 1);
}*/
//extract features from new samples
featureSet->extraction(detectSamples);
std::vector<Mat> response = featureSet->getResponses();
//predict new location
ConfidenceMap cmap;
model.staticCast<TrackerMILModel>()->setMode(TrackerMILModel::MODE_ESTIMATON, detectSamples);
model.staticCast<TrackerMILModel>()->responseToConfidenceMap(response, cmap);
model->getTrackerStateEstimator().staticCast<TrackerStateEstimatorMILBoosting>()->setCurrentConfidenceMap(cmap);
if (!model->runStateEstimator())
{
return false;
}
Ptr<TrackerTargetState> currentState = model->getLastTargetState();
boundingBox = Rect((int)currentState->getTargetPosition().x, (int)currentState->getTargetPosition().y, currentState->getTargetWidth(),
currentState->getTargetHeight());
/*//TODO debug
rectangle(f, lastBoundingBox, Scalar(0,255,0), 1);
rectangle(f, boundingBox, Scalar(0,0,255), 1);
imshow("f", f);
//waitKey( 0 );*/
//sampling new frame based on new location
//Positive sampling
samplers[0].staticCast<TrackerSamplerCSC>()->setMode(TrackerSamplerCSC::MODE_INIT_POS);
sampler->sampling(intImage, boundingBox);
std::vector<Mat> posSamples = sampler->getSamples();
//Negative sampling
samplers[0].staticCast<TrackerSamplerCSC>()->setMode(TrackerSamplerCSC::MODE_INIT_NEG);
sampler->sampling(intImage, boundingBox);
std::vector<Mat> negSamples = sampler->getSamples();
if (posSamples.empty() || negSamples.empty())
return false;
//extract features
featureSet->extraction(posSamples);
std::vector<Mat> posResponse = featureSet->getResponses();
featureSet->extraction(negSamples);
std::vector<Mat> negResponse = featureSet->getResponses();
//model estimate
model.staticCast<TrackerMILModel>()->setMode(TrackerMILModel::MODE_POSITIVE, posSamples);
model->modelEstimation(posResponse);
model.staticCast<TrackerMILModel>()->setMode(TrackerMILModel::MODE_NEGATIVE, negSamples);
model->modelEstimation(negResponse);
//model update
model->modelUpdate();
return true;
}
}} // namespace tracking::impl
TrackerMIL::Params::Params()
{
samplerInitInRadius = 3;
samplerSearchWinSize = 25;
samplerInitMaxNegNum = 65;
samplerTrackInRadius = 4;
samplerTrackMaxPosNum = 100000;
samplerTrackMaxNegNum = 65;
featureSetNumFeatures = 250;
}
TrackerMIL::TrackerMIL()
{
// nothing
}
TrackerMIL::~TrackerMIL()
{
// nothing
}
Ptr<TrackerMIL> TrackerMIL::create(const TrackerMIL::Params& parameters)
{
return makePtr<tracking::impl::TrackerMILImpl>(parameters);
}
} // namespace cv