Commit 447ef443d15967d13129cf07ea40db9f8db87b5a

Authored by Jordan Cheney
1 parent edcbc8b8

More steps towards representations and proper formatting in backend

openbr/core/boost.cpp
@@ -1158,6 +1158,7 @@ float CascadeBoost::predict( int sampleIdx, bool returnSum ) const @@ -1158,6 +1158,7 @@ float CascadeBoost::predict( int sampleIdx, bool returnSum ) const
1158 { 1158 {
1159 CV_Assert( weak ); 1159 CV_Assert( weak );
1160 double sum = 0; 1160 double sum = 0;
  1161 +
1161 CvSeqReader reader; 1162 CvSeqReader reader;
1162 cvStartReadSeq( weak, &reader ); 1163 cvStartReadSeq( weak, &reader );
1163 cvSetSeqReaderPos( &reader, 0 ); 1164 cvSetSeqReaderPos( &reader, 0 );
@@ -1167,6 +1168,7 @@ float CascadeBoost::predict( int sampleIdx, bool returnSum ) const @@ -1167,6 +1168,7 @@ float CascadeBoost::predict( int sampleIdx, bool returnSum ) const
1167 CV_READ_SEQ_ELEM( wtree, reader ); 1168 CV_READ_SEQ_ELEM( wtree, reader );
1168 sum += ((CascadeBoostTree*)wtree)->predict(sampleIdx)->value; 1169 sum += ((CascadeBoostTree*)wtree)->predict(sampleIdx)->value;
1169 } 1170 }
  1171 +
