From 12d23aae021dd0a195e1c242247f4a3ecd272b0e Mon Sep 17 00:00:00 2001
From: "marina.kolpakova" <marina.kolpakova@itseez.com>
Date: Fri, 1 Mar 2013 23:39:32 +0400
Subject: [PATCH] refactor channel builder fix condition for sample index in
 assert

---
 .../opencv2/softcascade/softcascade.hpp       |  9 ++--
 .../src/integral_channel_builder.cpp          | 42 ++++++++++---------
 .../softcascade/src/soft_cascade_octave.cpp   | 18 ++++----
 modules/softcascade/src/softcascade.cpp       | 22 ++++++----
 .../test/test_channel_features.cpp            |  4 +-
 modules/softcascade/test/test_training.cpp    |  5 ++-
 6 files changed, 57 insertions(+), 43 deletions(-)

diff --git a/modules/softcascade/include/opencv2/softcascade/softcascade.hpp b/modules/softcascade/include/opencv2/softcascade/softcascade.hpp
index 6e405af077..fc987afa3e 100644
--- a/modules/softcascade/include/opencv2/softcascade/softcascade.hpp
+++ b/modules/softcascade/include/opencv2/softcascade/softcascade.hpp
@@ -87,7 +87,7 @@ public:
     virtual void write( cv::FileStorage& fs, int index) const = 0;
     virtual ~FeaturePool();
 
-    static cv::Ptr<FeaturePool> create(const cv::Size& model, int nfeatures);
+    static cv::Ptr<FeaturePool> create(const cv::Size& model, int nfeatures, int nchannels );
 };
 
 // ========================================================================== //
@@ -128,7 +128,10 @@ public:
     // apply channels to source frame
     CV_WRAP_AS(compute) virtual void operator()(InputArray src, CV_OUT OutputArray channels, cv::Size channelsSize = cv::Size()) const = 0;
 
-    CV_WRAP static cv::Ptr<ChannelFeatureBuilder> create();
+    CV_WRAP virtual int totalChannels() const = 0;
+    virtual cv::AlgorithmInfo* info() const = 0;
+
+    CV_WRAP static cv::Ptr<ChannelFeatureBuilder> create(const std::string& featureType);
 };
 
 // ========================================================================== //
@@ -199,7 +202,7 @@ public:
 
     virtual ~Octave();
     static cv::Ptr<Octave> create(cv::Rect boundingBox, int npositives, int nnegatives,
-        int logScale, int shrinkage, int poolSize);
+        int logScale, int shrinkage, int poolSize, cv::Ptr<ChannelFeatureBuilder> builder);
 
     virtual bool train(const Dataset* dataset, const FeaturePool* pool, int weaks, int treeDepth) = 0;
     virtual void setRejectThresholds(OutputArray thresholds) = 0;
