code cleaning of cascade classifier
This commit is contained in:
parent
33c44fcd7a
commit
d8415ed44e
@ -64,7 +64,7 @@ extern "C" {
|
||||
|
||||
typedef struct CvHaarFeature
|
||||
{
|
||||
int tilted;
|
||||
int tilted;
|
||||
struct
|
||||
{
|
||||
CvRect r;
|
||||
@ -328,16 +328,16 @@ public:
|
||||
CV_WRAP bool load(const string& filename);
|
||||
bool read(const FileNode& node);
|
||||
CV_WRAP void detectMultiScale( const Mat& image,
|
||||
CV_OUT vector<Rect>& objects,
|
||||
double scaleFactor=1.1,
|
||||
int minNeighbors=3, int flags=0,
|
||||
Size minSize=Size(),
|
||||
Size maxSize=Size());
|
||||
CV_OUT vector<Rect>& objects,
|
||||
double scaleFactor=1.1,
|
||||
int minNeighbors=3, int flags=0,
|
||||
Size minSize=Size(),
|
||||
Size maxSize=Size());
|
||||
|
||||
bool setImage( Ptr<FeatureEvaluator>&, const Mat& );
|
||||
int runAt( Ptr<FeatureEvaluator>&, Point );
|
||||
|
||||
bool is_stump_based;
|
||||
bool isStumpBased;
|
||||
|
||||
int stageType;
|
||||
int featureType;
|
||||
|
@ -717,26 +717,30 @@ inline int predictCategorical( CascadeClassifier& cascade, Ptr<FeatureEvaluator>
|
||||
template<class FEval>
|
||||
inline int predictOrderedStump( CascadeClassifier& cascade, Ptr<FeatureEvaluator> &_feval )
|
||||
{
|
||||
int si, nstages = (int)cascade.stages.size();
|
||||
int nodeOfs = 0, leafOfs = 0;
|
||||
FEval& feval = (FEval&)*_feval;
|
||||
float* cascadeLeaves = &cascade.leaves[0];
|
||||
CascadeClassifier::DTreeNode* cascadeNodes = &cascade.nodes[0];
|
||||
CascadeClassifier::Stage* cascadeStages = &cascade.stages[0];
|
||||
for( si = 0; si < nstages; si++ )
|
||||
|
||||
int nstages = (int)cascade.stages.size();
|
||||
for( int stageIdx = 0; stageIdx < nstages; stageIdx++ )
|
||||
{
|
||||
CascadeClassifier::Stage& stage = cascadeStages[si];
|
||||
int wi, ntrees = stage.ntrees;
|
||||
double sum = 0;
|
||||
for( wi = 0; wi < ntrees; wi++, nodeOfs++, leafOfs+= 2 )
|
||||
CascadeClassifier::Stage& stage = cascadeStages[stageIdx];
|
||||
double sum = 0.0;
|
||||
|
||||
int ntrees = stage.ntrees;
|
||||
for( int i = 0; i < ntrees; i++, nodeOfs++, leafOfs+= 2 )
|
||||
{
|
||||
CascadeClassifier::DTreeNode& node = cascadeNodes[nodeOfs];
|
||||
double val = feval(node.featureIdx);
|
||||
sum += cascadeLeaves[ val < node.threshold ? leafOfs : leafOfs+1 ];
|
||||
double value = feval(node.featureIdx);
|
||||
sum += cascadeLeaves[ value < node.threshold ? leafOfs : leafOfs + 1 ];
|
||||
}
|
||||
|
||||
if( sum < stage.threshold )
|
||||
return -si;
|
||||
return -stageIdx;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -773,7 +777,7 @@ inline int predictCategoricalStump( CascadeClassifier& cascade, Ptr<FeatureEvalu
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CascadeClassifier::runAt( Ptr<FeatureEvaluator> &_feval, Point pt )
|
||||
int CascadeClassifier::runAt( Ptr<FeatureEvaluator>& featureEvaluator, Point pt )
|
||||
{
|
||||
CV_Assert( oldCascade.empty() );
|
||||
/*if( !oldCascade.empty() )
|
||||
@ -781,17 +785,17 @@ int CascadeClassifier::runAt( Ptr<FeatureEvaluator> &_feval, Point pt )
|
||||
|
||||
assert(featureType == FeatureEvaluator::HAAR ||
|
||||
featureType == FeatureEvaluator::LBP);
|
||||
return !_feval->setWindow(pt) ? -1 :
|
||||
is_stump_based ? ( featureType == FeatureEvaluator::HAAR ?
|
||||
predictOrderedStump<HaarEvaluator>( *this, _feval ) :
|
||||
predictCategoricalStump<LBPEvaluator>( *this, _feval ) ) :
|
||||
|
||||
return !featureEvaluator->setWindow(pt) ? -1 :
|
||||
isStumpBased ? ( featureType == FeatureEvaluator::HAAR ?
|
||||
predictOrderedStump<HaarEvaluator>( *this, featureEvaluator ) :
|
||||
predictCategoricalStump<LBPEvaluator>( *this, featureEvaluator ) ) :
|
||||
( featureType == FeatureEvaluator::HAAR ?
|
||||
predictOrdered<HaarEvaluator>( *this, _feval ) :
|
||||
predictCategorical<LBPEvaluator>( *this, _feval ) );
|
||||
predictOrdered<HaarEvaluator>( *this, featureEvaluator ) :
|
||||
predictCategorical<LBPEvaluator>( *this, featureEvaluator ) );
|
||||
}
|
||||
|
||||
|
||||
bool CascadeClassifier::setImage( Ptr<FeatureEvaluator> &_feval, const Mat& image )
|
||||
bool CascadeClassifier::setImage( Ptr<FeatureEvaluator>& featureEvaluator, const Mat& image )
|
||||
{
|
||||
/*if( !oldCascade.empty() )
|
||||
{
|
||||
@ -803,7 +807,7 @@ bool CascadeClassifier::setImage( Ptr<FeatureEvaluator> &_feval, const Mat& imag
|
||||
cvSetImagesForHaarClassifierCascade( oldCascade, &_sum, &_sqsum, &_tilted, 1. );
|
||||
return true;
|
||||
}*/
|
||||
return empty() ? false : _feval->setImage(image, origWinSize );
|
||||
return empty() ? false : featureEvaluator->setImage(image, origWinSize);
|
||||
}
|
||||
|
||||
|
||||
@ -811,37 +815,40 @@ struct CascadeClassifierInvoker
|
||||
{
|
||||
CascadeClassifierInvoker( CascadeClassifier& _cc, Size _sz1, int _stripSize, int _yStep, double _factor, ConcurrentRectVector& _vec )
|
||||
{
|
||||
cc = &_cc;
|
||||
sz1 = _sz1;
|
||||
classifier = &_cc;
|
||||
processingAreaSize = _sz1;
|
||||
stripSize = _stripSize;
|
||||
yStep = _yStep;
|
||||
factor = _factor;
|
||||
vec = &_vec;
|
||||
scalingFactor = _factor;
|
||||
rectangles = &_vec;
|
||||
}
|
||||
|
||||
void operator()(const BlockedRange& range) const
|
||||
{
|
||||
Ptr<FeatureEvaluator> feval = cc->feval->clone();
|
||||
int y1 = range.begin()*stripSize, y2 = min(range.end()*stripSize, sz1.height);
|
||||
Size winSize(cvRound(cc->origWinSize.width*factor), cvRound(cc->origWinSize.height*factor));
|
||||
Ptr<FeatureEvaluator> evaluator = classifier->feval->clone();
|
||||
Size winSize(cvRound(classifier->origWinSize.width * scalingFactor), cvRound(classifier->origWinSize.height * scalingFactor));
|
||||
|
||||
int y1 = range.begin() * stripSize;
|
||||
int y2 = min(range.end() * stripSize, processingAreaSize.height);
|
||||
for( int y = y1; y < y2; y += yStep )
|
||||
for( int x = 0; x < sz1.width; x += yStep )
|
||||
{
|
||||
for( int x = 0; x < processingAreaSize.width; x += yStep )
|
||||
{
|
||||
int r = cc->runAt(feval, Point(x, y));
|
||||
if( r > 0 )
|
||||
vec->push_back(Rect(cvRound(x*factor), cvRound(y*factor),
|
||||
winSize.width, winSize.height));
|
||||
if( r == 0 )
|
||||
int result = classifier->runAt(evaluator, Point(x, y));
|
||||
if( result > 0 )
|
||||
rectangles->push_back(Rect(cvRound(x*scalingFactor), cvRound(y*scalingFactor),
|
||||
winSize.width, winSize.height));
|
||||
if( result == 0 )
|
||||
x += yStep;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CascadeClassifier* cc;
|
||||
Size sz1;
|
||||
CascadeClassifier* classifier;
|
||||
ConcurrentRectVector* rectangles;
|
||||
Size processingAreaSize;
|
||||
int stripSize, yStep;
|
||||
double factor;
|
||||
ConcurrentRectVector* vec;
|
||||
double scalingFactor;
|
||||
};
|
||||
|
||||
|
||||
@ -849,7 +856,7 @@ struct getRect { Rect operator ()(const CvAvgComp& e) const { return e.rect; } }
|
||||
|
||||
void CascadeClassifier::detectMultiScale( const Mat& image, vector<Rect>& objects,
|
||||
double scaleFactor, int minNeighbors,
|
||||
int flags, Size minSize, Size maxSize )
|
||||
int flags, Size minObjectSize, Size maxObjectSize )
|
||||
{
|
||||
const double GROUP_EPS = 0.2;
|
||||
|
||||
@ -863,7 +870,7 @@ void CascadeClassifier::detectMultiScale( const Mat& image, vector<Rect>& object
|
||||
MemStorage storage(cvCreateMemStorage(0));
|
||||
CvMat _image = image;
|
||||
CvSeq* _objects = cvHaarDetectObjects( &_image, oldCascade, storage, scaleFactor,
|
||||
minNeighbors, flags, minSize );
|
||||
minNeighbors, flags, minObjectSize );
|
||||
vector<CvAvgComp> vecAvgComp;
|
||||
Seq<CvAvgComp>(_objects).copyTo(vecAvgComp);
|
||||
objects.resize(vecAvgComp.size());
|
||||
@ -871,57 +878,60 @@ void CascadeClassifier::detectMultiScale( const Mat& image, vector<Rect>& object
|
||||
return;
|
||||
}
|
||||
|
||||
if( maxSize.height == 0 || maxSize.width == 0 )
|
||||
maxSize = image.size();
|
||||
|
||||
objects.clear();
|
||||
|
||||
Mat img = image, imgbuf(image.rows+1, image.cols+1, CV_8U);
|
||||
if( maxObjectSize.height == 0 || maxObjectSize.width == 0 )
|
||||
maxObjectSize = image.size();
|
||||
|
||||
if( img.channels() > 1 )
|
||||
Mat grayImage = image;
|
||||
if( grayImage.channels() > 1 )
|
||||
{
|
||||
Mat temp;
|
||||
cvtColor(img, temp, CV_BGR2GRAY);
|
||||
img = temp;
|
||||
cvtColor(grayImage, temp, CV_BGR2GRAY);
|
||||
grayImage = temp;
|
||||
}
|
||||
|
||||
ConcurrentRectVector allCandidates;
|
||||
Mat imageBuffer(image.rows + 1, image.cols + 1, CV_8U);
|
||||
ConcurrentRectVector candidates;
|
||||
|
||||
for( double factor = 1; ; factor *= scaleFactor )
|
||||
{
|
||||
int stripCount, stripSize;
|
||||
Size winSize( cvRound(origWinSize.width*factor), cvRound(origWinSize.height*factor) );
|
||||
Size sz( cvRound( img.cols/factor ), cvRound( img.rows/factor ) );
|
||||
Size sz1( sz.width - origWinSize.width, sz.height - origWinSize.height );
|
||||
|
||||
if( sz1.width <= 0 || sz1.height <= 0 )
|
||||
Size windowSize( cvRound(origWinSize.width*factor), cvRound(origWinSize.height*factor) );
|
||||
Size scaledImageSize( cvRound( grayImage.cols/factor ), cvRound( grayImage.rows/factor ) );
|
||||
Size processingAreaSize( scaledImageSize.width - origWinSize.width, scaledImageSize.height - origWinSize.height );
|
||||
|
||||
if( processingAreaSize.width <= 0 || processingAreaSize.height <= 0 )
|
||||
break;
|
||||
if( winSize.width > maxSize.width || winSize.height > maxSize.height )
|
||||
if( windowSize.width > maxObjectSize.width || windowSize.height > maxObjectSize.height )
|
||||
break;
|
||||
if( winSize.width < minSize.width || winSize.height < minSize.height )
|
||||
if( windowSize.width < minObjectSize.width || windowSize.height < minObjectSize.height )
|
||||
continue;
|
||||
|
||||
int yStep = factor > 2. ? 1 : 2;
|
||||
|
||||
#ifdef HAVE_TBB
|
||||
const int PTS_PER_THREAD = 1000;
|
||||
stripCount = ((sz1.width/yStep)*(sz1.height + yStep-1)/yStep + PTS_PER_THREAD/2)/PTS_PER_THREAD;
|
||||
stripCount = ((processingAreaSize.width/yStep)*(processingAreaSize.height + yStep-1)/yStep + PTS_PER_THREAD/2)/PTS_PER_THREAD;
|
||||
stripCount = std::min(std::max(stripCount, 1), 100);
|
||||
stripSize = (((sz1.height + stripCount - 1)/stripCount + yStep-1)/yStep)*yStep;
|
||||
stripSize = (((processingAreaSize.height + stripCount - 1)/stripCount + yStep-1)/yStep)*yStep;
|
||||
#else
|
||||
stripCount = 1;
|
||||
stripSize = sz1.height;
|
||||
stripSize = processingAreaSize.height;
|
||||
#endif
|
||||
|
||||
Mat img1( sz, CV_8U, imgbuf.data );
|
||||
resize( img, img1, sz, 0, 0, CV_INTER_LINEAR );
|
||||
if( !feval->setImage( img1, origWinSize ) )
|
||||
Mat scaledImage( scaledImageSize, CV_8U, imageBuffer.data );
|
||||
resize( grayImage, scaledImage, scaledImageSize, 0, 0, CV_INTER_LINEAR );
|
||||
if( !feval->setImage( scaledImage, origWinSize ) )
|
||||
break;
|
||||
|
||||
parallel_for(BlockedRange(0, stripCount), CascadeClassifierInvoker(*this, sz1, stripSize, yStep, factor, allCandidates));
|
||||
parallel_for(BlockedRange(0, stripCount), CascadeClassifierInvoker(*this, processingAreaSize, stripSize, yStep, factor, candidates));
|
||||
}
|
||||
|
||||
objects.resize(allCandidates.size());
|
||||
std::copy(allCandidates.begin(), allCandidates.end(), objects.begin());
|
||||
objects.resize(candidates.size());
|
||||
std::copy(candidates.begin(), candidates.end(), objects.begin());
|
||||
|
||||
groupRectangles( objects, minNeighbors, GROUP_EPS );
|
||||
}
|
||||
|
||||
@ -947,7 +957,7 @@ bool CascadeClassifier::read(const FileNode& root)
|
||||
origWinSize.height = (int)root[CC_HEIGHT];
|
||||
CV_Assert( origWinSize.height > 0 && origWinSize.width > 0 );
|
||||
|
||||
is_stump_based = (int)(root[CC_STAGE_PARAMS][CC_MAX_DEPTH]) == 1 ? true : false;
|
||||
isStumpBased = (int)(root[CC_STAGE_PARAMS][CC_MAX_DEPTH]) == 1 ? true : false;
|
||||
|
||||
// load feature params
|
||||
FileNode fn = root[CC_FEATURE_PARAMS];
|
||||
|
@ -112,7 +112,7 @@ CvHidHaarStageClassifier;
|
||||
struct CvHidHaarClassifierCascade
|
||||
{
|
||||
int count;
|
||||
int is_stump_based;
|
||||
int isStumpBased;
|
||||
int has_tilted_features;
|
||||
int is_tree;
|
||||
double inv_window_area;
|
||||
@ -272,7 +272,7 @@ icvCreateHidHaarClassifierCascade( CvHaarClassifierCascade* cascade )
|
||||
haar_classifier_ptr = (CvHidHaarClassifier*)(out->stage_classifier + cascade->count);
|
||||
haar_node_ptr = (CvHidHaarTreeNode*)(haar_classifier_ptr + total_classifiers);
|
||||
|
||||
out->is_stump_based = 1;
|
||||
out->isStumpBased = 1;
|
||||
out->has_tilted_features = has_tilted_features;
|
||||
out->is_tree = 0;
|
||||
|
||||
@ -329,12 +329,12 @@ icvCreateHidHaarClassifierCascade( CvHaarClassifierCascade* cascade )
|
||||
haar_node_ptr =
|
||||
(CvHidHaarTreeNode*)cvAlignPtr(alpha_ptr+node_count+1, sizeof(void*));
|
||||
|
||||
out->is_stump_based &= node_count == 1;
|
||||
out->isStumpBased &= node_count == 1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_IPP
|
||||
int can_use_ipp = !out->has_tilted_features && !out->is_tree && out->is_stump_based;
|
||||
int can_use_ipp = !out->has_tilted_features && !out->is_tree && out->isStumpBased;
|
||||
|
||||
if( can_use_ipp )
|
||||
{
|
||||
@ -719,7 +719,7 @@ cvRunHaarClassifierCascade( const CvHaarClassifierCascade* _cascade,
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( cascade->is_stump_based )
|
||||
else if( cascade->isStumpBased )
|
||||
{
|
||||
for( i = start_stage; i < cascade->count; i++ )
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user