Added to objdetect module: meanshift grouping (groupRectangles_meanshift(...) for input rectangles); new pedestrian detection model, trained on the Daimler base (getDaimlerPeopleDetector(...) ).

Some changes in the HOGDescriptor class interface(objdetect.hpp) (added useMeanShiftGrouping parameter to the detectMultiScale(...) function)
This commit is contained in:
Alexey Kazakov
2011-04-19 09:05:15 +00:00
parent 2057f2c452
commit e863c3d5f6
4 changed files with 924 additions and 25 deletions

View File

@@ -63,7 +63,7 @@ public:
};
static void groupRectangles(vector<Rect>& rectList, int groupThreshold, double eps, vector<int>* weights)
static void groupRectangles(vector<Rect>& rectList, int groupThreshold, double eps, vector<int>* weights, vector<double>* foundWeights)
{
if( groupThreshold <= 0 || rectList.empty() )
{
@@ -82,6 +82,7 @@ static void groupRectangles(vector<Rect>& rectList, int groupThreshold, double e
vector<Rect> rrects(nclasses);
vector<int> rweights(nclasses, 0);
vector<double> outWeights(nclasses, 0.0);
int i, j, nlabels = (int)labels.size();
for( i = 0; i < nlabels; i++ )
{
@@ -92,6 +93,14 @@ static void groupRectangles(vector<Rect>& rectList, int groupThreshold, double e
rrects[cls].height += rectList[i].height;
rweights[cls]++;
}
if ( foundWeights && !foundWeights->empty() )
{
for( i = 0; i < nlabels; i++ )
{
int cls = labels[i];
outWeights[cls] = outWeights[cls] + (*foundWeights)[i];
}
}
for( i = 0; i < nclasses; i++ )
{
@@ -106,11 +115,14 @@ static void groupRectangles(vector<Rect>& rectList, int groupThreshold, double e
rectList.clear();
if( weights )
weights->clear();
if( foundWeights )
foundWeights->clear();
for( i = 0; i < nclasses; i++ )
{
Rect r1 = rrects[i];
int n1 = rweights[i];
double w1 = outWeights[i];
if( n1 <= groupThreshold )
continue;
// filter out small face rectangles inside large rectangles
@@ -139,19 +151,76 @@ static void groupRectangles(vector<Rect>& rectList, int groupThreshold, double e
rectList.push_back(r1);
if( weights )
weights->push_back(n1);
if( foundWeights )
foundWeights->push_back(w1);
}
}
}
//new grouping function with using meanshift
static void groupRectangles_meanshift(vector<Rect>& rectList, double detectThreshold, vector<double>* foundWeights,
vector<double>& scales, Size winDetSize)
{
int detectionCount = rectList.size();
vector<Point3d> hits(detectionCount), resultHits;
vector<double> hitWeights(detectionCount), resultWeights;
Point2d hitCenter;
for (int i=0; i < detectionCount; i++)
{
hitWeights[i] = (*foundWeights)[i];
hitCenter = (rectList[i].tl() + rectList[i].br())*(0.5); //center of rectangles
hits[i] = Point3d(hitCenter.x, hitCenter.y, std::log(scales[i]));
}
rectList.clear();
if (foundWeights)
foundWeights->clear();
double logZ = std::log(1.3);
Point3d smothing(8, 16, logZ);
MeanshiftGrouping msGrouping(smothing, hits, hitWeights, 1e-5, 100);
msGrouping.getModes(resultHits, resultWeights, 1);
for (unsigned i=0; i < resultHits.size(); ++i)
{
double scale = exp(resultHits[i].z);
hitCenter.x = resultHits[i].x;
hitCenter.y = resultHits[i].y;
Size s( int(winDetSize.width * scale), int(winDetSize.height * scale) );
Rect resultRect( int(hitCenter.x-s.width/2), int(hitCenter.y-s.height/2),
int(s.width), int(s.height) );
if (resultWeights[i] > detectThreshold)
{
rectList.push_back(resultRect);
foundWeights->push_back(resultWeights[i]);
}
}
}
void groupRectangles(vector<Rect>& rectList, int groupThreshold, double eps)
{
groupRectangles(rectList, groupThreshold, eps, 0);
groupRectangles(rectList, groupThreshold, eps, 0, 0);
}
void groupRectangles(vector<Rect>& rectList, vector<int>& weights, int groupThreshold, double eps)
{
groupRectangles(rectList, groupThreshold, eps, &weights);
groupRectangles(rectList, groupThreshold, eps, &weights, 0);
}
void groupRectangles(vector<Rect>& rectList, vector<double>& foundWeights, int groupThreshold, double eps)
{
groupRectangles(rectList, groupThreshold, eps, 0, &foundWeights);
}
void groupRectangles_meanshift(vector<Rect>& rectList, vector<double>& foundWeights,
vector<double>& foundScales, double detectThreshold, Size winDetSize)
{
groupRectangles_meanshift(rectList, detectThreshold, &foundWeights, foundScales, winDetSize);
}
@@ -802,7 +871,8 @@ bool CascadeClassifier::setImage( Ptr<FeatureEvaluator>& featureEvaluator, const
struct CascadeClassifierInvoker
{
CascadeClassifierInvoker( CascadeClassifier& _cc, Size _sz1, int _stripSize, int _yStep, double _factor, ConcurrentRectVector& _vec )
CascadeClassifierInvoker( CascadeClassifier& _cc, Size _sz1, int _stripSize, int _yStep, double _factor,
ConcurrentRectVector& _vec, vector<int>& _levels, bool outputLevels = false )
{
classifier = &_cc;
processingRectSize = _sz1;
@@ -810,6 +880,7 @@ struct CascadeClassifierInvoker
yStep = _yStep;
scalingFactor = _factor;
rectangles = &_vec;
rejectLevels = outputLevels ? &_levels : 0;
}
void operator()(const BlockedRange& range) const
@@ -824,7 +895,17 @@ struct CascadeClassifierInvoker
for( int x = 0; x < processingRectSize.width; x += yStep )
{
int result = classifier->runAt(evaluator, Point(x, y));
if( result > 0 )
if( rejectLevels )
{
if( result == 1 )
result = -1*classifier->data.stages.size();
if( classifier->data.stages.size() + result < 6 )
{
rectangles->push_back(Rect(cvRound(x*scalingFactor), cvRound(y*scalingFactor), winSize.width, winSize.height));
rejectLevels->push_back(-result);
}
}
else if( result > 0 )
rectangles->push_back(Rect(cvRound(x*scalingFactor), cvRound(y*scalingFactor),
winSize.width, winSize.height));
if( result == 0 )
@@ -838,18 +919,31 @@ struct CascadeClassifierInvoker
Size processingRectSize;
int stripSize, yStep;
double scalingFactor;
vector<int> *rejectLevels;
};
struct getRect { Rect operator ()(const CvAvgComp& e) const { return e.rect; } };
bool CascadeClassifier::detectSingleScale( const Mat& image, int stripCount, Size processingRectSize,
int stripSize, int yStep, double factor, vector<Rect>& candidates )
int stripSize, int yStep, double factor, vector<Rect>& candidates,
bool outputRejectLevels, vector<int>& levels )
{
if( !featureEvaluator->setImage( image, data.origWinSize ) )
return false;
ConcurrentRectVector concurrentCandidates;
parallel_for(BlockedRange(0, stripCount), CascadeClassifierInvoker( *this, processingRectSize, stripSize, yStep, factor, concurrentCandidates));
vector<int> rejectLevels;
if( outputRejectLevels )
{
parallel_for(BlockedRange(0, stripCount), CascadeClassifierInvoker( *this, processingRectSize, stripSize, yStep, factor,
concurrentCandidates, rejectLevels, true));
levels.insert( levels.end(), rejectLevels.begin(), rejectLevels.end() );
}
else
{
parallel_for(BlockedRange(0, stripCount), CascadeClassifierInvoker( *this, processingRectSize, stripSize, yStep, factor,
concurrentCandidates, rejectLevels, false));
}
candidates.insert( candidates.end(), concurrentCandidates.begin(), concurrentCandidates.end() );
return true;
@@ -877,7 +971,8 @@ bool CascadeClassifier::setImage(const Mat& image)
void CascadeClassifier::detectMultiScale( const Mat& image, vector<Rect>& objects,
double scaleFactor, int minNeighbors,
int flags, Size minObjectSize, Size maxObjectSize )
int flags, Size minObjectSize, Size maxObjectSize,
bool outputRejectLevels, vector<int>& rejectLevels )
{
const double GROUP_EPS = 0.2;
@@ -946,14 +1041,16 @@ void CascadeClassifier::detectMultiScale( const Mat& image, vector<Rect>& object
stripSize = processingRectSize.height;
#endif
if( !detectSingleScale( scaledImage, stripCount, processingRectSize, stripSize, yStep, factor, candidates ) )
if( !detectSingleScale( scaledImage, stripCount, processingRectSize, stripSize, yStep, factor, candidates,
outputRejectLevels, rejectLevels ) )
break;
}
objects.resize(candidates.size());
std::copy(candidates.begin(), candidates.end(), objects.begin());
groupRectangles( objects, minNeighbors, GROUP_EPS );
groupRectangles( objects, rejectLevels, minNeighbors, GROUP_EPS );
}
bool CascadeClassifier::Data::read(const FileNode &root)