diff --git a/modules/softcascade/src/integral_channel_builder.cpp b/modules/softcascade/src/integral_channel_builder.cpp
index 38779797f1..e903cc424e 100644
--- a/modules/softcascade/src/integral_channel_builder.cpp
+++ b/modules/softcascade/src/integral_channel_builder.cpp
@@ -46,11 +46,15 @@ namespace {
 
 using namespace cv::softcascade;
 
-class ICFBuilder : public ChannelFeatureBuilder
+class HOG6MagLuv : public ChannelFeatureBuilder
 {
-    virtual ~ICFBuilder() {}
+    enum {N_CHANNELS = 10};
+public:
+    virtual ~HOG6MagLuv() {}
     virtual cv::AlgorithmInfo* info() const;
 
+    virtual int totalChannels() const {return N_CHANNELS; }
+
     virtual void operator()(cv::InputArray _frame, CV_OUT cv::OutputArray _integrals, cv::Size channelsSize) const
     {
         CV_Assert(_frame.type() == CV_8UC3);
@@ -60,16 +64,16 @@ class ICFBuilder : public ChannelFeatureBuilder
         int w = frame.cols;
 
         if (channelsSize != cv::Size())
-            _integrals.create(channelsSize.height * 10 + 1, channelsSize.width + 1, CV_32SC1);
+            _integrals.create(channelsSize.height * N_CHANNELS + 1, channelsSize.width + 1, CV_32SC1);
 
         if(_integrals.empty())
-            _integrals.create(frame.rows * 10 + 1, frame.cols + 1, CV_32SC1);
+            _integrals.create(frame.rows * N_CHANNELS + 1, frame.cols + 1, CV_32SC1);
 
         cv::Mat& integrals = _integrals.getMatRef();
 
         cv::Mat channels, gray;
 
-        channels.create(h * 10, w, CV_8UC1);
+        channels.create(h * N_CHANNELS, w, CV_8UC1);
         channels.setTo(0);
 
         cvtColor(frame, gray, CV_BGR2GRAY);
@@ -114,14 +118,13 @@ class ICFBuilder : public ChannelFeatureBuilder
 using cv::softcascade::ChannelFeatureBuilder;
 using cv::softcascade::ChannelFeature;
 
-CV_INIT_ALGORITHM(ICFBuilder, "ChannelFeatureBuilder.ICFBuilder", );
+CV_INIT_ALGORITHM(HOG6MagLuv,  "ChannelFeatureBuilder.HOG6MagLuv", );
 
 ChannelFeatureBuilder::~ChannelFeatureBuilder() {}
 
-cv::Ptr<ChannelFeatureBuilder> ChannelFeatureBuilder::create()
+cv::Ptr<ChannelFeatureBuilder> ChannelFeatureBuilder::create(const std::string& featureType)
 {
-    cv::Ptr<ChannelFeatureBuilder> builder(new ICFBuilder());
-    return builder;
+    return Algorithm::create<ChannelFeatureBuilder>("ChannelFeatureBuilder." + featureType);
 }
 
 ChannelFeature::ChannelFeature(int x, int y, int w, int h, int ch)
@@ -175,9 +178,9 @@ using namespace cv::softcascade;
 class ChannelFeaturePool : public FeaturePool
 {
 public:
-    ChannelFeaturePool(cv::Size m, int n) : FeaturePool(), model(m)
+    ChannelFeaturePool(cv::Size m, int n, int ch) : FeaturePool(), model(m), N_CHANNELS(ch)
     {
-        CV_Assert(m != cv::Size() && n > 0);
+        CV_Assert(m != cv::Size() && n > 0 && (ch == 10 || ch == 8));
         fill(n);
     }
 
@@ -193,7 +196,7 @@ private:
 
     cv::Size model;
     std::vector<ChannelFeature> pool;
-    enum { N_CHANNELS = 10 };
+    int N_CHANNELS;
 };
 
 float ChannelFeaturePool::apply(int fi, int si, const cv::Mat& integrals) const
@@ -203,7 +206,8 @@ float ChannelFeaturePool::apply(int fi, int si, const cv::Mat& integrals) const
 
 void ChannelFeaturePool::write( cv::FileStorage& fs, int index) const
 {
-    CV_Assert((index > 0) && (index < (int)pool.size()));
+
+    CV_Assert((index >= 0) && (index < (int)pool.size()));
     fs << pool[index];
 }
 
@@ -240,12 +244,12 @@ void ChannelFeaturePool::fill(int desired)
         // the old behavior:
         // http://www.boost.org/doc/libs/1_47_0/boost/random/uniform_int.hpp
         int w = 1 + wRand(
-	  eng,
+        eng,
           // This extra "- 1" appears to be necessary, based on the Boost docs.
-	  Random::uniform::param_type(0, (model.width  - x - 1) - 1));
+        Random::uniform::param_type(0, (model.width  - x - 1) - 1));
         int h = 1 + hRand(
-	  eng,
-	  Random::uniform::param_type(0, (model.height  - y - 1) - 1));
+        eng,
+        Random::uniform::param_type(0, (model.height  - y - 1) - 1));
 #else
         int w = 1 + wRand(eng, model.width  - x - 1);
         int h = 1 + hRand(eng, model.height - y - 1);
@@ -270,8 +274,8 @@ void ChannelFeaturePool::fill(int desired)
 
 }
 