1170 if( !returnSum ) 1172 if( !returnSum )
1171 sum = sum < threshold - CV_THRESHOLD_EPS ? 0.0 : 1.0; 1173 sum = sum < threshold - CV_THRESHOLD_EPS ? 0.0 : 1.0;
1172 return (float)sum; 1174 return (float)sum;
openbr/core/cascade.cpp
@@ -130,10 +130,12 @@ bool BrCascadeClassifier::train(const string _cascadeDirName, @@ -130,10 +130,12 @@ bool BrCascadeClassifier::train(const string _cascadeDirName,
130 numStages = _numStages; 130 numStages = _numStages;
131 imgReader.create(_posImages, _negImages, winSize); 131 imgReader.create(_posImages, _negImages, winSize);
132 132
  133 + Representation *representation = Representation::make("MBLBP(24,24)", NULL);
  134 +
133 stageParams = new CascadeBoostParams; 135 stageParams = new CascadeBoostParams;
134 *stageParams = _stageParams; 136 *stageParams = _stageParams;
135 featureEvaluator = new FeatureEvaluator; 137 featureEvaluator = new FeatureEvaluator;
136 - featureEvaluator->init(numPos + numNeg, winSize); 138 + featureEvaluator->init(representation, numPos + numNeg);
137 stageClassifiers.reserve( numStages ); 139 stageClassifiers.reserve( numStages );
138 140
139 double requiredLeafFARate = pow( (double) stageParams->maxFalseAlarm, (double) numStages ) / 141 double requiredLeafFARate = pow( (double) stageParams->maxFalseAlarm, (double) numStages ) /
openbr/core/features.cpp
@@ -5,65 +5,22 @@ using namespace br; @@ -5,65 +5,22 @@ using namespace br;
5 5
6 //------------------------------------- FeatureEvaluator --------------------------------------- 6 //------------------------------------- FeatureEvaluator ---------------------------------------
7 7
8 -void FeatureEvaluator::init(int _maxSampleCount, Size _winSize ) 8 +void FeatureEvaluator::init(Representation *_representation, int _maxSampleCount)
9 { 9 {
10 - CV_Assert(_maxSampleCount > 0);  
11 - winSize = _winSize;  
12 - numFeatures = 0;  
13 - data.create((int)_maxSampleCount, (_winSize.width + 1) * (_winSize.height + 1), CV_32SC1); 10 + representation = _representation;
  11 + data.create((int)_maxSampleCount, representation->postWindowSize().area(), CV_32SC1);
14 cls.create( (int)_maxSampleCount, 1, CV_32FC1 ); 12 cls.create( (int)_maxSampleCount, 1, CV_32FC1 );
15 -  
16 - maxCatCount = 256;  
17 - featSize = 1;  
18 -  
19 - generateFeatures();  
20 } 13 }
21 14
22 void FeatureEvaluator::setImage(const Mat &img, uchar clsLabel, int idx) 15 void FeatureEvaluator::setImage(const Mat &img, uchar clsLabel, int idx)
23 { 16 {
24 - CV_Assert(img.cols == winSize.width);  
25 - CV_Assert(img.rows == winSize.height);  
26 - CV_Assert(idx < cls.rows);  
27 cls.ptr<float>(idx)[0] = clsLabel; 17 cls.ptr<float>(idx)[0] = clsLabel;
28 - Mat integralImg(winSize.height + 1, winSize.width + 1, data.type(), data.ptr<int>(idx));  
29 - integral(img, integralImg);  
30 -}  
31 -  
32 -void FeatureEvaluator::writeFeatures(FileStorage &fs, const Mat &featureMap) const  
33 -{  
34 - _writeFeatures( features, fs, featureMap );  
35 -}  
36 18
37 -void FeatureEvaluator::generateFeatures()  
38 -{  
39 - int offset = winSize.width + 1;  
40 - for (int x = 0; x < winSize.width; x++)  
41 - for (int y = 0; y < winSize.height; y++)  
42 - for (int w = 1; w <= winSize.width / 3; w++)  
43 - for (int h = 1; h <= winSize.height / 3; h++)  
44 - if ((x+3*w <= winSize.width) && (y+3*h <= winSize.height))  
45 - features.push_back(Feature(offset, x, y, w, h ));  
46 - numFeatures = (int)features.size(); 19 + Mat integralImg(representation->postWindowSize(), data.type(), data.ptr<int>(idx));
  20 + representation->preprocess(img, integralImg);
47 } 21 }
48 22
49 -FeatureEvaluator::Feature::Feature()  
50 -{  
51 - rect = cvRect(0, 0, 0, 0);  
52 -}  
53 -  
54 -FeatureEvaluator::Feature::Feature( int offset, int x, int y, int _blockWidth, int _blockHeight )  
55 -{  
56 - Rect tr = rect = cvRect(x, y, _blockWidth, _blockHeight);  
57 - CV_SUM_OFFSETS( p[0], p[1], p[4], p[5], tr, offset )  
58 - tr.x += 2*rect.width;  
59 - CV_SUM_OFFSETS( p[2], p[3], p[6], p[7], tr, offset )  
60 - tr.y +=2*rect.height;  
61 - CV_SUM_OFFSETS( p[10], p[11], p[14], p[15], tr, offset )  
62 - tr.x -= 2*rect.width;  
63 - CV_SUM_OFFSETS( p[8], p[9], p[12], p[13], tr, offset )  
64 -}  
65 -  
66 -void FeatureEvaluator::Feature::write(FileStorage &fs) const 23 +void FeatureEvaluator::writeFeatures(FileStorage &fs, const Mat &featureMap) const
67 { 24 {
68 - fs << CC_RECT << "[:" << rect.x << rect.y << rect.width << rect.height << "]"; 25 + representation->write(fs, featureMap);
69 } 26 }
openbr/core/features.h
@@ -48,90 +48,28 @@ @@ -48,90 +48,28 @@
48 #define TIME( arg ) (time( arg )) 48 #define TIME( arg ) (time( arg ))
49 #endif 49 #endif
50 50
51 -#define CV_SUM_OFFSETS( p0, p1, p2, p3, rect, step ) \  
52 - /* (x, y) */ \  
53 - (p0) = (rect).x + (step) * (rect).y; \  
54 - /* (x + w, y) */ \  
55 - (p1) = (rect).x + (rect).width + (step) * (rect).y; \  
56 - /* (x + w, y) */ \  
57 - (p2) = (rect).x + (step) * ((rect).y + (rect).height); \  
58 - /* (x + w, y + h) */ \  
59 - (p3) = (rect).x + (rect).width + (step) * ((rect).y + (rect).height);  
60 -  
61 namespace br 51 namespace br
62 { 52 {
63 53
64 -template<class Feature>  
65 -void _writeFeatures( const std::vector<Feature> features, cv::FileStorage &fs, const cv::Mat& featureMap )  
66 -{  
67 - fs << CC_FEATURES << "[";  
68 - const cv::Mat_<int>& featureMap_ = (const cv::Mat_<int>&)featureMap;  
69 - for ( int fi = 0; fi < featureMap.cols; fi++ )  
70 - if ( featureMap_(0, fi) >= 0 )  
71 - {  
72 - fs << "{";  
73 - features[fi].write( fs );  
74 - fs << "}";  
75 - }  
76 - fs << "]";  
77 -}  
78 -  
79 class FeatureEvaluator 54 class FeatureEvaluator
80 { 55 {
81 public: 56 public:
82 ~FeatureEvaluator() {} 57 ~FeatureEvaluator() {}
83 - void init(int _maxSampleCount, cv::Size _winSize); 58 + void init(Representation *_representation, int _maxSampleCount);
84 void setImage(const cv::Mat& img, uchar clsLabel, int idx); 59 void setImage(const cv::Mat& img, uchar clsLabel, int idx);
85 void writeFeatures(cv::FileStorage &fs, const cv::Mat& featureMap) const; 60 void writeFeatures(cv::FileStorage &fs, const cv::Mat& featureMap) const;
86 - float operator()(int featureIdx, int sampleIdx) const { return (float)features[featureIdx].calc(data, sampleIdx); } 61 + float operator()(int featureIdx, int sampleIdx) const { return representation->evaluate(data.row(sampleIdx), featureIdx); }
87 62
88 - int getNumFeatures() const { return numFeatures; }  
89 - int getMaxCatCount() const { return maxCatCount; }  
90 - int getFeatureSize() const { return featSize; } 63 + int getNumFeatures() const { return representation->numFeatures(); }
  64 + int getMaxCatCount() const { return representation->maxCatCount(); }
  65 + int getFeatureSize() const { return 1; }
91 const cv::Mat& getCls() const { return cls; } 66 const cv::Mat& getCls() const { return cls; }
92 float getCls(int si) const { return cls.at<float>(si, 0); } 67 float getCls(int si) const { return cls.at<float>(si, 0); }
93 68
94 -protected:  
95 - void generateFeatures();  
96 -  
97 - class Feature  
98 - {  
99 - public:  
100 - Feature();  
101 - Feature( int offset, int x, int y, int _block_w, int _block_h );  
102 - uchar calc( const cv::Mat &data, int y ) const;  
103 - void write( cv::FileStorage &fs ) const;  
104 -  
105 - cv::Rect rect;  
106 - int p[16];  
107 - };  
108 - std::vector<Feature> features;  
109 -  
110 cv::Mat data, cls; 69 cv::Mat data, cls;
111 -  
112 - int npos, nneg;  
113 - int numFeatures;  
114 - int maxCatCount; // 0 in case of numerical features  
115 - int featSize; // 1 in case of simple features (HAAR, LBP) and N_BINS(9)*N_CELLS(4) in case of Dalal's HOG features  
116 -  
117 - cv::Size winSize; 70 + Representation *representation;
118 }; 71 };
119 72
120 -inline uchar FeatureEvaluator::Feature::calc(const cv::Mat &data, int y) const  
121 -{  
122 - const int* ptr = data.ptr<int>(y);  
123 - int cval = ptr[p[5]] - ptr[p[6]] - ptr[p[9]] + ptr[p[10]];  
124 -  
125 - return (uchar)((ptr[p[0]] - ptr[p[1]] - ptr[p[4]] + ptr[p[5]] >= cval ? 128 : 0) | // 0  
126 - (ptr[p[1]] - ptr[p[2]] - ptr[p[5]] + ptr[p[6]] >= cval ? 64 : 0) | // 1  
127 - (ptr[p[2]] - ptr[p[3]] - ptr[p[6]] + ptr[p[7]] >= cval ? 32 : 0) | // 2  
128 - (ptr[p[6]] - ptr[p[7]] - ptr[p[10]] + ptr[p[11]] >= cval ? 16 : 0) | // 5  
129 - (ptr[p[10]] - ptr[p[11]] - ptr[p[14]] + ptr[p[15]] >= cval ? 8 : 0) | // 8  
130 - (ptr[p[9]] - ptr[p[10]] - ptr[p[13]] + ptr[p[14]] >= cval ? 4 : 0) | // 7  
131 - (ptr[p[8]] - ptr[p[9]] - ptr[p[12]] + ptr[p[13]] >= cval ? 2 : 0) | // 6  
132 - (ptr[p[4]] - ptr[p[5]] - ptr[p[8]] + ptr[p[9]] >= cval ? 1 : 0)); // 3  
133 -}  
134 -  
135 } // namespace br 73 } // namespace br
136 74
137 #endif // FEATURE_H 75 #endif // FEATURE_H
openbr/openbr_plugin.h
@@ -1395,18 +1395,27 @@ class BR_EXPORT Representation : public Object @@ -1395,18 +1395,27 @@ class BR_EXPORT Representation : public Object
1395 { 1395 {
1396 Q_OBJECT 1396 Q_OBJECT
1397 1397
  1398 + Q_PROPERTY(int winWidth READ get_winWidth WRITE set_winWidth RESET reset_winWidth STORED false)
  1399 + Q_PROPERTY(int winHeight READ get_winHeight WRITE set_winHeight RESET reset_winHeight STORED false)
  1400 + BR_PROPERTY(int, winWidth, 24)
  1401 + BR_PROPERTY(int, winHeight, 24)
  1402 +
1398 public: 1403 public:
1399 virtual ~Representation() {} 1404 virtual ~Representation() {}
1400 1405
1401 static Representation *make(QString str, QObject *parent); /*!< \brief Make a representation from a string. */ 1406 static Representation *make(QString str, QObject *parent); /*!< \brief Make a representation from a string. */
1402 - virtual cv::Mat preprocess(const cv::Mat &image) const { return image; } 1407 + virtual void preprocess(const cv::Mat &src, cv::Mat &dst) const { dst = src; }
1403 virtual void train(const QList<cv::Mat> &images, const QList<float> &labels) { (void) images; (void)labels; } 1408 virtual void train(const QList<cv::Mat> &images, const QList<float> &labels) { (void) images; (void)labels; }
  1409 +
  1410 + virtual float evaluate(const cv::Mat &image, int idx) const = 0;
1404 // By convention, an empty indices list will result in all feature responses being calculated 1411 // By convention, an empty indices list will result in all feature responses being calculated
1405 // and returned. 1412 // and returned.
1406 virtual cv::Mat evaluate(const cv::Mat &image, const QList<int> &indices = QList<int>()) const = 0; 1413 virtual cv::Mat evaluate(const cv::Mat &image, const QList<int> &indices = QList<int>()) const = 0;
1407 1414
  1415 + virtual cv::Size preWindowSize() const = 0; // window size before preprocessing
  1416 + virtual cv::Size postWindowSize() const = 0; // window size after preprocessing
1408 virtual int numFeatures() const = 0; 1417 virtual int numFeatures() const = 0;
1409 - virtual cv::Size windowSize() const = 0; 1418 + virtual int maxCatCount() const = 0;
1410 1419
1411 // Temporary for OpenCV compatibility 1420 // Temporary for OpenCV compatibility
1412 virtual void write( cv::FileStorage &fs, const cv::Mat &featureMap ) { (void)fs; (void)featureMap; } 1421 virtual void write( cv::FileStorage &fs, const cv::Mat &featureMap ) { (void)fs; (void)featureMap; }
@@ -1421,12 +1430,20 @@ public: @@ -1421,12 +1430,20 @@ public:
1421 1430
1422 static Classifier *make(QString str, QObject *parent); /*!< \brief Make a classifier from a string. */ 1431 static Classifier *make(QString str, QObject *parent); /*!< \brief Make a classifier from a string. */
1423 1432
1424 - virtual Classifier *clone() const { return Factory<Classifier>::make("." + description(false)); }  
1425 -  
1426 virtual void train(const QList<cv::Mat> &images, const QList<float> &labels) = 0; 1433 virtual void train(const QList<cv::Mat> &images, const QList<float> &labels) = 0;
1427 // By convention, classify should return a value normalized such that the threshold is 0. Negative values 1434 // By convention, classify should return a value normalized such that the threshold is 0. Negative values
1428 // can be interpreted as a negative classification and positive values as a positive classification. 1435 // can be interpreted as a negative classification and positive values as a positive classification.
1429 virtual float classify(const cv::Mat &image) const = 0; 1436 virtual float classify(const cv::Mat &image) const = 0;
  1437 +
  1438 + // Slots for representation
  1439 + virtual cv::Size windowSize() const = 0;
  1440 +
  1441 + // OpenCV compatibility
  1442 + virtual int numFeatures() const = 0;
  1443 + virtual int maxCatCount() const = 0;
  1444 + virtual void getUsedFeatures(cv::Mat &featureMap) const { (void)featureMap; return; }
  1445 + virtual void write(cv::FileStorage &fs, const cv::Mat &featureMap) const { (void)fs; (void)featureMap; }
  1446 + virtual void writeFeatures(cv::FileStorage &fs, const cv::Mat &featureMap) const { (void)fs; (void)featureMap; }
1430 }; 1447 };
1431 1448
1432 /*! 1449 /*!
openbr/plugins/classification/boostedforest.cpp
@@ -11,12 +11,14 @@ class BoostedForestClassifier : public Classifier @@ -11,12 +11,14 @@ class BoostedForestClassifier : public Classifier
11 { 11 {
12 Q_OBJECT 12 Q_OBJECT
13 13
  14 + Q_PROPERTY(br::Representation *representation READ get_representation WRITE set_representation RESET reset_representation STORED false)
14 Q_PROPERTY(float minTAR READ get_minTAR WRITE set_minTAR RESET reset_minTAR STORED false) 15 Q_PROPERTY(float minTAR READ get_minTAR WRITE set_minTAR RESET reset_minTAR STORED false)
15 Q_PROPERTY(float maxFAR READ get_maxFAR WRITE set_maxFAR RESET reset_maxFAR STORED false) 16 Q_PROPERTY(float maxFAR READ get_maxFAR WRITE set_maxFAR RESET reset_maxFAR STORED false)
16 Q_PROPERTY(float trimRate READ get_trimRate WRITE set_trimRate RESET reset_trimRate STORED false) 17 Q_PROPERTY(float trimRate READ get_trimRate WRITE set_trimRate RESET reset_trimRate STORED false)
17 Q_PROPERTY(int maxDepth READ get_maxDepth WRITE set_maxDepth RESET reset_maxDepth STORED false) 18 Q_PROPERTY(int maxDepth READ get_maxDepth WRITE set_maxDepth RESET reset_maxDepth STORED false)
18 Q_PROPERTY(int maxWeakCount READ get_maxWeakCount WRITE set_maxWeakCount RESET reset_maxWeakCount STORED false) 19 Q_PROPERTY(int maxWeakCount READ get_maxWeakCount WRITE set_maxWeakCount RESET reset_maxWeakCount STORED false)
19 20
  21 + BR_PROPERTY(br::Representation *, representation, NULL)
20 BR_PROPERTY(float, minTAR, 0.995) 22 BR_PROPERTY(float, minTAR, 0.995)
21 BR_PROPERTY(float, maxFAR, 0.5) 23 BR_PROPERTY(float, maxFAR, 0.5)
22 BR_PROPERTY(float, trimRate, 0.95) 24 BR_PROPERTY(float, trimRate, 0.95)
@@ -24,16 +26,56 @@ class BoostedForestClassifier : public Classifier @@ -24,16 +26,56 @@ class BoostedForestClassifier : public Classifier
24 BR_PROPERTY(int, maxWeakCount, 100) 26 BR_PROPERTY(int, maxWeakCount, 100)
25 27
26 CascadeBoost *boost; 28 CascadeBoost *boost;
  29 + FeatureEvaluator *featureEvaluator;
27 30
28 void train(const QList<Mat> &images, const QList<float> &labels) 31 void train(const QList<Mat> &images, const QList<float> &labels)
29 { 32 {
30 - (void)images; (void)labels; 33 + CascadeBoostParams params(CvBoost::GENTLE, minTAR, maxFAR, trimRate, maxDepth, maxWeakCount);
  34 +
  35 + featureEvaluator = new FeatureEvaluator;
  36 + featureEvaluator->init(representation, images.size());
  37 +
  38 + for (int i = 0; i < images.size(); i++)
  39 + featureEvaluator->setImage(images[i], labels[i], i);
  40 +
  41 + boost = new CascadeBoost;
  42 + boost->train(featureEvaluator, images.size(), 1024, 1024, params);
31 } 43 }
32 44
33 float classify(const Mat &image) const 45 float classify(const Mat &image) const
34 { 46 {
35 - (void) image;  
36 - return 0.; 47 + featureEvaluator->setImage(image, 0, 0);
  48 + return boost->predict(0);
  49 + }
  50 +
  51 + int numFeatures() const
  52 + {
  53 + return representation->numFeatures();
  54 + }
  55 +
  56 + int maxCatCount() const
  57 + {
  58 + return representation->maxCatCount();
  59 + }
  60 +
  61 + Size windowSize() const
  62 + {
  63 + return representation->preWindowSize();
  64 + }
  65 +
  66 + void getUsedFeatures(Mat &featureMap) const
  67 + {
  68 + boost->markUsedFeaturesInMap(featureMap);
  69 + }
  70 +
  71 + void write(FileStorage &fs, const Mat &featureMap) const
  72 + {
  73 + boost->write(fs, featureMap);
  74 + }
  75 +
  76 + void writeFeatures(FileStorage &fs, const Mat &featureMap) const
  77 + {
  78 + featureEvaluator->writeFeatures(fs, featureMap);
37 } 79 }
38 }; 80 };
39 81
openbr/plugins/classification/cascade.cpp
1 #include <openbr/plugins/openbr_internal.h> 1 #include <openbr/plugins/openbr_internal.h>
2 -#include <openbr/core/cascade.h> 2 +#include <openbr/core/features.h>
  3 +#include <openbr/core/boost.h>
3 4
4 using namespace cv; 5 using namespace cv;
5 6
6 namespace br 7 namespace br
7 { 8 {
8 9
  10 +struct ImageHandler
  11 +{
  12 + bool create( const QList<cv::Mat> &_posImages, const QList<cv::Mat> &_negImages, cv::Size _winSize )
  13 + {
  14 + posImages = _posImages;
  15 + negImages = _negImages;
  16 + winSize = _winSize;
  17 +
  18 + posIdx = negIdx = 0;
  19 +
  20 + src.create( 0, 0 , CV_8UC1 );
  21 + img.create( 0, 0, CV_8UC1 );
  22 + point = offset = Point( 0, 0 );
  23 + scale = 1.0F;
  24 + scaleFactor = 1.4142135623730950488016887242097F;
  25 + stepFactor = 0.5F;
  26 + round = 0;
  27 +
  28 + return true;
  29 + }
  30 +
  31 + void restart() { posIdx = 0; }
  32 +
  33 + int numPos() const { return posImages.size(); }
  34 + int numNeg() const { return negImages.size(); }
  35 +
  36 + bool nextNeg()
  37 + {
  38 + Point _offset = Point(0,0);
  39 + size_t count = negImages.size();
  40 + for (size_t i = 0; i < count; i++) {
  41 + src = negImages[negIdx++];
  42 + if( src.empty() )
  43 + continue;
  44 + round += negIdx / count;
  45 + round = round % (winSize.width * winSize.height);
  46 + negIdx %= count;
  47 +
  48 + _offset.x = std::min( (int)round % winSize.width, src.cols - winSize.width );
  49 + _offset.y = std::min( (int)round / winSize.width, src.rows - winSize.height );
  50 + if( !src.empty() && src.type() == CV_8UC1 && _offset.x >= 0 && _offset.y >= 0 )
  51 + break;
  52 + }
  53 +
  54 + if( src.empty() )
  55 + return false; // no appropriate image
  56 + point = offset = _offset;
  57 + scale = max( ((float)winSize.width + point.x) / ((float)src.cols),
  58 + ((float)winSize.height + point.y) / ((float)src.rows) );
  59 +
  60 + Size sz( (int)(scale*src.cols + 0.5F), (int)(scale*src.rows + 0.5F) );
  61 + resize( src, img, sz );
  62 + return true;
  63 + }
  64 +
  65 + bool getNeg(cv::Mat &_img)
  66 + {
  67 + if( img.empty() )
  68 + if ( !nextNeg() )
  69 + return false;
  70 +
  71 + Mat mat( winSize.height, winSize.width, CV_8UC1,
  72 + (void*)(img.data + point.y * img.step + point.x * img.elemSize()), img.step );
  73 + mat.copyTo(_img);
  74 +
  75 + if( (int)( point.x + (1.0F + stepFactor ) * winSize.width ) < img.cols )
  76 + point.x += (int)(stepFactor * winSize.width);
  77 + else
  78 + {
  79 + point.x = offset.x;
  80 + if( (int)( point.y + (1.0F + stepFactor ) * winSize.height ) < img.rows )
  81 + point.y += (int)(stepFactor * winSize.height);
  82 + else
  83 + {
  84 + point.y = offset.y;
  85 + scale *= scaleFactor;
  86 + if( scale <= 1.0F )
  87 + resize( src, img, Size( (int)(scale*src.cols), (int)(scale*src.rows) ) );
  88 + else
  89 + {
  90 + if ( !nextNeg() )
  91 + return false;
  92 + }
  93 + }
  94 + }
  95 + return true;
  96 + }
  97 +
  98 + bool getPos(cv::Mat &_img)
  99 + {
  100 + if (posIdx >= posImages.size())
  101 + return false;
  102 +
  103 + posImages[posIdx++].copyTo(_img);
  104 + return true;
  105 + }
  106 +
  107 + QList<cv::Mat> posImages, negImages;
  108 +
  109 + int posIdx, negIdx;
  110 +
  111 + cv::Mat src, img;
  112 + cv::Point offset, point;
  113 + float scale;
  114 + float scaleFactor;
  115 + float stepFactor;
  116 + size_t round;
  117 + cv::Size winSize;
  118 +};
  119 +
9 class _CascadeClassifier : public Classifier 120 class _CascadeClassifier : public Classifier
10 { 121 {
11 Q_OBJECT 122 Q_OBJECT
12 123
13 - Q_PROPERTY(br::Classifier *stage READ get_stage WRITE set_stage RESET reset_stage STORED false) 124 + Q_PROPERTY(QString stageDescription READ get_stageDescription WRITE set_stageDescription RESET reset_stageDescription STORED false)
14 Q_PROPERTY(int numStages READ get_numStages WRITE set_numStages RESET reset_numStages STORED false) 125 Q_PROPERTY(int numStages READ get_numStages WRITE set_numStages RESET reset_numStages STORED false)
  126 + Q_PROPERTY(int numPos READ get_numPos WRITE set_numPos RESET reset_numPos STORED false)
15 Q_PROPERTY(int numNegs READ get_numNegs WRITE set_numNegs RESET reset_numNegs STORED false) 127 Q_PROPERTY(int numNegs READ get_numNegs WRITE set_numNegs RESET reset_numNegs STORED false)
16 Q_PROPERTY(float maxFAR READ get_maxFAR WRITE set_maxFAR RESET reset_maxFAR STORED false) 128 Q_PROPERTY(float maxFAR READ get_maxFAR WRITE set_maxFAR RESET reset_maxFAR STORED false)
17 129
18 - BR_PROPERTY(br::Classifier *, stage, NULL) 130 + BR_PROPERTY(QString, stageDescription, "")
19 BR_PROPERTY(int, numStages, 20) 131 BR_PROPERTY(int, numStages, 20)
  132 + BR_PROPERTY(int, numPos, 1000)
20 BR_PROPERTY(int, numNegs, 1000) 133 BR_PROPERTY(int, numNegs, 1000)
21 BR_PROPERTY(float, maxFAR, pow(0.5, numStages)) 134 BR_PROPERTY(float, maxFAR, pow(0.5, numStages))
22 135
@@ -28,127 +141,132 @@ class _CascadeClassifier : public Classifier @@ -28,127 +141,132 @@ class _CascadeClassifier : public Classifier
28 for (int i = 0; i < images.size(); i++) 141 for (int i = 0; i < images.size(); i++)
29 labels[i] == 1 ? posImages.append(images[i]) : negImages.append(images[i]); 142 labels[i] == 1 ? posImages.append(images[i]) : negImages.append(images[i]);
30 143
31 - QList<Mat> trainingImages;  
32 - QList<float> trainingLabels; 144 + ImageHandler imgHandler;
  145 + imgHandler.create(posImages, negImages, Size(24, 24));
33 146
  147 + stages.reserve(numStages);
34 for (int i = 0; i < numStages; i++) { 148 for (int i = 0; i < numStages; i++) {
35 - float currFAR = updateTrainingSet(posImages, negImages, trainingImages, trainingLabels); 149 + qDebug() << "===== TRAINING" << i << "stage =====";
  150 + qDebug() << "<BEGIN";
  151 +
  152 + QList<Mat> trainingImages;
  153 + QList<float> trainingLabels;
  154 +
  155 + float currFAR = fillTrainingSet(imgHandler, trainingImages, trainingLabels);
36 156
37 if (currFAR < maxFAR) { 157 if (currFAR < maxFAR) {
38 qDebug() << "FAR is below required level! Terminating early"; 158 qDebug() << "FAR is below required level! Terminating early";
39 return; 159 return;
40 } 160 }
41 161
42 - Classifier *next_stage = stage->clone(); 162 + Classifier *next_stage = Classifier::make(stageDescription, NULL);
43 next_stage->train(trainingImages, trainingLabels); 163 next_stage->train(trainingImages, trainingLabels);
44 stages.append(next_stage); 164 stages.append(next_stage);
  165 +
  166 + qDebug() << "END>";
45 } 167 }
46 } 168 }
47 169
48 float classify(const Mat &image) const 170 float classify(const Mat &image) const
49 { 171 {
50 - (void) image;  
51 - return 0.; 172 + foreach (const Classifier *stage, stages)
  173 + if (stage->classify(image) == 0.0f)
  174 + return 0.0f;
  175 + return 1.0f;
52 } 176 }
53 177
54 - float updateTrainingSet(const QList<Mat> &posImages, const QList<Mat> &negImages, QList<Mat> &trainingImages, QList<float> &trainingLabels) 178 + int numFeatures() const
55 { 179 {
56 - trainingImages.clear();  
57 - trainingLabels.clear(); 180 + return stages.first()->numFeatures();
  181 + }
58 182
59 - foreach (const Mat &pos, posImages) {  
60 - if (classify(pos) > 0) {  
61 - trainingImages.append(pos);  
62 - trainingLabels.append(1.);  
63 - }  
64 - } 183 + int maxCatCount() const
  184 + {
  185 + return stages.first()->maxCatCount();
  186 + }
65 187
66 - NegFinder finder(negImages, Size(24, 24));  
67 - int totalNegs = 0, passedNegs = 0;  
68 - while (true) {  
69 - totalNegs++;  
70 - Mat neg = finder.get();  
71 - if (classify(neg) > 0) {  
72 - trainingImages.append(neg);  
73 - trainingLabels.append(0.);  
74 - passedNegs++;  
75 - } 188 + cv::Size windowSize() const
  189 + {
  190 + return stages.first()->windowSize();
  191 + }
76 192
77 - if (passedNegs >= numNegs)  
78 - return passedNegs / (float)totalNegs;  
79 - } 193 + void getUsedFeatures(Mat &featureMap) const
  194 + {
  195 + foreach (const Classifier *stage, stages)
  196 + stage->getUsedFeatures(featureMap);
80 } 197 }
81 198
82 -private:  
83 - struct NegFinder 199 + void write(FileStorage &fs, const Mat &featureMap) const
84 { 200 {
85 - NegFinder(const QList<Mat> &_negs, Size _winSize)  
86 - {  
87 - negs = _negs;  
88 - winSize = _winSize;  
89 -  
90 - negIdx = round = 0;  
91 - img.create( 0, 0, CV_8UC1 );  
92 - point = offset = Point( 0, 0 );  
93 - scale = 1.0F;  
94 - scaleFactor = 1.4142135623730950488016887242097F;  
95 - stepFactor = 0.5F;  
96 - } 201 + fs << CC_STAGE_TYPE << CC_BOOST;
  202 + fs << CC_FEATURE_TYPE << CC_LBP;
  203 + fs << CC_HEIGHT << 24;
  204 + fs << CC_WIDTH << 24;
97 205
98 - void _next()  
99 - {  
100 - src = negs[negIdx++]; 206 + CascadeBoostParams stageParams(CvBoost::GINI, 0.999, 0.5, 0.95, 1, 200);
  207 + fs << CC_STAGE_PARAMS << "{"; stageParams.write( fs ); fs << "}";
  208 +
  209 + fs << CC_FEATURE_PARAMS << "{";
  210 + fs << CC_MAX_CAT_COUNT << stages.first()->maxCatCount();
  211 + fs << CC_FEATURE_SIZE << 1;
  212 + fs << "}";
  213 +
  214 + fs << CC_STAGE_NUM << stages.size();
  215 +
  216 + char cmnt[30];
  217 + int i = 0;
  218 + fs << CC_STAGES << "[";
  219 + foreach (const Classifier *stage, stages) {
  220 + sprintf( cmnt, "stage %d", i );
  221 + cvWriteComment( fs.fs, cmnt, 0 );
  222 + fs << "{";
  223 + stage->write(fs, featureMap);
  224 + fs << "}";
  225 + }
  226 + fs << "]";
  227 + }
101 228
102 - round += negIdx / negs.size();  
103 - round %= (winSize.width * winSize.height);  
104 - negIdx %= negs.size(); 229 + void writeFeatures(FileStorage &fs, const Mat& featureMap) const
  230 + {
  231 + stages.first()->writeFeatures(fs, featureMap);
  232 + }
105 233
106 - point = offset = Point(std::min(round % winSize.width, src.cols - winSize.width),  
107 - std::min(round / winSize.width, src.rows - winSize.height)); 234 +private:
  235 + float fillTrainingSet(ImageHandler &imgHandler, QList<Mat> &images, QList<float> &labels)
  236 + {
  237 + imgHandler.restart();
108 238
109 - scale = max(((float)winSize.width + point.x) / ((float)src.cols),  
110 - ((float)winSize.height + point.y) / ((float)src.rows)); 239 + while (images.size() < numPos) {
  240 + Mat pos(imgHandler.winSize, CV_8UC1);
  241 + if (!imgHandler.getPos(pos))
  242 + qFatal("Cannot get another positive sample!");
111 243
112 - Size sz((int)(scale*src.cols + 0.5F), (int)(scale*src.rows + 0.5F));  
113 - resize(src, img, sz); 244 + if (classify(pos) == 1.0f) {
  245 + images.append(pos);
  246 + labels.append(1.0f);
  247 + }
114 } 248 }
115 249
116 - Mat get()  
117 - {  
118 - if (img.empty())  
119 - _next();  
120 -  
121 - Mat neg(winSize, CV_8UC1);  
122 - Mat m(winSize.height, winSize.width, CV_8UC1, (void*)(img.data + point.y * img.step + point.x * img.elemSize()), img.step);  
123 - m.copyTo(neg);  
124 -  
125 - if ((int)(point.x + (1.0F + stepFactor ) * winSize.width) < img.cols)  
126 - point.x += (int)(stepFactor * winSize.width);  
127 - else {  
128 - point.x = offset.x;  
129 - if ((int)( point.y + (1.0F + stepFactor ) * winSize.height ) < img.rows)  
130 - point.y += (int)(stepFactor * winSize.height);  
131 - else {  
132 - point.y = offset.y;  
133 - scale *= scaleFactor;  
134 - if( scale <= 1.0F )  
135 - resize(src, img, Size( (int)(scale*src.cols), (int)(scale*src.rows)));  
136 - else  
137 - _next();  
138 - } 250 + int posCount = images.size();
  251 + qDebug() << "POS count : consumed " << posCount << ":" << imgHandler.posIdx;
  252 +
  253 + int passedNegs = 0;
  254 + while ((images.size() - posCount) < numNegs) {
  255 + Mat neg(imgHandler.winSize, CV_8UC1);
  256 + if (!imgHandler.getNeg(neg))
  257 + qFatal("Cannot get another negative sample!");
  258 +
  259 + if (classify(neg) == 1.0f) {
  260 + images.append(neg);
  261 + labels.append(0.0f);
139 } 262 }
140 - return neg; 263 + passedNegs++;
141 } 264 }
142 265
143 - QList<Mat> negs;  
144 - int negIdx, round;  
145 - Mat src, img;  
146 - float scale;  
147 - float scaleFactor;  
148 - float stepFactor;  
149 - Size winSize;  
150 - Point offset, point;  
151 - }; 266 + double acceptanceRatio = (images.size() - posCount) / (double)passedNegs;
  267 + qDebug() << "NEG count : acceptanceRatio " << images.size() - posCount << ":" << acceptanceRatio;
  268 + return acceptanceRatio;
  269 + }
152 }; 270 };
153 271
154 BR_REGISTER(Classifier, _CascadeClassifier) 272 BR_REGISTER(Classifier, _CascadeClassifier)
openbr/plugins/imgproc/slidingwindow.cpp
@@ -26,63 +26,27 @@ using namespace cv; @@ -26,63 +26,27 @@ using namespace cv;
26 26
27 namespace br 27 namespace br
28 { 28 {
29 -/*  
30 -class CascadeResourceMaker : public ResourceMaker<CascadeClassifier>  
31 -{  
32 - QString file;  
33 -  
34 -public:  
35 - CascadeResourceMaker(const QString &model)  
36 - {  
37 - file = Globals->sdkPath + "/share/openbr/models/";  
38 - if (model == "Ear") file += "haarcascades/haarcascade_ear.xml";  
39 - else if (model == "Eye") file += "haarcascades/haarcascade_eye_tree_eyeglasses.xml";  
40 - else if (model == "FrontalFace") file += "haarcascades/haarcascade_frontalface_alt2.xml";  
41 - else if (model == "ProfileFace") file += "haarcascades/haarcascade_profileface.xml";  
42 - else {  
43 - // Create a directory for trainable cascades  
44 - file += "openbrcascades/"+model+"/cascade.xml";  
45 - QFile touchFile(file);  
46 - QtUtils::touchDir(touchFile);  
47 - }  
48 - }  
49 29
50 -private:  
51 - CascadeClassifier *make() const  
52 - {  
53 - CascadeClassifier *cascade = new CascadeClassifier();  
54 - if (!cascade->load(file.toStdString()))  
55 - qFatal("Failed to load: %s", qPrintable(file));  
56 - return cascade;  
57 - }  
58 -};  
59 -*/  
60 /*! 30 /*!
61 * \ingroup transforms 31 * \ingroup transforms
62 * \brief Applies a classifier to a sliding window. 32 * \brief Applies a classifier to a sliding window.
63 * Discards negative detections. 33 * Discards negative detections.
64 * \author Jordan Cheney \cite JordanCheney 34 * \author Jordan Cheney \cite JordanCheney
65 */ 35 */
66 - /* 36 +
67 class SlidingWindowTransform : public Transform 37 class SlidingWindowTransform : public Transform
68 { 38 {
69 Q_OBJECT 39 Q_OBJECT
70 40
71 Q_PROPERTY(br::Classifier *classifier READ get_classifier WRITE set_classifier RESET reset_classifier STORED false) 41 Q_PROPERTY(br::Classifier *classifier READ get_classifier WRITE set_classifier RESET reset_classifier STORED false)
  42 + Q_PROPERTY(QString cascadeDir READ get_cascadeDir WRITE set_cascadeDir RESET reset_cascadeDir STORED false)
72 Q_PROPERTY(QString vecFile READ get_vecFile WRITE set_vecFile RESET reset_vecFile STORED false) 43 Q_PROPERTY(QString vecFile READ get_vecFile WRITE set_vecFile RESET reset_vecFile STORED false)
73 Q_PROPERTY(QString negFile READ get_negFile WRITE set_negFile RESET reset_negFile STORED false) 44 Q_PROPERTY(QString negFile READ get_negFile WRITE set_negFile RESET reset_negFile STORED false)
74 - Q_PROPERTY(int minSize READ get_minSize WRITE set_minSize RESET reset_minSize STORED false)  
75 - Q_PROPERTY(int maxSize READ get_maxSize WRITE set_maxSize RESET reset_maxSize STORED false)  
76 - Q_PROPERTY(float scaleFactor READ get_scaleFactor WRITE set_scaleFactor RESET reset_scaleFactor STORED false)  
77 45
78 BR_PROPERTY(br::Classifier *, classifier, NULL) 46 BR_PROPERTY(br::Classifier *, classifier, NULL)
  47 + BR_PROPERTY(QString, cascadeDir, "")
79 BR_PROPERTY(QString, vecFile, "vec.vec") 48 BR_PROPERTY(QString, vecFile, "vec.vec")
80 BR_PROPERTY(QString, negFile, "neg.txt") 49 BR_PROPERTY(QString, negFile, "neg.txt")
81 - BR_PROPERTY(int, minSize, 20)  
82 - BR_PROPERTY(int, maxSize, -1)  
83 - BR_PROPERTY(float, scaleFactor, 1.2)  
84 -  
85 - Resource<CascadeClassifier> cascadeResource;  
86 50
87 QList<Mat> getPos() 51 QList<Mat> getPos()
88 { 52 {
@@ -159,9 +123,7 @@ class SlidingWindowTransform : public Transform @@ -159,9 +123,7 @@ class SlidingWindowTransform : public Transform
159 123
160 void init() 124 void init()
161 { 125 {
162 - cascadeResource.setResourceMaker(new CascadeResourceMaker(model));  
163 - if (model == "Ear" || model == "Eye" || model == "FrontalFace" || model == "ProfileFace")  
164 - this->trainable = false; 126 + cascadeDir = Globals->sdkPath + "/share/openbr/models/openbrcascades/" + cascadeDir;
165 } 127 }
166 128
167 void train(const TemplateList &_data) 129 void train(const TemplateList &_data)
@@ -183,118 +145,38 @@ class SlidingWindowTransform : public Transform @@ -183,118 +145,38 @@ class SlidingWindowTransform : public Transform
183 } 145 }
184 146
185 classifier->train(images, labels); 147 classifier->train(images, labels);
186 - }  
187 148
188 - void project(const Template &src, Template &dst) const  
189 - {  
190 - TemplateList temp;  
191 - project(TemplateList() << src, temp);  
192 - if (!temp.isEmpty()) dst = temp.first(); 149 + // save the cascade
  150 + std::string filename = cascadeDir.toStdString() + "/cascade.xml";
  151 + FileStorage fs(filename, FileStorage::WRITE );
  152 +
  153 + if ( !fs.isOpened() )
  154 + return;
  155 +
  156 + fs << FileStorage::getDefaultObjectName(filename) << "{";
  157 +
  158 + Mat featureMap(1, classifier->numFeatures(), CV_32SC1);
  159 + featureMap.setTo(Scalar(-1));
  160 +
  161 + classifier->getUsedFeatures(featureMap);
  162 +
  163 + for (int fi = 0, idx = 0; fi < classifier->numFeatures(); fi++)
  164 + if (featureMap.at<int>(0, fi) >= 0)
  165 + featureMap.ptr<int>(0)[fi] = idx++;
  166 +
  167 + classifier->write(fs, featureMap);
  168 + classifier->writeFeatures(fs, featureMap);
  169 +
  170 + fs << "}";
193 } 171 }
194 172
195 - void project(const TemplateList &src, TemplateList &dst) const 173 + void project(const Template &src, Template &dst) const
196 { 174 {
197 - CascadeClassifier *cascade = cascadeResource.acquire();  
198 - foreach (const Template &t, src) {  
199 - const bool enrollAll = t.file.getBool("enrollAll");  
200 -  
201 - // Mirror the behavior of ExpandTransform in the special case  
202 - // of an empty template.  
203 - if (t.empty() && !enrollAll) {  
204 - dst.append(t);  
205 - continue;  
206 - }  
207 -  
208 - for (int i=0; i<t.size(); i++) {  
209 - Mat m;  
210 - OpenCVUtils::cvtUChar(t[i], m);  
211 -  
212 - Size maxSize(m.cols, m.rows);  
213 -  
214 - Mat imageBuffer(m.rows + 1, m.cols + 1, CV_8U);  
215 -  
216 - QList<Rect> rects;  
217 - QList<int> levels;  
218 - QList<double> weights;  
219 -  
220 - for (double factor = 1; ; factor *= 1.2) {  
221 - Size originalWindowSize = Size(winWidth, winHeight);  
222 -  
223 - Size windowSize( cvRound(originalWindowSize.width*factor), cvRound(originalWindowSize.height*factor) );  
224 - Size scaledImageSize( cvRound( m.cols/factor ), cvRound( m.rows/factor ) );  
225 - Size processingRectSize( scaledImageSize.width - originalWindowSize.width, scaledImageSize.height - originalWindowSize.height );  
226 -  
227 - if( processingRectSize.width <= 0 || processingRectSize.height <= 0 )  
228 - break;  
229 - if( windowSize.width > maxSize.width || windowSize.height > maxSize.height )  
230 - break;  
231 - if( windowSize.width < minSize || windowSize.height < minSize )  
232 - continue;  
233 -  
234 - Mat scaledImage( scaledImageSize, CV_8U, imageBuffer.data );  
235 - resize( m, scaledImage, scaledImageSize, 0, 0, CV_INTER_LINEAR );  
236 -  
237 - int yStep = factor > 2. ? 1 : 2;  
238 - int stripCount, stripSize;  
239 -  
240 - const int PTS_PER_THREAD = 1000;  
241 - stripCount = ((processingRectSize.width/yStep)*(processingRectSize.height + yStep-1)/yStep + PTS_PER_THREAD/2)/PTS_PER_THREAD;  
242 - stripCount = std::min(std::max(stripCount, 1), 100);  
243 - stripSize = (((processingRectSize.height + stripCount - 1)/stripCount + yStep-1)/yStep)*yStep;  
244 -  
245 - if( !cascade->setImage( scaledImage ) )  
246 - qFatal("Can't set an image. Don't know why");  
247 -  
248 - for( int y = 0; y < min(stripCount * stripSize, processingRectSize.height); y += yStep ) {  
249 - for( int x = 0; x < processingRectSize.width; x += yStep ) {  
250 - double gypWeight;  
251 - int result = cascade->runAt(cascade->featureEvaluator, Point(x, y), gypWeight);  
252 -  
253 - if (ROCMode) {  
254 - if (result == 1)  
255 - result = -(int)cascade->data.stages.size();  
256 - if (cascade->data.stages.size() + result < 4 ) {  
257 - rects.append(Rect(cvRound(x*factor), cvRound(y*factor), windowSize.width, windowSize.height));  
258 - levels.append(-result);  
259 - weights.append(gypWeight);  
260 - }  
261 - }  
262 - else if( result > 0 ) {  
263 - rects.append(Rect(cvRound(x*factor), cvRound(y*factor), windowSize.width, windowSize.height));  
264 - }  
265 - if( result == 0 )  
266 - x += yStep;  
267 - }  
268 - }  
269 - }  
270 -  
271 - if (ROCMode)  
272 - groupRectangles(rects, levels, weights, minNeighbors, 0.2);  
273 - else  
274 - groupRectangles(rects, minNeighbors, 0.2);  
275 -  
276 - if (!enrollAll && rects.empty())  
277 - rects.append(Rect(0, 0, m.cols, m.rows));  
278 -  
279 - for (int j = 0; j < rects.size(); j++) {  
280 - Template u(t.file, m);  
281 - if (levels.size() > j)  
282 - u.file.set("Confidence", levels[j]*weights[j]);  
283 - else  
284 - u.file.set("Confidence", 1);  
285 - const QRectF rect = OpenCVUtils::fromRect(rects[j]);  
286 - u.file.appendRect(rect);  
287 - u.file.set(model, rect);  
288 - dst.append(u);  
289 - }  
290 - }  
291 - }  
292 - cascadeResource.release(cascade); 175 + (void)src; (void)dst;
293 } 176 }
294 }; 177 };
295 178
296 BR_REGISTER(Transform, SlidingWindowTransform) 179 BR_REGISTER(Transform, SlidingWindowTransform)
297 -*/  
298 180
299 } // namespace br 181 } // namespace br
300 182
openbr/plugins/representation/mblbp.cpp
@@ -22,11 +22,6 @@ class MBLBPRepresentation : public Representation @@ -22,11 +22,6 @@ class MBLBPRepresentation : public Representation
22 { 22 {
23 Q_OBJECT 23 Q_OBJECT
24 24
25 - Q_PROPERTY(int winWidth READ get_winWidth WRITE set_winWidth RESET reset_winWidth STORED false)  
26 - Q_PROPERTY(int winHeight READ get_winHeight WRITE set_winHeight RESET reset_winHeight STORED false)  
27 - BR_PROPERTY(int, winWidth, 24)  
28 - BR_PROPERTY(int, winHeight, 24)  
29 -  
30 void init() 25 void init()
31 { 26 {
32 int offset = winWidth + 1; 27 int offset = winWidth + 1;
@@ -38,11 +33,14 @@ class MBLBPRepresentation : public Representation @@ -38,11 +33,14 @@ class MBLBPRepresentation : public Representation
38 features.append(Feature(offset, x, y, w, h ) ); 33 features.append(Feature(offset, x, y, w, h ) );
39 } 34 }
40 35
41 - Mat preprocess(const Mat &image) const 36 + void preprocess(const Mat &src, Mat &dst) const
  37 + {
  38 + integral(src, dst);
  39 + }
  40 +
  41 + float evaluate(const Mat &image, int idx) const
42 { 42 {
43 - Mat integralImage;  
44 - integral(image, integralImage);  
45 - return integralImage; 43 + return (float)features[idx].calc(image);
46 } 44 }
47 45
48 Mat evaluate(const Mat &image, const QList<int> &indices) const 46 Mat evaluate(const Mat &image, const QList<int> &indices) const
@@ -55,7 +53,9 @@ class MBLBPRepresentation : public Representation @@ -55,7 +53,9 @@ class MBLBPRepresentation : public Representation
55 53
56 void write(FileStorage &fs, const Mat &featureMap); 54 void write(FileStorage &fs, const Mat &featureMap);
57 int numFeatures() const { return features.size(); } 55 int numFeatures() const { return features.size(); }
58 - Size windowSize() const { return Size(winWidth + 1, winHeight + 1); } 56 + Size preWindowSize() const { return Size(winWidth, winHeight); }
  57 + Size postWindowSize() const { return Size(winWidth + 1, winHeight + 1); }
  58 + int maxCatCount() const { return 256; }
59 59
60 struct Feature 60 struct Feature
61 { 61 {
@@ -100,17 +100,17 @@ MBLBPRepresentation::Feature::Feature( int offset, int x, int y, int _blockWidth @@ -100,17 +100,17 @@ MBLBPRepresentation::Feature::Feature( int offset, int x, int y, int _blockWidth
100 100
101 inline uchar MBLBPRepresentation::Feature::calc(const Mat &img) const 101 inline uchar MBLBPRepresentation::Feature::calc(const Mat &img) const
102 { 102 {
103 - const int* psum = img.ptr<int>();  
104 - int cval = psum[p[5]] - psum[p[6]] - psum[p[9]] + psum[p[10]];  
105 -  
106 - return (uchar)((psum[p[0]] - psum[p[1]] - psum[p[4]] + psum[p[5]] >= cval ? 128 : 0) | // 0  
107 - (psum[p[1]] - psum[p[2]] - psum[p[5]] + psum[p[6]] >= cval ? 64 : 0) | // 1  
108 - (psum[p[2]] - psum[p[3]] - psum[p[6]] + psum[p[7]] >= cval ? 32 : 0) | // 2  
109 - (psum[p[6]] - psum[p[7]] - psum[p[10]] + psum[p[11]] >= cval ? 16 : 0) | // 5  
110 - (psum[p[10]] - psum[p[11]] - psum[p[14]] + psum[p[15]] >= cval ? 8 : 0) | // 8  
111 - (psum[p[9]] - psum[p[10]] - psum[p[13]] + psum[p[14]] >= cval ? 4 : 0) | // 7  
112 - (psum[p[8]] - psum[p[9]] - psum[p[12]] + psum[p[13]] >= cval ? 2 : 0) | // 6  
113 - (psum[p[4]] - psum[p[5]] - psum[p[8]] + psum[p[9]] >= cval ? 1 : 0)); // 3 103 + const int* ptr = img.ptr<int>();
  104 + int cval = ptr[p[5]] - ptr[p[6]] - ptr[p[9]] + ptr[p[10]];
  105 +
  106 + return (uchar)((ptr[p[0]] - ptr[p[1]] - ptr[p[4]] + ptr[p[5]] >= cval ? 128 : 0) | // 0
  107 + (ptr[p[1]] - ptr[p[2]] - ptr[p[5]] + ptr[p[6]] >= cval ? 64 : 0) | // 1
  108 + (ptr[p[2]] - ptr[p[3]] - ptr[p[6]] + ptr[p[7]] >= cval ? 32 : 0) | // 2
  109 + (ptr[p[6]] - ptr[p[7]] - ptr[p[10]] + ptr[p[11]] >= cval ? 16 : 0) | // 5
  110 + (ptr[p[10]] - ptr[p[11]] - ptr[p[14]] + ptr[p[15]] >= cval ? 8 : 0) | // 8
  111 + (ptr[p[9]] - ptr[p[10]] - ptr[p[13]] + ptr[p[14]] >= cval ? 4 : 0) | // 7
  112 + (ptr[p[8]] - ptr[p[9]] - ptr[p[12]] + ptr[p[13]] >= cval ? 2 : 0) | // 6
  113 + (ptr[p[4]] - ptr[p[5]] - ptr[p[8]] + ptr[p[9]] >= cval ? 1 : 0)); // 3
114 } 114 }
115 115
116 } // namespace br 116 } // namespace br