mirror of
https://github.com/opencv/opencv.git
synced 2024-11-27 20:50:25 +08:00
Added HOG features to cascade detection algorithm.
Added pedestrian detection trained model for HOG cascade detection algorithm.
This commit is contained in:
parent
4ee462c961
commit
50543d627f
3986
data/hogcascades/hogcascade_pedestrians.xml
Normal file
3986
data/hogcascades/hogcascade_pedestrians.xml
Normal file
File diff suppressed because it is too large
Load Diff
@ -298,7 +298,7 @@ CV_EXPORTS void groupRectangles_meanshift(vector<Rect>& rectList, vector<double>
|
|||||||
class CV_EXPORTS FeatureEvaluator
|
class CV_EXPORTS FeatureEvaluator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum { HAAR = 0, LBP = 1 };
|
enum { HAAR = 0, LBP = 1, HOG = 2 };
|
||||||
virtual ~FeatureEvaluator();
|
virtual ~FeatureEvaluator();
|
||||||
|
|
||||||
virtual bool read(const FileNode& node);
|
virtual bool read(const FileNode& node);
|
||||||
|
@ -592,14 +592,197 @@ bool LBPEvaluator::setWindow( Point pt )
|
|||||||
return false;
|
return false;
|
||||||
offset = pt.y * ((int)sum.step/sizeof(int)) + pt.x;
|
offset = pt.y * ((int)sum.step/sizeof(int)) + pt.x;
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------- HOGEvaluator ---------------------------------------
|
||||||
|
bool HOGEvaluator::Feature :: read( const FileNode& node )
|
||||||
|
{
|
||||||
|
FileNode rnode = node[CC_RECT];
|
||||||
|
FileNodeIterator it = rnode.begin();
|
||||||
|
it >> rect[0].x >> rect[0].y >> rect[0].width >> rect[0].height >> featComponent;
|
||||||
|
rect[1].x = rect[0].x + rect[0].width;
|
||||||
|
rect[1].y = rect[0].y;
|
||||||
|
rect[2].x = rect[0].x;
|
||||||
|
rect[2].y = rect[0].y + rect[0].height;
|
||||||
|
rect[3].x = rect[0].x + rect[0].width;
|
||||||
|
rect[3].y = rect[0].y + rect[0].height;
|
||||||
|
rect[1].width = rect[2].width = rect[3].width = rect[0].width;
|
||||||
|
rect[1].height = rect[2].height = rect[3].height = rect[0].height;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ptr<FeatureEvaluator> FeatureEvaluator::create(int featureType)
|
HOGEvaluator::HOGEvaluator()
|
||||||
|
{
|
||||||
|
features = new vector<Feature>();
|
||||||
|
}
|
||||||
|
|
||||||
|
HOGEvaluator::~HOGEvaluator()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HOGEvaluator::read( const FileNode& node )
|
||||||
|
{
|
||||||
|
features->resize(node.size());
|
||||||
|
featuresPtr = &(*features)[0];
|
||||||
|
FileNodeIterator it = node.begin(), it_end = node.end();
|
||||||
|
for(int i = 0; it != it_end; ++it, i++)
|
||||||
|
{
|
||||||
|
if(!featuresPtr[i].read(*it))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ptr<FeatureEvaluator> HOGEvaluator::clone() const
|
||||||
|
{
|
||||||
|
HOGEvaluator* ret = new HOGEvaluator;
|
||||||
|
ret->origWinSize = origWinSize;
|
||||||
|
ret->features = features;
|
||||||
|
ret->featuresPtr = &(*ret->features)[0];
|
||||||
|
ret->offset = offset;
|
||||||
|
ret->hist = hist;
|
||||||
|
ret->normSum = normSum;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HOGEvaluator::setImage( const Mat& image, Size winSize )
|
||||||
|
{
|
||||||
|
int rows = image.rows + 1;
|
||||||
|
int cols = image.cols + 1;
|
||||||
|
origWinSize = winSize;
|
||||||
|
if( image.cols < origWinSize.width || image.rows < origWinSize.height )
|
||||||
|
return false;
|
||||||
|
hist.clear();
|
||||||
|
for( int bin = 0; bin < Feature::BIN_NUM; bin++ )
|
||||||
|
{
|
||||||
|
hist.push_back( Mat(rows, cols, CV_32FC1) );
|
||||||
|
}
|
||||||
|
normSum.create( rows, cols, CV_32FC1 );
|
||||||
|
|
||||||
|
integralHistogram( image, hist, normSum, Feature::BIN_NUM );
|
||||||
|
|
||||||
|
size_t featIdx, featCount = features->size();
|
||||||
|
|
||||||
|
for( featIdx = 0; featIdx < featCount; featIdx++ )
|
||||||
|
{
|
||||||
|
featuresPtr[featIdx].updatePtrs( hist, normSum );
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HOGEvaluator::setWindow(Point pt)
|
||||||
|
{
|
||||||
|
if( pt.x < 0 || pt.y < 0 ||
|
||||||
|
pt.x + origWinSize.width >= hist[0].cols-2 ||
|
||||||
|
pt.y + origWinSize.height >= hist[0].rows-2 )
|
||||||
|
return false;
|
||||||
|
offset = pt.y * ((int)hist[0].step/sizeof(float)) + pt.x;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HOGEvaluator::integralHistogram(const Mat &img, vector<Mat> &histogram, Mat &norm, int nbins) const
|
||||||
|
{
|
||||||
|
CV_Assert( img.type() == CV_8U || img.type() == CV_8UC3 );
|
||||||
|
int x, y, binIdx;
|
||||||
|
|
||||||
|
Size gradSize(img.size());
|
||||||
|
Size histSize(histogram[0].size());
|
||||||
|
Mat grad(gradSize, CV_32F);
|
||||||
|
Mat qangle(gradSize, CV_8U);
|
||||||
|
|
||||||
|
AutoBuffer<int> mapbuf(gradSize.width + gradSize.height + 4);
|
||||||
|
int* xmap = (int*)mapbuf + 1;
|
||||||
|
int* ymap = xmap + gradSize.width + 2;
|
||||||
|
|
||||||
|
const int borderType = (int)BORDER_REPLICATE;
|
||||||
|
|
||||||
|
for( x = -1; x < gradSize.width + 1; x++ )
|
||||||
|
xmap[x] = borderInterpolate(x, gradSize.width, borderType);
|
||||||
|
for( y = -1; y < gradSize.height + 1; y++ )
|
||||||
|
ymap[y] = borderInterpolate(y, gradSize.height, borderType);
|
||||||
|
|
||||||
|
int width = gradSize.width;
|
||||||
|
AutoBuffer<float> _dbuf(width*4);
|
||||||
|
float* dbuf = _dbuf;
|
||||||
|
Mat Dx(1, width, CV_32F, dbuf);
|
||||||
|
Mat Dy(1, width, CV_32F, dbuf + width);
|
||||||
|
Mat Mag(1, width, CV_32F, dbuf + width*2);
|
||||||
|
Mat Angle(1, width, CV_32F, dbuf + width*3);
|
||||||
|
|
||||||
|
float angleScale = (float)(nbins/CV_PI);
|
||||||
|
|
||||||
|
for( y = 0; y < gradSize.height; y++ )
|
||||||
|
{
|
||||||
|
const uchar* currPtr = img.data + img.step*ymap[y];
|
||||||
|
const uchar* prevPtr = img.data + img.step*ymap[y-1];
|
||||||
|
const uchar* nextPtr = img.data + img.step*ymap[y+1];
|
||||||
|
float* gradPtr = (float*)grad.ptr(y);
|
||||||
|
uchar* qanglePtr = (uchar*)qangle.ptr(y);
|
||||||
|
|
||||||
|
for( x = 0; x < width; x++ )
|
||||||
|
{
|
||||||
|
dbuf[x] = (float)(currPtr[xmap[x+1]] - currPtr[xmap[x-1]]);
|
||||||
|
dbuf[width + x] = (float)(nextPtr[xmap[x]] - prevPtr[xmap[x]]);
|
||||||
|
}
|
||||||
|
cartToPolar( Dx, Dy, Mag, Angle, false );
|
||||||
|
for( x = 0; x < width; x++ )
|
||||||
|
{
|
||||||
|
float mag = dbuf[x+width*2];
|
||||||
|
float angle = dbuf[x+width*3];
|
||||||
|
angle = angle*angleScale - 0.5f;
|
||||||
|
int bidx = cvFloor(angle);
|
||||||
|
angle -= bidx;
|
||||||
|
if( bidx < 0 )
|
||||||
|
bidx += nbins;
|
||||||
|
else if( bidx >= nbins )
|
||||||
|
bidx -= nbins;
|
||||||
|
|
||||||
|
qanglePtr[x] = (uchar)bidx;
|
||||||
|
gradPtr[x] = mag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
integral(grad, norm, grad.depth());
|
||||||
|
|
||||||
|
float* histBuf;
|
||||||
|
const float* magBuf;
|
||||||
|
const uchar* binsBuf;
|
||||||
|
|
||||||
|
int binsStep = (int)( qangle.step / sizeof(uchar) );
|
||||||
|
int histStep = (int)( histogram[0].step / sizeof(float) );
|
||||||
|
int magStep = (int)( grad.step / sizeof(float) );
|
||||||
|
for( binIdx = 0; binIdx < nbins; binIdx++ )
|
||||||
|
{
|
||||||
|
histBuf = (float*)histogram[binIdx].data;
|
||||||
|
magBuf = (const float*)grad.data;
|
||||||
|
binsBuf = (const uchar*)qangle.data;
|
||||||
|
|
||||||
|
memset( histBuf, 0, histSize.width * sizeof(histBuf[0]) );
|
||||||
|
histBuf += histStep + 1;
|
||||||
|
for( y = 0; y < qangle.rows; y++ )
|
||||||
|
{
|
||||||
|
histBuf[-1] = 0.f;
|
||||||
|
float strSum = 0.f;
|
||||||
|
for( x = 0; x < qangle.cols; x++ )
|
||||||
|
{
|
||||||
|
if( binsBuf[x] == binIdx )
|
||||||
|
strSum += magBuf[x];
|
||||||
|
histBuf[x] = histBuf[-histStep + x] + strSum;
|
||||||
|
}
|
||||||
|
histBuf += histStep;
|
||||||
|
binsBuf += binsStep;
|
||||||
|
magBuf += magStep;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ptr<FeatureEvaluator> FeatureEvaluator::create( int featureType )
|
||||||
{
|
{
|
||||||
return featureType == HAAR ? Ptr<FeatureEvaluator>(new HaarEvaluator) :
|
return featureType == HAAR ? Ptr<FeatureEvaluator>(new HaarEvaluator) :
|
||||||
featureType == LBP ? Ptr<FeatureEvaluator>(new LBPEvaluator) : Ptr<FeatureEvaluator>();
|
featureType == LBP ? Ptr<FeatureEvaluator>(new LBPEvaluator) :
|
||||||
|
featureType == HOG ? Ptr<FeatureEvaluator>(new HOGEvaluator) :
|
||||||
|
Ptr<FeatureEvaluator>();
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------- Classifier Cascade --------------------------------------------
|
//---------------------------------------- Classifier Cascade --------------------------------------------
|
||||||
|
|
||||||
CascadeClassifier::CascadeClassifier()
|
CascadeClassifier::CascadeClassifier()
|
||||||
@ -637,21 +820,38 @@ bool CascadeClassifier::load(const string& filename)
|
|||||||
return !oldCascade.empty();
|
return !oldCascade.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int CascadeClassifier::runAt( Ptr<FeatureEvaluator>& featureEvaluator, Point pt, double& weight )
|
int CascadeClassifier::runAt( Ptr<FeatureEvaluator>& featureEvaluator, Point pt, double& weight )
|
||||||
{
|
{
|
||||||
CV_Assert( oldCascade.empty() );
|
CV_Assert( oldCascade.empty() );
|
||||||
|
|
||||||
assert(data.featureType == FeatureEvaluator::HAAR ||
|
assert( data.featureType == FeatureEvaluator::HAAR ||
|
||||||
data.featureType == FeatureEvaluator::LBP);
|
data.featureType == FeatureEvaluator::LBP ||
|
||||||
|
data.featureType == FeatureEvaluator::HOG );
|
||||||
|
|
||||||
return !featureEvaluator->setWindow(pt) ? -1 :
|
if( !featureEvaluator->setWindow(pt) )
|
||||||
data.isStumpBased ? ( data.featureType == FeatureEvaluator::HAAR ?
|
return -1;
|
||||||
predictOrderedStump<HaarEvaluator>( *this, featureEvaluator, weight ) :
|
if( data.isStumpBased )
|
||||||
predictCategoricalStump<LBPEvaluator>( *this, featureEvaluator, weight ) ) :
|
{
|
||||||
( data.featureType == FeatureEvaluator::HAAR ?
|
if( data.featureType == FeatureEvaluator::HAAR )
|
||||||
predictOrdered<HaarEvaluator>( *this, featureEvaluator, weight ) :
|
return predictOrderedStump<HaarEvaluator>( *this, featureEvaluator, weight );
|
||||||
predictCategorical<LBPEvaluator>( *this, featureEvaluator, weight ) );
|
else if( data.featureType == FeatureEvaluator::LBP )
|
||||||
|
return predictCategoricalStump<LBPEvaluator>( *this, featureEvaluator, weight );
|
||||||
|
else if( data.featureType == FeatureEvaluator::HOG )
|
||||||
|
return predictOrderedStump<HOGEvaluator>( *this, featureEvaluator, weight );
|
||||||
|
else
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( data.featureType == FeatureEvaluator::HAAR )
|
||||||
|
return predictOrdered<HaarEvaluator>( *this, featureEvaluator, weight );
|
||||||
|
else if( data.featureType == FeatureEvaluator::LBP )
|
||||||
|
return predictCategorical<LBPEvaluator>( *this, featureEvaluator, weight );
|
||||||
|
else if( data.featureType == FeatureEvaluator::HOG )
|
||||||
|
return predictOrdered<HOGEvaluator>( *this, featureEvaluator, weight );
|
||||||
|
else
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CascadeClassifier::setImage( Ptr<FeatureEvaluator>& featureEvaluator, const Mat& image )
|
bool CascadeClassifier::setImage( Ptr<FeatureEvaluator>& featureEvaluator, const Mat& image )
|
||||||
@ -827,7 +1027,16 @@ void CascadeClassifier::detectMultiScale( const Mat& image, vector<Rect>& object
|
|||||||
Mat scaledImage( scaledImageSize, CV_8U, imageBuffer.data );
|
Mat scaledImage( scaledImageSize, CV_8U, imageBuffer.data );
|
||||||
resize( grayImage, scaledImage, scaledImageSize, 0, 0, CV_INTER_LINEAR );
|
resize( grayImage, scaledImage, scaledImageSize, 0, 0, CV_INTER_LINEAR );
|
||||||
|
|
||||||
int yStep = factor > 2. ? 1 : 2;
|
int yStep;
|
||||||
|
if( getFeatureType() == cv::FeatureEvaluator::HOG )
|
||||||
|
{
|
||||||
|
yStep = 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
yStep = factor > 2. ? 1 : 2;
|
||||||
|
}
|
||||||
|
|
||||||
int stripCount, stripSize;
|
int stripCount, stripSize;
|
||||||
|
|
||||||
#if defined(HAVE_TBB) || defined(HAVE_THREADING_FRAMEWORK)
|
#if defined(HAVE_TBB) || defined(HAVE_THREADING_FRAMEWORK)
|
||||||
@ -885,6 +1094,9 @@ bool CascadeClassifier::Data::read(const FileNode &root)
|
|||||||
featureType = FeatureEvaluator::HAAR;
|
featureType = FeatureEvaluator::HAAR;
|
||||||
else if( featureTypeStr == CC_LBP )
|
else if( featureTypeStr == CC_LBP )
|
||||||
featureType = FeatureEvaluator::LBP;
|
featureType = FeatureEvaluator::LBP;
|
||||||
|
else if( featureTypeStr == CC_HOG )
|
||||||
|
featureType = FeatureEvaluator::HOG;
|
||||||
|
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -32,6 +32,8 @@ namespace cv
|
|||||||
#define CC_LBP "LBP"
|
#define CC_LBP "LBP"
|
||||||
#define CC_RECT "rect"
|
#define CC_RECT "rect"
|
||||||
|
|
||||||
|
#define CC_HOG "HOG"
|
||||||
|
|
||||||
#define CV_SUM_PTRS( p0, p1, p2, p3, sum, rect, step ) \
|
#define CV_SUM_PTRS( p0, p1, p2, p3, sum, rect, step ) \
|
||||||
/* (x, y) */ \
|
/* (x, y) */ \
|
||||||
(p0) = sum + (rect).x + (step) * (rect).y, \
|
(p0) = sum + (rect).x + (step) * (rect).y, \
|
||||||
@ -236,6 +238,84 @@ inline void LBPEvaluator::Feature :: updatePtrs( const Mat& sum )
|
|||||||
CV_SUM_PTRS( p[8], p[9], p[12], p[13], ptr, tr, step );
|
CV_SUM_PTRS( p[8], p[9], p[12], p[13], ptr, tr, step );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------- HOGEvaluator -------------------------------------------
|
||||||
|
|
||||||
|
class HOGEvaluator : public FeatureEvaluator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct Feature
|
||||||
|
{
|
||||||
|
Feature();
|
||||||
|
float calc( int offset ) const;
|
||||||
|
void updatePtrs( const vector<Mat>& _hist, const Mat &_normSum );
|
||||||
|
bool read( const FileNode& node );
|
||||||
|
|
||||||
|
enum { CELL_NUM = 4, BIN_NUM = 9 };
|
||||||
|
|
||||||
|
Rect rect[CELL_NUM];
|
||||||
|
int featComponent; //component index from 0 to 35
|
||||||
|
const float* pF[4]; //for feature calculation
|
||||||
|
const float* pN[4]; //for normalization calculation
|
||||||
|
};
|
||||||
|
HOGEvaluator();
|
||||||
|
virtual ~HOGEvaluator();
|
||||||
|
virtual bool read( const FileNode& node );
|
||||||
|
virtual Ptr<FeatureEvaluator> clone() const;
|
||||||
|
virtual int getFeatureType() const { return FeatureEvaluator::HOG; }
|
||||||
|
virtual bool setImage( const Mat& image, Size winSize );
|
||||||
|
virtual bool setWindow( Point pt );
|
||||||
|
double operator()(int featureIdx) const
|
||||||
|
{
|
||||||
|
return featuresPtr[featureIdx].calc(offset);
|
||||||
|
}
|
||||||
|
virtual double calcOrd( int featureIdx ) const
|
||||||
|
{
|
||||||
|
return (*this)(featureIdx);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual void integralHistogram( const Mat& srcImage, vector<Mat> &histogram, Mat &norm, int nbins ) const;
|
||||||
|
|
||||||
|
Size origWinSize;
|
||||||
|
Ptr<vector<Feature>> features;
|
||||||
|
Feature* featuresPtr;
|
||||||
|
vector<Mat> hist;
|
||||||
|
Mat normSum;
|
||||||
|
int offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline HOGEvaluator::Feature :: Feature()
|
||||||
|
{
|
||||||
|
rect[0] = rect[1] = rect[2] = rect[3] = Rect();
|
||||||
|
pF[0] = pF[1] = pF[2] = pF[3] = 0;
|
||||||
|
pN[0] = pN[1] = pN[2] = pN[3] = 0;
|
||||||
|
featComponent = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float HOGEvaluator::Feature :: calc( int offset ) const
|
||||||
|
{
|
||||||
|
float res = CALC_SUM(pF, offset);
|
||||||
|
float normFactor = CALC_SUM(pN, offset);
|
||||||
|
res = (res > 0.001f) ? (res / ( normFactor + 0.001f) ) : 0.f;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void HOGEvaluator::Feature :: updatePtrs( const vector<Mat> &_hist, const Mat &_normSum )
|
||||||
|
{
|
||||||
|
int binIdx = featComponent % BIN_NUM;
|
||||||
|
int cellIdx = featComponent / BIN_NUM;
|
||||||
|
Rect normRect = Rect( rect[0].x, rect[0].y, 2*rect[0].width, 2*rect[0].height );
|
||||||
|
|
||||||
|
const float* featBuf = (const float*)_hist[binIdx].data;
|
||||||
|
size_t featStep = _hist[0].step / sizeof(featBuf[0]);
|
||||||
|
|
||||||
|
const float* normBuf = (const float*)_normSum.data;
|
||||||
|
size_t normStep = _normSum.step / sizeof(normBuf[0]);
|
||||||
|
|
||||||
|
CV_SUM_PTRS( pF[0], pF[1], pF[2], pF[3], featBuf, rect[cellIdx], featStep );
|
||||||
|
CV_SUM_PTRS( pN[0], pN[1], pN[2], pN[3], normBuf, normRect, normStep );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user