-cv::Ptr<FeaturePool> FeaturePool::create(const cv::Size& model, int nfeatures)
+cv::Ptr<FeaturePool> FeaturePool::create(const cv::Size& model, int nfeatures, int nchannels )
 {
-    cv::Ptr<FeaturePool> pool(new ChannelFeaturePool(model, nfeatures));
+    cv::Ptr<FeaturePool> pool(new ChannelFeaturePool(model, nfeatures, nchannels));
     return pool;
 }
diff --git a/modules/softcascade/src/soft_cascade_octave.cpp b/modules/softcascade/src/soft_cascade_octave.cpp
index f7b3b3fb04..3d3864ecf5 100644
--- a/modules/softcascade/src/soft_cascade_octave.cpp
+++ b/modules/softcascade/src/soft_cascade_octave.cpp
@@ -63,7 +63,8 @@ class BoostedSoftCascadeOctave : public cv::Boost, public Octave
 public:
 
     BoostedSoftCascadeOctave(cv::Rect boundingBox = cv::Rect(), int npositives = 0, int nnegatives = 0, int logScale = 0,
-        int shrinkage = 1, int poolSize = 0);
+        int shrinkage = 1, int poolSize = 0,
+        cv::Ptr<ChannelFeatureBuilder> builder = ChannelFeatureBuilder::create("HOG6MagLuv"));
     virtual ~BoostedSoftCascadeOctave();
     virtual cv::AlgorithmInfo* info() const;
     virtual bool train(const Dataset* dataset, const FeaturePool* pool, int weaks, int treeDepth);
@@ -101,7 +102,8 @@ private:
     cv::Ptr<ChannelFeatureBuilder> builder;
 };
 
-BoostedSoftCascadeOctave::BoostedSoftCascadeOctave(cv::Rect bb, int np, int nn, int ls, int shr, int poolSize)
+BoostedSoftCascadeOctave::BoostedSoftCascadeOctave(cv::Rect bb, int np, int nn, int ls, int shr, int poolSize,
+    cv::Ptr<ChannelFeatureBuilder> _builder)
 : logScale(ls), boundingBox(bb), npositives(np), nnegatives(nn), shrinkage(shr)
 {
     int maxSample = npositives + nnegatives;
@@ -130,7 +132,7 @@ BoostedSoftCascadeOctave::BoostedSoftCascadeOctave(cv::Rect bb, int np, int nn,
 
     params = _params;
 
-    builder = ChannelFeatureBuilder::create();
+    builder = _builder;
 
     int w = boundingBox.width;
     int h = boundingBox.height;
@@ -204,7 +206,7 @@ void BoostedSoftCascadeOctave::processPositives(const Dataset* dataset)
     {
         cv::Mat sample = dataset->get( Dataset::POSITIVE, curr);
 
-        cv::Mat channels = integrals.row(total).reshape(0, h / shrinkage * 10 + 1);
+        cv::Mat channels = integrals.row(total).reshape(0, h / shrinkage * builder->totalChannels() + 1);
         sample = sample(boundingBox);
 
         _builder(sample, channels);
@@ -249,7 +251,7 @@ void BoostedSoftCascadeOctave::generateNegatives(const Dataset* dataset)
 
         frame = frame(cv::Rect(dx, dy, boundingBox.width, boundingBox.height));
 
-        cv::Mat channels = integrals.row(i).reshape(0, h / shrinkage * 10 + 1);
+        cv::Mat channels = integrals.row(i).reshape(0, h / shrinkage * builder->totalChannels() + 1);
         _builder(frame, channels);
 
         // // if (predict(sum))
@@ -442,14 +444,14 @@ void BoostedSoftCascadeOctave::write( CvFileStorage* fs, std::string _name) cons
 
 }
 
-CV_INIT_ALGORITHM(BoostedSoftCascadeOctave, "SoftCascadeOctave.BoostedSoftCascadeOctave", );
+CV_INIT_ALGORITHM(BoostedSoftCascadeOctave, "Octave.BoostedSoftCascadeOctave", );
 
 Octave::~Octave(){}
 
 cv::Ptr<Octave> Octave::create(cv::Rect boundingBox, int npositives, int nnegatives,
-        int logScale, int shrinkage, int poolSize)
+        int logScale, int shrinkage, int poolSize, cv::Ptr<ChannelFeatureBuilder> builder)
 {
     cv::Ptr<Octave> octave(
-        new BoostedSoftCascadeOctave(boundingBox, npositives, nnegatives, logScale, shrinkage, poolSize));
+        new BoostedSoftCascadeOctave(boundingBox, npositives, nnegatives, logScale, shrinkage, poolSize, builder));
     return octave;
 }
