--- /dev/null
+#include "HOGfeatures.h"\r
+#include "cascadeclassifier.h"\r
+\r
+\r
+CvHOGFeatureParams::CvHOGFeatureParams()\r
+{\r
+ maxCatCount = 0;\r
+ name = HOGF_NAME;\r
+ featSize = N_BINS * N_CELLS;\r
+}\r
+\r
+void CvHOGEvaluator::init(const CvFeatureParams *_featureParams, int _maxSampleCount, Size _winSize)\r
+{\r
+ CV_Assert( _maxSampleCount > 0);\r
+ int cols = (_winSize.width + 1) * (_winSize.height + 1);\r
+ for (int bin = 0; bin < N_BINS; bin++)\r
+ {\r
+ hist.push_back(Mat(_maxSampleCount, cols, CV_32FC1));\r
+ }\r
+ normSum.create( (int)_maxSampleCount, cols, CV_32FC1 );\r
+ CvFeatureEvaluator::init( _featureParams, _maxSampleCount, _winSize );\r
+}\r
+\r
+void CvHOGEvaluator::setImage(const Mat &img, uchar clsLabel, int idx)\r
+{\r
+ CV_DbgAssert( !hist.empty());\r
+ CvFeatureEvaluator::setImage( img, clsLabel, idx );\r
+ vector<Mat> integralHist;\r
+ for (int bin = 0; bin < N_BINS; bin++)\r
+ {\r
+ integralHist.push_back( Mat(winSize.height + 1, winSize.width + 1, hist[bin].type(), hist[bin].ptr<float>((int)idx)) );\r
+ }\r
+ Mat integralNorm(winSize.height + 1, winSize.width + 1, normSum.type(), normSum.ptr<float>((int)idx));\r
+ integralHistogram(img, integralHist, integralNorm, (int)N_BINS);\r
+}\r
+\r
+//void CvHOGEvaluator::writeFeatures( FileStorage &fs, const Mat& featureMap ) const\r
+//{\r
+// _writeFeatures( features, fs, featureMap );\r
+//}\r
+\r
+void CvHOGEvaluator::writeFeatures( FileStorage &fs, const Mat& featureMap ) const\r
+{\r
+ int featIdx;\r
+ int componentIdx;\r
+ const Mat_<int>& featureMap_ = (const Mat_<int>&)featureMap;\r
+ fs << FEATURES << "[";\r
+ for ( int fi = 0; fi < featureMap.cols; fi++ )\r
+ if ( featureMap_(0, fi) >= 0 )\r
+ {\r
+ fs << "{";\r
+ featIdx = fi / getFeatureSize();\r
+ componentIdx = fi % getFeatureSize();\r
+ features[featIdx].write( fs, componentIdx );\r
+ fs << "}";\r
+ }\r
+ fs << "]"; \r
+}\r
+\r
+void CvHOGEvaluator::generateFeatures()\r
+{\r
+ int offset = winSize.width + 1;\r
+ Size blockStep;\r
+ int x, y, t, w, h;\r
+\r
+ for (t = 8; t <= winSize.width/2; t+=8) //t = size of a cell. blocksize = 4*cellSize\r
+ {\r
+ blockStep = Size(4,4);\r
+ w = 2*t; //width of a block\r
+ h = 2*t; //height of a block\r
+ for (x = 0; x <= winSize.width - w; x += blockStep.width)\r
+ {\r
+ for (y = 0; y <= winSize.height - h; y += blockStep.height)\r
+ {\r
+ features.push_back(Feature(offset, x, y, t, t));\r
+ }\r
+ }\r
+ w = 2*t;\r
+ h = 4*t;\r
+ for (x = 0; x <= winSize.width - w; x += blockStep.width)\r
+ {\r
+ for (y = 0; y <= winSize.height - h; y += blockStep.height)\r
+ {\r
+ features.push_back(Feature(offset, x, y, t, 2*t));\r
+ }\r
+ }\r
+ w = 4*t;\r
+ h = 2*t; \r
+ for (x = 0; x <= winSize.width - w; x += blockStep.width)\r
+ {\r
+ for (y = 0; y <= winSize.height - h; y += blockStep.height)\r
+ { \r
+ features.push_back(Feature(offset, x, y, 2*t, t));\r
+ }\r
+ }\r
+ }\r
+\r
+ numFeatures = (int)features.size();\r
+}\r
+\r
+CvHOGEvaluator::Feature::Feature()\r
+{\r
+ for (int i = 0; i < N_CELLS; i++)\r
+ {\r
+ rect[i] = Rect(0, 0, 0, 0);\r
+ }\r
+}\r
+\r
+CvHOGEvaluator::Feature::Feature( int offset, int x, int y, int cellW, int cellH )\r
+{\r
+ rect[0] = Rect(x, y, cellW, cellH); //cell0\r
+ rect[1] = Rect(x+cellW, y, cellW, cellH); //cell1\r
+ rect[2] = Rect(x, y+cellH, cellW, cellH); //cell2\r
+ rect[3] = Rect(x+cellW, y+cellH, cellW, cellH); //cell3\r
+\r
+ for (int i = 0; i < N_CELLS; i++)\r
+ {\r
+ CV_SUM_OFFSETS(fastRect[i].p0, fastRect[i].p1, fastRect[i].p2, fastRect[i].p3, rect[i], offset);\r
+ }\r
+}\r
+\r
+void CvHOGEvaluator::Feature::write(FileStorage &fs) const\r
+{\r
+ fs << CC_RECTS << "[";\r
+ for( int i = 0; i < N_CELLS; i++ )\r
+ {\r
+ fs << "[:" << rect[i].x << rect[i].y << rect[i].width << rect[i].height << "]";\r
+ }\r
+ fs << "]";\r
+}\r
+\r
+//cell and bin idx writing\r
+//void CvHOGEvaluator::Feature::write(FileStorage &fs, int varIdx) const\r
+//{\r
+// int featComponent = varIdx % (N_CELLS * N_BINS);\r
+// int cellIdx = featComponent / N_BINS;\r
+// int binIdx = featComponent % N_BINS;\r
+//\r
+// fs << CC_RECTS << "[:" << rect[cellIdx].x << rect[cellIdx].y << \r
+// rect[cellIdx].width << rect[cellIdx].height << binIdx << "]";\r
+//}\r
+\r
+//cell[0] and featComponent idx writing. By cell[0] it's possible to recover all block\r
+//All block is nessesary for block normalization\r
+void CvHOGEvaluator::Feature::write(FileStorage &fs, int featComponentIdx) const\r
+{\r
+ fs << CC_RECT << "[:" << rect[0].x << rect[0].y << \r
+ rect[0].width << rect[0].height << featComponentIdx << "]";\r
+}\r
+\r
+\r
+void CvHOGEvaluator::integralHistogram(const Mat &img, vector<Mat> &histogram, Mat &norm, int nbins) const\r
+{\r
+ CV_Assert( img.type() == CV_8U || img.type() == CV_8UC3 );\r
+ int x, y, binIdx;\r
+\r
+ Size gradSize(img.size());\r
+ Size histSize(histogram[0].size());\r
+ Mat grad(gradSize, CV_32F);\r
+ Mat qangle(gradSize, CV_8U);\r
+\r
+ AutoBuffer<int> mapbuf(gradSize.width + gradSize.height + 4);\r
+ int* xmap = (int*)mapbuf + 1;\r
+ int* ymap = xmap + gradSize.width + 2;\r
+\r
+ const int borderType = (int)BORDER_REPLICATE;\r
+\r
+ for( x = -1; x < gradSize.width + 1; x++ )\r
+ xmap[x] = borderInterpolate(x, gradSize.width, borderType);\r
+ for( y = -1; y < gradSize.height + 1; y++ )\r
+ ymap[y] = borderInterpolate(y, gradSize.height, borderType);\r
+\r
+ int width = gradSize.width;\r
+ AutoBuffer<float> _dbuf(width*4);\r
+ float* dbuf = _dbuf;\r
+ Mat Dx(1, width, CV_32F, dbuf);\r
+ Mat Dy(1, width, CV_32F, dbuf + width);\r
+ Mat Mag(1, width, CV_32F, dbuf + width*2);\r
+ Mat Angle(1, width, CV_32F, dbuf + width*3);\r
+\r
+ float angleScale = (float)(nbins/CV_PI);\r
+\r
+ for( y = 0; y < gradSize.height; y++ )\r
+ {\r
+ const uchar* currPtr = img.data + img.step*ymap[y];\r
+ const uchar* prevPtr = img.data + img.step*ymap[y-1];\r
+ const uchar* nextPtr = img.data + img.step*ymap[y+1];\r
+ float* gradPtr = (float*)grad.ptr(y);\r
+ uchar* qanglePtr = (uchar*)qangle.ptr(y);\r
+\r
+ for( x = 0; x < width; x++ )\r
+ {\r
+ dbuf[x] = (float)(currPtr[xmap[x+1]] - currPtr[xmap[x-1]]);\r
+ dbuf[width + x] = (float)(nextPtr[xmap[x]] - prevPtr[xmap[x]]);\r
+ }\r
+ cartToPolar( Dx, Dy, Mag, Angle, false );\r
+ for( x = 0; x < width; x++ )\r
+ {\r
+ float mag = dbuf[x+width*2];\r
+ float angle = dbuf[x+width*3];\r
+ angle = angle*angleScale - 0.5f;\r
+ int bidx = cvFloor(angle);\r
+ angle -= bidx;\r
+ if( bidx < 0 )\r
+ bidx += nbins;\r
+ else if( bidx >= nbins )\r
+ bidx -= nbins;\r
+\r
+ qanglePtr[x] = (uchar)bidx;\r
+ gradPtr[x] = mag;\r
+ }\r
+ }\r
+ integral(grad, norm, grad.depth());\r
+\r
+ float* histBuf;\r
+ const float* magBuf;\r
+ const uchar* binsBuf;\r
+\r
+ int binsStep = (int)( qangle.step / sizeof(uchar) );\r
+ int histStep = (int)( histogram[0].step / sizeof(float) );\r
+ int magStep = (int)( grad.step / sizeof(float) );\r
+ for( binIdx = 0; binIdx < nbins; binIdx++ )\r
+ {\r
+ histBuf = (float*)histogram[binIdx].data;\r
+ magBuf = (const float*)grad.data;\r
+ binsBuf = (const uchar*)qangle.data;\r
+\r
+ memset( histBuf, 0, histSize.width * sizeof(histBuf[0]) );\r
+ histBuf += histStep + 1;\r
+ for( y = 0; y < qangle.rows; y++ )\r
+ { \r
+ histBuf[-1] = 0.f;\r
+ float strSum = 0.f;\r
+ for( x = 0; x < qangle.cols; x++ )\r
+ {\r
+ if( binsBuf[x] == binIdx )\r
+ strSum += magBuf[x];\r
+ histBuf[x] = histBuf[-histStep + x] + strSum;\r
+ }\r
+ histBuf += histStep;\r
+ binsBuf += binsStep;\r
+ magBuf += magStep;\r
+ }\r
+ }\r
+}\r
--- /dev/null
+#ifndef _OPENCV_HOGFEATURES_H_\r
+#define _OPENCV_HOGFEATURES_H_\r
+\r
+#include "traincascade_features.h"\r
+\r
+//#define TEST_INTHIST_BUILD\r
+//#define TEST_FEAT_CALC\r
+\r
+#define N_BINS 9\r
+#define N_CELLS 4\r
+\r
+#define HOGF_NAME "HOGFeatureParams"\r
+struct CvHOGFeatureParams : public CvFeatureParams\r
+{\r
+ CvHOGFeatureParams(); \r
+};\r
+\r
+class CvHOGEvaluator : public CvFeatureEvaluator\r
+{\r
+public:\r
+ virtual ~CvHOGEvaluator() {}\r
+ virtual void init(const CvFeatureParams *_featureParams,\r
+ int _maxSampleCount, Size _winSize );\r
+ virtual void setImage(const Mat& img, uchar clsLabel, int idx); \r
+ virtual float operator()(int varIdx, int sampleIdx) const;\r
+ virtual void writeFeatures( FileStorage &fs, const Mat& featureMap ) const;\r
+protected:\r
+ virtual void generateFeatures();\r
+ virtual void integralHistogram(const Mat &img, vector<Mat> &histogram, Mat &norm, int nbins) const;\r
+ class Feature\r
+ {\r
+ public:\r
+ Feature();\r
+ Feature( int offset, int x, int y, int cellW, int cellH ); \r
+ float calc( const vector<Mat> &_hists, const Mat &_normSum, size_t y, int featComponent ) const; \r
+ void write( FileStorage &fs ) const;\r
+ void write( FileStorage &fs, int varIdx ) const;\r
+\r
+ Rect rect[N_CELLS]; //cells\r
+\r
+ struct\r
+ {\r
+ int p0, p1, p2, p3;\r
+ } fastRect[N_CELLS];\r
+ };\r
+ vector<Feature> features;\r
+\r
+ Mat normSum; //for nomalization calculation (L1 or L2)\r
+ vector<Mat> hist;\r
+};\r
+\r
+inline float CvHOGEvaluator::operator()(int varIdx, int sampleIdx) const\r
+{\r
+ int featureIdx = varIdx / (N_BINS * N_CELLS);\r
+ int componentIdx = varIdx % (N_BINS * N_CELLS);\r
+ //return features[featureIdx].calc( hist, sampleIdx, componentIdx); \r
+ return features[featureIdx].calc( hist, normSum, sampleIdx, componentIdx); \r
+}\r
+\r
+inline float CvHOGEvaluator::Feature::calc( const vector<Mat>& _hists, const Mat& _normSum, size_t y, int featComponent ) const\r
+{\r
+ float normFactor;\r
+ float res;\r
+\r
+ int binIdx = featComponent % N_BINS;\r
+ int cellIdx = featComponent / N_BINS;\r
+\r
+ const float *hist = _hists[binIdx].ptr<float>(y);\r
+ res = hist[fastRect[cellIdx].p0] - hist[fastRect[cellIdx].p1] - hist[fastRect[cellIdx].p2] + hist[fastRect[cellIdx].p3];\r
+\r
+ const float *normSum = _normSum.ptr<float>(y);\r
+ normFactor = (float)(normSum[fastRect[0].p0] - normSum[fastRect[1].p1] - normSum[fastRect[2].p2] + normSum[fastRect[3].p3]);\r
+ res = (res > 0.001f) ? ( res / (normFactor + 0.001f) ) : 0.f; //for cutting negative values, which apper due to floating precision\r
+\r
+ return res;\r
+}\r
+\r
+#endif // _OPENCV_HOGFEATURES_H_\r
using namespace std;
static const char* stageTypes[] = { CC_BOOST };
-static const char* featureTypes[] = { CC_HAAR, CC_LBP };
+static const char* featureTypes[] = { CC_HAAR, CC_LBP, CC_HOG };
CvCascadeParams::CvCascadeParams() : stageType( defaultStageType ),
featureType( defaultFeatureType ), winSize( cvSize(24, 24) )
CV_Assert( !stageTypeStr.empty() );
fs << CC_STAGE_TYPE << stageTypeStr;
String featureTypeStr = featureType == CvFeatureParams::HAAR ? CC_HAAR :
- featureType == CvFeatureParams::LBP ? CC_LBP : 0;
+ featureType == CvFeatureParams::LBP ? CC_LBP :
+ featureType == CvFeatureParams::HOG ? CC_HOG :
+ 0;
CV_Assert( !stageTypeStr.empty() );
fs << CC_FEATURE_TYPE << featureTypeStr;
fs << CC_HEIGHT << winSize.height;
return false;
rnode >> featureTypeStr;
featureType = !featureTypeStr.compare( CC_HAAR ) ? CvFeatureParams::HAAR :
- !featureTypeStr.compare( CC_LBP ) ? CvFeatureParams::LBP : -1;
+ !featureTypeStr.compare( CC_LBP ) ? CvFeatureParams::LBP :
+ !featureTypeStr.compare( CC_HOG ) ? CvFeatureParams::HOG :
+ -1;
if (featureType == -1)
return false;
node[CC_HEIGHT] >> winSize.height;
void CvCascadeClassifier::getUsedFeaturesIdxMap( Mat& featureMap )
{
- featureMap.create( 1, featureEvaluator->getNumFeatures(), CV_32SC1 );
+ int varCount = featureEvaluator->getNumFeatures() * featureEvaluator->getFeatureSize();
+ featureMap.create( 1, varCount, CV_32SC1 );
featureMap.setTo(Scalar(-1));
for( vector< Ptr<CvCascadeBoost> >::const_iterator it = stageClassifiers.begin();
it != stageClassifiers.end(); it++ )
((CvCascadeBoost*)((Ptr<CvCascadeBoost>)(*it)))->markUsedFeaturesInMap( featureMap );
- for( int fi = 0, idx = 0; fi < featureEvaluator->getNumFeatures(); fi++ )
+ for( int fi = 0, idx = 0; fi < varCount; fi++ )
if ( featureMap.at<int>(0, fi) >= 0 )
featureMap.ptr<int>(0)[fi] = idx++;
}