Files
opencv/modules/video/src/tracking/detail/tracking_online_mil.cpp
T

357 lines
9.1 KiB
C++

// 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 / std::pow(_sig0, 0.5f)));
_log_n1 = std::log(float(1.0f / std::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 / std::pow(_sig0, 0.5f)));
_log_n1 = std::log(float(1.0f / std::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