1
0
mirror of https://github.com/opencv/opencv_contrib.git synced 2025-10-20 21:40:49 +08:00
Files
opencv_contrib/modules/tracking/src/onlineBoosting.cpp
Ilya Lavrenov 89cd87107f fixed warnings
2014-07-04 13:09:18 +04:00

736 lines
21 KiB
C++

/*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"
#include "opencv2/tracking/onlineBoosting.hpp"
namespace cv
{
StrongClassifierDirectSelection::StrongClassifierDirectSelection( int numBaseClf, int numWeakClf, Size patchSz, const Rect& sampleROI,
bool useFeatureEx, int iterationInit )
{
//StrongClassifier
numBaseClassifier = numBaseClf;
numAllWeakClassifier = numWeakClf + iterationInit;
iterInit = iterationInit;
numWeakClassifier = numWeakClf;
alpha.assign( numBaseClf, 0 );
patchSize = patchSz;
useFeatureExchange = useFeatureEx;
m_errorMask.resize( numAllWeakClassifier );
m_errors.resize( numAllWeakClassifier );
m_sumErrors.resize( numAllWeakClassifier );
ROI = sampleROI;
detector = new Detector( this );
}
void StrongClassifierDirectSelection::initBaseClassifier()
{
baseClassifier = new BaseClassifier*[numBaseClassifier];
baseClassifier[0] = new BaseClassifier( numWeakClassifier, iterInit );
for ( int curBaseClassifier = 1; curBaseClassifier < numBaseClassifier; curBaseClassifier++ )
baseClassifier[curBaseClassifier] = new BaseClassifier( numWeakClassifier, iterInit, baseClassifier[0]->getReferenceWeakClassifier() );
}
StrongClassifierDirectSelection::~StrongClassifierDirectSelection()
{
for ( int curBaseClassifier = 0; curBaseClassifier < numBaseClassifier; curBaseClassifier++ )
delete baseClassifier[curBaseClassifier];
delete[] baseClassifier;
alpha.clear();
delete detector;
}
Size StrongClassifierDirectSelection::getPatchSize() const
{
return patchSize;
}
Rect StrongClassifierDirectSelection::getROI() const
{
return ROI;
}
float StrongClassifierDirectSelection::classifySmooth( const std::vector<Mat>& images, const Rect& sampleROI, int& idx )
{
ROI = sampleROI;
idx = 0;
float confidence = 0;
//detector->classify (image, patches);
detector->classifySmooth( images );
//move to best detection
if( detector->getNumDetections() <= 0 )
{
confidence = 0;
return confidence;
}
idx = detector->getPatchIdxOfBestDetection();
confidence = detector->getConfidenceOfBestDetection();
return confidence;
}
bool StrongClassifierDirectSelection::getUseFeatureExchange() const
{
return useFeatureExchange;
}
int StrongClassifierDirectSelection::getReplacedClassifier() const
{
return replacedClassifier;
}
int StrongClassifierDirectSelection::getSwappedClassifier() const
{
return swappedClassifier;
}
bool StrongClassifierDirectSelection::update( const Mat& image, int target, float importance )
{
m_errorMask.assign( (size_t)numAllWeakClassifier, false );
m_errors.assign( (size_t)numAllWeakClassifier, 0.0f );
m_sumErrors.assign( (size_t)numAllWeakClassifier, 0.0f );
baseClassifier[0]->trainClassifier( image, target, importance, m_errorMask );
for ( int curBaseClassifier = 0; curBaseClassifier < numBaseClassifier; curBaseClassifier++ )
{
int selectedClassifier = baseClassifier[curBaseClassifier]->selectBestClassifier( m_errorMask, importance, m_errors );
if( m_errors[selectedClassifier] >= 0.5 )
alpha[curBaseClassifier] = 0;
else
alpha[curBaseClassifier] = logf( ( 1.0f - m_errors[selectedClassifier] ) / m_errors[selectedClassifier] );
if( m_errorMask[selectedClassifier] )
importance *= (float) sqrt( ( 1.0f - m_errors[selectedClassifier] ) / m_errors[selectedClassifier] );
else
importance *= (float) sqrt( m_errors[selectedClassifier] / ( 1.0f - m_errors[selectedClassifier] ) );
//weight limitation
//if (importance > 100) importance = 100;
//sum up errors
for ( int curWeakClassifier = 0; curWeakClassifier < numAllWeakClassifier; curWeakClassifier++ )
{
if( m_errors[curWeakClassifier] != FLT_MAX && m_sumErrors[curWeakClassifier] >= 0 )
m_sumErrors[curWeakClassifier] += m_errors[curWeakClassifier];
}
//mark feature as used
m_sumErrors[selectedClassifier] = -1;
m_errors[selectedClassifier] = FLT_MAX;
}
if( useFeatureExchange )
{
replacedClassifier = baseClassifier[0]->computeReplaceWeakestClassifier( m_sumErrors );
swappedClassifier = baseClassifier[0]->getIdxOfNewWeakClassifier();
}
return true;
}
void StrongClassifierDirectSelection::replaceWeakClassifier( int idx )
{
if( useFeatureExchange && idx >= 0 )
{
baseClassifier[0]->replaceWeakClassifier( idx );
for ( int curBaseClassifier = 1; curBaseClassifier < numBaseClassifier; curBaseClassifier++ )
baseClassifier[curBaseClassifier]->replaceClassifierStatistic( baseClassifier[0]->getIdxOfNewWeakClassifier(), idx );
}
}
std::vector<int> StrongClassifierDirectSelection::getSelectedWeakClassifier()
{
std::vector<int> selected;
int curBaseClassifier = 0;
for ( curBaseClassifier = 0; curBaseClassifier < numBaseClassifier; curBaseClassifier++ )
{
selected.push_back( baseClassifier[curBaseClassifier]->getSelectedClassifier() );
}
return selected;
}
float StrongClassifierDirectSelection::eval( const Mat& response )
{
float value = 0.0f;
int curBaseClassifier = 0;
for ( curBaseClassifier = 0; curBaseClassifier < numBaseClassifier; curBaseClassifier++ )
value += baseClassifier[curBaseClassifier]->eval( response ) * alpha[curBaseClassifier];
return value;
}
int StrongClassifierDirectSelection::getNumBaseClassifier()
{
return numBaseClassifier;
}
BaseClassifier::BaseClassifier( int numWeakClassifier, int iterationInit )
{
this->m_numWeakClassifier = numWeakClassifier;
this->m_iterationInit = iterationInit;
weakClassifier = new WeakClassifierHaarFeature*[numWeakClassifier + iterationInit];
m_idxOfNewWeakClassifier = numWeakClassifier;
generateRandomClassifier();
m_referenceWeakClassifier = false;
m_selectedClassifier = 0;
m_wCorrect.assign( numWeakClassifier + iterationInit, 0 );
m_wWrong.assign( numWeakClassifier + iterationInit, 0 );
for ( int curWeakClassifier = 0; curWeakClassifier < numWeakClassifier + iterationInit; curWeakClassifier++ )
m_wWrong[curWeakClassifier] = m_wCorrect[curWeakClassifier] = 1;
}
BaseClassifier::BaseClassifier( int numWeakClassifier, int iterationInit, WeakClassifierHaarFeature** weakCls )
{
m_numWeakClassifier = numWeakClassifier;
m_iterationInit = iterationInit;
weakClassifier = weakCls;
m_referenceWeakClassifier = true;
m_selectedClassifier = 0;
m_idxOfNewWeakClassifier = numWeakClassifier;
m_wCorrect.assign( numWeakClassifier + iterationInit, 0 );
m_wWrong.assign( numWeakClassifier + iterationInit, 0 );
for ( int curWeakClassifier = 0; curWeakClassifier < numWeakClassifier + iterationInit; curWeakClassifier++ )
m_wWrong[curWeakClassifier] = m_wCorrect[curWeakClassifier] = 1;
}
BaseClassifier::~BaseClassifier()
{
if( !m_referenceWeakClassifier )
{
for ( int curWeakClassifier = 0; curWeakClassifier < m_numWeakClassifier + m_iterationInit; curWeakClassifier++ )
delete weakClassifier[curWeakClassifier];
delete[] weakClassifier;
}
m_wCorrect.clear();
m_wWrong.clear();
}
void BaseClassifier::generateRandomClassifier()
{
for ( int curWeakClassifier = 0; curWeakClassifier < m_numWeakClassifier + m_iterationInit; curWeakClassifier++ )
{
weakClassifier[curWeakClassifier] = new WeakClassifierHaarFeature();
}
}
int BaseClassifier::eval( const Mat& image )
{
return weakClassifier[m_selectedClassifier]->eval( image.at<float>( m_selectedClassifier ) );
}
int BaseClassifier::getSelectedClassifier() const
{
return m_selectedClassifier;
}
void BaseClassifier::trainClassifier( const Mat& image, int target, float importance, std::vector<bool>& errorMask )
{
//get poisson value
double A = 1;
int K = 0;
int K_max = 10;
for ( ; ; )
{
double U_k = (double) rand() / RAND_MAX;
A *= U_k;
if( K > K_max || A < exp( -importance ) )
break;
K++;
}
for ( int curK = 0; curK <= K; curK++ )
{
for ( int curWeakClassifier = 0; curWeakClassifier < m_numWeakClassifier + m_iterationInit; curWeakClassifier++ )
{
errorMask[curWeakClassifier] = weakClassifier[curWeakClassifier]->update( image.at<float>( curWeakClassifier ), target );
}
}
}
float BaseClassifier::getError( int curWeakClassifier )
{
if( curWeakClassifier == -1 )
curWeakClassifier = m_selectedClassifier;
return m_wWrong[curWeakClassifier] / ( m_wWrong[curWeakClassifier] + m_wCorrect[curWeakClassifier] );
}
int BaseClassifier::selectBestClassifier( std::vector<bool>& errorMask, float importance, std::vector<float> & errors )
{
float minError = FLT_MAX;
int tmp_selectedClassifier = m_selectedClassifier;
for ( int curWeakClassifier = 0; curWeakClassifier < m_numWeakClassifier + m_iterationInit; curWeakClassifier++ )
{
if( errorMask[curWeakClassifier] )
{
m_wWrong[curWeakClassifier] += importance;
}
else
{
m_wCorrect[curWeakClassifier] += importance;
}
if( errors[curWeakClassifier] == FLT_MAX )
continue;
errors[curWeakClassifier] = m_wWrong[curWeakClassifier] / ( m_wWrong[curWeakClassifier] + m_wCorrect[curWeakClassifier] );
/*if(errors[curWeakClassifier] < 0.001 || !(errors[curWeakClassifier]>0.0))
{
errors[curWeakClassifier] = 0.001;
}
if(errors[curWeakClassifier] >= 1.0)
errors[curWeakClassifier] = 0.999;
assert (errors[curWeakClassifier] > 0.0);
assert (errors[curWeakClassifier] < 1.0);*/
if( curWeakClassifier < m_numWeakClassifier )
{
if( errors[curWeakClassifier] < minError )
{
minError = errors[curWeakClassifier];
tmp_selectedClassifier = curWeakClassifier;
}
}
}
m_selectedClassifier = tmp_selectedClassifier;
return m_selectedClassifier;
}
void BaseClassifier::getErrors( float* errors )
{
for ( int curWeakClassifier = 0; curWeakClassifier < m_numWeakClassifier + m_iterationInit; curWeakClassifier++ )
{
if( errors[curWeakClassifier] == FLT_MAX )
continue;
errors[curWeakClassifier] = m_wWrong[curWeakClassifier] / ( m_wWrong[curWeakClassifier] + m_wCorrect[curWeakClassifier] );
CV_Assert( errors[curWeakClassifier] > 0 );
}
}
void BaseClassifier::replaceWeakClassifier( int index )
{
delete weakClassifier[index];
weakClassifier[index] = weakClassifier[m_idxOfNewWeakClassifier];
m_wWrong[index] = m_wWrong[m_idxOfNewWeakClassifier];
m_wWrong[m_idxOfNewWeakClassifier] = 1;
m_wCorrect[index] = m_wCorrect[m_idxOfNewWeakClassifier];
m_wCorrect[m_idxOfNewWeakClassifier] = 1;
weakClassifier[m_idxOfNewWeakClassifier] = new WeakClassifierHaarFeature();
}
int BaseClassifier::computeReplaceWeakestClassifier( const std::vector<float> & errors )
{
float maxError = 0.0f;
int index = -1;
//search the classifier with the largest error
for ( int curWeakClassifier = m_numWeakClassifier - 1; curWeakClassifier >= 0; curWeakClassifier-- )
{
if( errors[curWeakClassifier] > maxError )
{
maxError = errors[curWeakClassifier];
index = curWeakClassifier;
}
}
CV_Assert( index > -1 );
CV_Assert( index != m_selectedClassifier );
//replace
m_idxOfNewWeakClassifier++;
if( m_idxOfNewWeakClassifier == m_numWeakClassifier + m_iterationInit )
m_idxOfNewWeakClassifier = m_numWeakClassifier;
if( maxError > errors[m_idxOfNewWeakClassifier] )
{
return index;
}
else
return -1;
}
void BaseClassifier::replaceClassifierStatistic( int sourceIndex, int targetIndex )
{
CV_Assert( targetIndex >= 0 );
CV_Assert( targetIndex != m_selectedClassifier );
CV_Assert( targetIndex < m_numWeakClassifier );
//replace
m_wWrong[targetIndex] = m_wWrong[sourceIndex];
m_wWrong[sourceIndex] = 1.0f;
m_wCorrect[targetIndex] = m_wCorrect[sourceIndex];
m_wCorrect[sourceIndex] = 1.0f;
}
EstimatedGaussDistribution::EstimatedGaussDistribution()
{
m_mean = 0;
m_sigma = 1;
this->m_P_mean = 1000;
this->m_R_mean = 0.01f;
this->m_P_sigma = 1000;
this->m_R_sigma = 0.01f;
}
EstimatedGaussDistribution::EstimatedGaussDistribution( float P_mean, float R_mean, float P_sigma, float R_sigma )
{
m_mean = 0;
m_sigma = 1;
this->m_P_mean = P_mean;
this->m_R_mean = R_mean;
this->m_P_sigma = P_sigma;
this->m_R_sigma = R_sigma;
}
EstimatedGaussDistribution::~EstimatedGaussDistribution()
{
}
void EstimatedGaussDistribution::update( float value )
{
//update distribution (mean and sigma) using a kalman filter for each
float K;
float minFactor = 0.001f;
//mean
K = m_P_mean / ( m_P_mean + m_R_mean );
if( K < minFactor )
K = minFactor;
m_mean = K * value + ( 1.0f - K ) * m_mean;
m_P_mean = m_P_mean * m_R_mean / ( m_P_mean + m_R_mean );
K = m_P_sigma / ( m_P_sigma + m_R_sigma );
if( K < minFactor )
K = minFactor;
float tmp_sigma = K * ( m_mean - value ) * ( m_mean - value ) + ( 1.0f - K ) * m_sigma * m_sigma;
m_P_sigma = m_P_sigma * m_R_mean / ( m_P_sigma + m_R_sigma );
m_sigma = static_cast<float>( sqrt( tmp_sigma ) );
if( m_sigma <= 1.0f )
m_sigma = 1.0f;
}
void EstimatedGaussDistribution::setValues( float mean, float sigma )
{
this->m_mean = mean;
this->m_sigma = sigma;
}
float EstimatedGaussDistribution::getMean()
{
return m_mean;
}
float EstimatedGaussDistribution::getSigma()
{
return m_sigma;
}
WeakClassifierHaarFeature::WeakClassifierHaarFeature()
{
sigma = 1;
mean = 0;
EstimatedGaussDistribution* m_posSamples = new EstimatedGaussDistribution();
EstimatedGaussDistribution* m_negSamples = new EstimatedGaussDistribution();
generateRandomClassifier( m_posSamples, m_negSamples );
getInitialDistribution( (EstimatedGaussDistribution*) m_classifier->getDistribution( -1 ) );
getInitialDistribution( (EstimatedGaussDistribution*) m_classifier->getDistribution( 1 ) );
}
WeakClassifierHaarFeature::~WeakClassifierHaarFeature()
{
delete m_classifier;
}
void WeakClassifierHaarFeature::getInitialDistribution( EstimatedGaussDistribution* distribution )
{
distribution->setValues( mean, sigma );
}
void WeakClassifierHaarFeature::generateRandomClassifier( EstimatedGaussDistribution* m_posSamples, EstimatedGaussDistribution* m_negSamples )
{
m_classifier = new ClassifierThreshold( m_posSamples, m_negSamples );
}
bool WeakClassifierHaarFeature::update( float value, int target )
{
m_classifier->update( value, target );
return ( m_classifier->eval( value ) != target );
}
int WeakClassifierHaarFeature::eval( float value )
{
return m_classifier->eval( value );
}
Detector::Detector( StrongClassifierDirectSelection* classifier ) :
m_sizeDetections( 0 )
{
this->m_classifier = classifier;
m_sizeConfidences = 0;
m_maxConfidence = -FLT_MAX;
m_numDetections = 0;
m_idxBestDetection = -1;
}
Detector::~Detector()
{
}
void Detector::prepareConfidencesMemory( int numPatches )
{
if( numPatches <= m_sizeConfidences )
return;
m_sizeConfidences = numPatches;
m_confidences.resize( numPatches );
}
void Detector::prepareDetectionsMemory( int numDetections )
{
if( numDetections <= m_sizeDetections )
return;
m_sizeDetections = numDetections;
m_idxDetections.resize( numDetections );
}
void Detector::classifySmooth( const std::vector<Mat>& images, float minMargin )
{
int numPatches = static_cast<int>(images.size());
prepareConfidencesMemory( numPatches );
m_numDetections = 0;
m_idxBestDetection = -1;
m_maxConfidence = -FLT_MAX;
//compute grid
//TODO 0.99 overlap from params
Size patchSz = m_classifier->getPatchSize();
int stepCol = (int) floor( ( 1.0f - 0.99f ) * (float) patchSz.width + 0.5f );
int stepRow = (int) floor( ( 1.0f - 0.99f ) * (float) patchSz.height + 0.5f );
if( stepCol <= 0 )
stepCol = 1;
if( stepRow <= 0 )
stepRow = 1;
Size patchGrid;
Rect ROI = m_classifier->getROI();
patchGrid.height = ( (int) ( (float) ( ROI.height - patchSz.height ) / stepRow ) + 1 );
patchGrid.width = ( (int) ( (float) ( ROI.width - patchSz.width ) / stepCol ) + 1 );
if( ( patchGrid.width != m_confMatrix.cols ) || ( patchGrid.height != m_confMatrix.rows ) )
{
m_confMatrix.create( patchGrid.height, patchGrid.width );
m_confMatrixSmooth.create( patchGrid.height, patchGrid.width );
m_confImageDisplay.create( patchGrid.height, patchGrid.width );
}
int curPatch = 0;
// Eval and filter
for ( int row = 0; row < patchGrid.height; row++ )
{
for ( int col = 0; col < patchGrid.width; col++ )
{
m_confidences[curPatch] = m_classifier->eval( images[curPatch] );
// fill matrix
m_confMatrix( row, col ) = m_confidences[curPatch];
curPatch++;
}
}
// Filter
//cv::GaussianBlur(m_confMatrix,m_confMatrixSmooth,cv::Size(3,3),0.8);
cv::GaussianBlur( m_confMatrix, m_confMatrixSmooth, cv::Size( 3, 3 ), 0 );
// Make display friendly
double min_val, max_val;
cv::minMaxLoc( m_confMatrixSmooth, &min_val, &max_val );
for ( int y = 0; y < m_confImageDisplay.rows; y++ )
{
unsigned char* pConfImg = m_confImageDisplay[y];
const float* pConfData = m_confMatrixSmooth[y];
for ( int x = 0; x < m_confImageDisplay.cols; x++, pConfImg++, pConfData++ )
{
*pConfImg = static_cast<unsigned char>( 255.0 * ( *pConfData - min_val ) / ( max_val - min_val ) );
}
}
// Get best detection
curPatch = 0;
for ( int row = 0; row < patchGrid.height; row++ )
{
for ( int col = 0; col < patchGrid.width; col++ )
{
// fill matrix
m_confidences[curPatch] = m_confMatrixSmooth( row, col );
if( m_confidences[curPatch] > m_maxConfidence )
{
m_maxConfidence = m_confidences[curPatch];
m_idxBestDetection = curPatch;
}
if( m_confidences[curPatch] > minMargin )
{
m_numDetections++;
}
curPatch++;
}
}
prepareDetectionsMemory( m_numDetections );
int curDetection = -1;
for ( int currentPatch = 0; currentPatch < numPatches; currentPatch++ )
{
if( m_confidences[currentPatch] > minMargin )
m_idxDetections[++curDetection] = currentPatch;
}
}
int Detector::getNumDetections()
{
return m_numDetections;
}
float Detector::getConfidence( int patchIdx )
{
return m_confidences[patchIdx];
}
float Detector::getConfidenceOfDetection( int detectionIdx )
{
return m_confidences[getPatchIdxOfDetection( detectionIdx )];
}
int Detector::getPatchIdxOfBestDetection()
{
return m_idxBestDetection;
}
int Detector::getPatchIdxOfDetection( int detectionIdx )
{
return m_idxDetections[detectionIdx];
}
ClassifierThreshold::ClassifierThreshold( EstimatedGaussDistribution* posSamples, EstimatedGaussDistribution* negSamples )
{
m_posSamples = posSamples;
m_negSamples = negSamples;
m_threshold = 0.0f;
m_parity = 0;
}
ClassifierThreshold::~ClassifierThreshold()
{
if( m_posSamples != NULL )
delete m_posSamples;
if( m_negSamples != NULL )
delete m_negSamples;
}
void*
ClassifierThreshold::getDistribution( int target )
{
if( target == 1 )
return m_posSamples;
else
return m_negSamples;
}
void ClassifierThreshold::update( float value, int target )
{
//update distribution
if( target == 1 )
m_posSamples->update( value );
else
m_negSamples->update( value );
//adapt threshold and parity
m_threshold = ( m_posSamples->getMean() + m_negSamples->getMean() ) / 2.0f;
m_parity = ( m_posSamples->getMean() > m_negSamples->getMean() ) ? 1 : -1;
}
int ClassifierThreshold::eval( float value )
{
return ( ( ( m_parity * ( value - m_threshold ) ) > 0 ) ? 1 : -1 );
}
} /* namespace cv */