diff --git a/modules/softcascade/src/softcascade.cpp b/modules/softcascade/src/softcascade.cpp
index 465deb489a..43772449ac 100644
--- a/modules/softcascade/src/softcascade.cpp
+++ b/modules/softcascade/src/softcascade.cpp
@@ -187,11 +187,12 @@ struct ChannelStorage
 
     enum {HOG_BINS = 6, HOG_LUV_BINS = 10};
 
-    ChannelStorage(const cv::Mat& colored, int shr) : shrinkage(shr)
+    ChannelStorage(const cv::Mat& colored, int shr, std::string featureTypeStr) : shrinkage(shr)
     {
         model_height = cvRound(colored.rows / (float)shrinkage);
+        if (featureTypeStr == "ICF") featureTypeStr = "HOG6MagLuv";
 
-        builder = ChannelFeatureBuilder::create();
+        builder = ChannelFeatureBuilder::create(featureTypeStr);
         (*builder)(colored, hog, cv::Size(cvRound(colored.cols / (float)shrinkage), model_height));
 
         step = hog.step1();
@@ -201,8 +202,8 @@ struct ChannelStorage
     {
         const int *ptr = hog.ptr<const int>(0) + model_height * channel * step + offset;
 
-        int a = ptr[area.y * step + area.x];
-        int b = ptr[area.y * step + area.width];
+        int a = ptr[area.y      * step + area.x];
+        int b = ptr[area.y      * step + area.width];
         int c = ptr[area.height * step + area.width];
         int d = ptr[area.height * step + area.x];
 
@@ -224,7 +225,7 @@ struct Detector::Fields
 
     int shrinkage;
 
-    std::vector<SOctave>  octaves;
+    std::vector<SOctave> octaves;
     std::vector<Weak>    weaks;
     std::vector<Node>    nodes;
     std::vector<float>   leaves;
@@ -237,6 +238,8 @@ struct Detector::Fields
     typedef std::vector<SOctave>::iterator  octIt_t;
     typedef std::vector<Detection> dvector;
 
+    std::string featureTypeStr;
+
     void detectAt(const int dx, const int dy, const Level& level, const ChannelStorage& storage, dvector& detections) const
     {
         float detectionScore = 0.f;
@@ -341,6 +344,7 @@ struct Detector::Fields
         static const char *const SC_BOOST            = "BOOST";
 
         static const char *const SC_FEATURE_TYPE     = "featureType";
+        static const char *const SC_HOG6_MAG_LUV     = "HOG6MagLuv";
         static const char *const SC_ICF              = "ICF";
 
         static const char *const SC_ORIG_W           = "width";
@@ -365,8 +369,8 @@ struct Detector::Fields
         bool useBoxes = (fformat == "BOX");
 
         // only HOG-like integral channel features supported
-        std::string featureTypeStr = (std::string)root[SC_FEATURE_TYPE];
-        CV_Assert(featureTypeStr == SC_ICF);
+        featureTypeStr = (std::string)root[SC_FEATURE_TYPE];
+        CV_Assert(featureTypeStr == SC_ICF || featureTypeStr == SC_HOG6_MAG_LUV);
 
         origObjWidth  = (int)root[SC_ORIG_W];
         origObjHeight = (int)root[SC_ORIG_H];
@@ -491,7 +495,7 @@ void Detector::detectNoRoi(const cv::Mat& image, std::vector<Detection>& objects
 {
     Fields& fld = *fields;
     // create integrals
-    ChannelStorage storage(image, fld.shrinkage);
+    ChannelStorage storage(image, fld.shrinkage, fld.featureTypeStr);
 
     typedef std::vector<Level>::const_iterator lIt;
     for (lIt it = fld.levels.begin(); it != fld.levels.end(); ++it)
@@ -539,7 +543,7 @@ void Detector::detect(cv::InputArray _image, cv::InputArray _rois, std::vector<D
         cv::Mat(mask, cv::Rect(r[i].x / shr, r[i].y / shr, r[i].width / shr , r[i].height / shr)).setTo(cv::Scalar::all(1));
 
     // create integrals
-    ChannelStorage storage(image, shr);
+    ChannelStorage storage(image, shr, fld.featureTypeStr);
 
     typedef std::vector<Level>::const_iterator lIt;
     for (lIt it = fld.levels.begin(); it != fld.levels.end(); ++it)
diff --git a/modules/softcascade/test/test_channel_features.cpp b/modules/softcascade/test/test_channel_features.cpp
index 0a8cbf43ba..07b8957a50 100644
--- a/modules/softcascade/test/test_channel_features.cpp
+++ b/modules/softcascade/test/test_channel_features.cpp
@@ -46,13 +46,13 @@ using namespace cv::softcascade;
 
 TEST(ChannelFeatureBuilderTest, info)
 {
-    cv::Ptr<ChannelFeatureBuilder> builder = ChannelFeatureBuilder::create();
+    cv::Ptr<ChannelFeatureBuilder> builder = ChannelFeatureBuilder::create("HOG6MagLuv");
     ASSERT_TRUE(builder->info() != 0);
 }
 
 TEST(ChannelFeatureBuilderTest, compute)
 {
-    cv::Ptr<ChannelFeatureBuilder> builder = ChannelFeatureBuilder::create();
+    cv::Ptr<ChannelFeatureBuilder> builder = ChannelFeatureBuilder::create("HOG6MagLuv");
 
     cv::Mat colored = cv::imread(cvtest::TS::ptr()->get_data_path()  + "cascadeandhog/images/image_00000000_0.png");
     cv::Mat ints;
diff --git a/modules/softcascade/test/test_training.cpp b/modules/softcascade/test/test_training.cpp
index 301bab35c6..94d774754e 100644
--- a/modules/softcascade/test/test_training.cpp
+++ b/modules/softcascade/test/test_training.cpp
@@ -212,7 +212,7 @@ TEST(DISABLED_SoftCascade, training)
         float octave = powf(2.f, (float)(*it));
         cv::Size model = cv::Size( cvRound(64 * octave) / shrinkage, cvRound(128 * octave) / shrinkage );
 
-        cv::Ptr<FeaturePool> pool = FeaturePool::create(model, nfeatures);
+        cv::Ptr<FeaturePool> pool = FeaturePool::create(model, nfeatures, 10);
         nfeatures = pool->size();
         int npositives = 20;
         int nnegatives = 40;
@@ -220,7 +220,8 @@ TEST(DISABLED_SoftCascade, training)
         cv::Rect boundingBox = cv::Rect( cvRound(20 * octave), cvRound(20  * octave),
                                          cvRound(64 * octave), cvRound(128 * octave));
 
-        cv::Ptr<Octave> boost = Octave::create(boundingBox, npositives, nnegatives, *it, shrinkage, nfeatures);
+        cv::Ptr<ChannelFeatureBuilder> builder = ChannelFeatureBuilder::create("HOG6MagLuv");
+        cv::Ptr<Octave> boost = Octave::create(boundingBox, npositives, nnegatives, *it, shrinkage, nfeatures, builder);
 
         std::string path = cvtest::TS::ptr()->get_data_path() + "softcascade/sample_training_set";
         ScaledDataset dataset(path, *it);