final refactoring and test for training
authormarina.kolpakova <marina.kolpakova@itseez.com>
Wed, 30 Jan 2013 09:34:34 +0000 (13:34 +0400)
committermarina.kolpakova <marina.kolpakova@itseez.com>
Fri, 1 Feb 2013 10:36:06 +0000 (14:36 +0400)
14 files changed:
apps/sft/CMakeLists.txt
apps/sft/config.cpp
apps/sft/dataset.cpp [moved from apps/sft/fpool.cpp with 95% similarity]
apps/sft/include/sft/common.hpp
apps/sft/include/sft/config.hpp
apps/sft/include/sft/dataset.hpp [moved from apps/sft/include/sft/fpool.hpp with 95% similarity]
apps/sft/sft.cpp
modules/ml/include/opencv2/ml/ml.hpp
modules/ml/src/boost.cpp
modules/softcascade/src/_random.hpp
modules/softcascade/src/integral_channel_builder.cpp
modules/softcascade/src/precomp.hpp
modules/softcascade/src/soft_cascade_octave.cpp
modules/softcascade/test/test_training.cpp [new file with mode: 0644]

index bc7c1eb..7197519 100644 (file)
@@ -1,7 +1,3 @@
-if(IOS OR ANDROID)
-  return()
-endif()
-
 set(name sft)
 set(the_target opencv_${name})
 
index d993722..3fc1139 100644 (file)
@@ -108,9 +108,9 @@ void sft::write(cv::FileStorage& fs, const string&, const Config& x)
 
 void sft::read(const cv::FileNode& node, Config& x, const Config& default_value)
 {
-    if(node.empty())
-        x = default_value;
-    else
+    x = default_value;
+
+    if(!node.empty())
         x.read(node);
 }
 
similarity index 95%
rename from apps/sft/fpool.cpp
rename to apps/sft/dataset.cpp
index 825d88d..52ec8ac 100644 (file)
 //
 //M*/
 
-#include <sft/fpool.hpp>
+#include <sft/dataset.hpp>
+#include <opencv2/highgui/highgui.hpp>
 
 #include <iostream>
 #include <queue>
 
-// ============ Dataset ============ //
-namespace {
-using namespace sft;
-
-string itoa(long i)
-{
-    char s[65];
-    sprintf(s, "%ld", i);
-    return std::string(s);
-}
-
-}
+inline std::string itoa(long i) { return cv::format("%ld", i); }
 
 #if !defined (_WIN32) && ! defined(__MINGW32__)
-
-#include <glob.h>
+# include <glob.h>
 
 namespace {
 using namespace sft;
@@ -84,7 +73,7 @@ void glob(const string& path, svector& ret)
 }
 #else
 
-#include <windows.h>
+# include <windows.h>
 namespace {
 using namespace sft;
 void glob(const string& refRoot, const string& refExt, svector &refvecFiles)
@@ -138,7 +127,6 @@ void glob(const string& refRoot, const string& refExt, svector &refvecFiles)
 ScaledDataset::ScaledDataset(const string& path, const int oct)
 {
     dprintf("%s\n", "get dataset file names...");
-
     dprintf("%s\n", "Positives globing...");
 
 #if !defined (_WIN32) && ! defined(__MINGW32__)
index 4ddc0a3..1371875 100644 (file)
@@ -44,6 +44,7 @@
 #define __SFT_COMMON_HPP__
 
 #include <opencv2/core/core.hpp>
+#include <opencv2/softcascade/softcascade.hpp>
 
 namespace sft
 {
@@ -58,7 +59,7 @@ namespace sft
 }
 
 // used for noisy printfs
-#define WITH_DEBUG_OUT
+//#define WITH_DEBUG_OUT
 
 #if defined WITH_DEBUG_OUT
 # include <stdio.h>
index 5be5ebd..6bdb861 100644 (file)
@@ -75,9 +75,7 @@ struct Config
 
     string resPath(ivector::const_iterator it) const
     {
-        char s[65];
-        sprintf(s, "%d", *it);
-        return std::string(cascadeName) + s + ".xml";
+        return cv::format("%s%d.xml",cascadeName.c_str(), *it);
     }
 
     // Paths to a rescaled data
similarity index 95%
rename from apps/sft/include/sft/fpool.hpp
rename to apps/sft/include/sft/dataset.hpp
index ad0f56d..14cffa7 100644 (file)
 #define __SFT_OCTAVE_HPP__
 
 #include <sft/common.hpp>
-
-#include <opencv2/imgproc/imgproc.hpp>
-#include <opencv2/highgui/highgui.hpp>
-#include <opencv2/softcascade/softcascade.hpp>
 namespace sft
 {
 
index 67c56fc..f3c8481 100644 (file)
@@ -44,7 +44,7 @@
 
 #include <sft/common.hpp>
 #include <iostream>
-#include <sft/fpool.hpp>
+#include <sft/dataset.hpp>
 #include <sft/config.hpp>
 
 #include <opencv2/core/core_c.h>
index 93123dc..7bb553d 100644 (file)
@@ -1251,7 +1251,7 @@ protected:
     virtual void write_params( CvFileStorage* fs ) const;
     virtual void read_params( CvFileStorage* fs, CvFileNode* node );
 
-    virtual void initial_weights(double (&p)[2]);
+    virtual void initialize_weights(double (&p)[2]);
 
     CvDTreeTrainData* data;
     CvBoostParams params;
index 0dc0d28..4b27dcf 100644 (file)
@@ -1115,7 +1115,7 @@ bool CvBoost::train( CvMLData* _data,
     return result;
 }
 
-void CvBoost::initial_weights(double (&p)[2])
+void CvBoost::initialize_weights(double (&p)[2])
 {
     p[0] = 1.;
     p[1] = 1.;
@@ -1166,7 +1166,7 @@ CvBoost::update_weights( CvBoostTree* tree )
 
         double w0 = 1./ n;
         double p[2] = { 1., 1. };
-        initial_weights(p);
+        initialize_weights(p);
 
         cvReleaseMat( &orig_response );
         cvReleaseMat( &sum_response );
index 3a3be8b..b7a402d 100644 (file)
@@ -114,4 +114,27 @@ struct Random
 
 #endif
 
+#if defined _WIN32 && (_WIN32 || _WIN64)
+# if _WIN64
+#  define USE_LONG_SEEDS
+# endif
+#endif
+#if defined (__GNUC__) &&__GNUC__
+# if defined(__x86_64__) || defined(__ppc64__)
+#  define USE_LONG_SEEDS
+# endif
+#endif
+
+#if defined USE_LONG_SEEDS
+# define FEATURE_RECT_SEED      8854342234LU
+# define INDEX_ENGINE_SEED      764224349868LU
+#else
+# define FEATURE_RECT_SEED      88543422LU
+# define INDEX_ENGINE_SEED      76422434LU
+#endif
+#undef USE_LONG_SEEDS
+
+#define DCHANNELS_SEED         314152314LU
+#define DX_DY_SEED             65633343LU
+
 #endif
\ No newline at end of file
index 539642a..ad5bc7e 100644 (file)
@@ -41,7 +41,6 @@
 //M*/
 
 #include "precomp.hpp"
-#include "_random.hpp"
 
 namespace {
 
@@ -199,25 +198,6 @@ void ChannelFeaturePool::write( cv::FileStorage& fs, int index) const
     fs << pool[index];
 }
 
-#if defined _WIN32 && (_WIN32 || _WIN64)
-# if _WIN64
-#  define USE_LONG_SEEDS
-# endif
-#endif
-#if defined (__GNUC__) &&__GNUC__
-# if defined(__x86_64__) || defined(__ppc64__)
-#  define USE_LONG_SEEDS
-# endif
-#endif
-
-#if defined USE_LONG_SEEDS
-# define FEATURE_RECT_SEED      8854342234LU
-#else
-# define FEATURE_RECT_SEED      88543422LU
-#endif
-# define DCHANNELS_SEED         314152314LU
-#undef USE_LONG_SEEDS
-
 void ChannelFeaturePool::fill(int desired)
 {
     int mw = model.width;
@@ -226,8 +206,6 @@ void ChannelFeaturePool::fill(int desired)
     int maxPoolSize = (mw -1) * mw / 2 * (mh - 1) * mh / 2 * N_CHANNELS;
 
     int nfeatures = std::min(desired, maxPoolSize);
-    // dprintf("Requeste feature pool %d max %d suggested %d\n", desired, maxPoolSize, nfeatures);
-
     pool.reserve(nfeatures);
 
     sft::Random::engine eng(FEATURE_RECT_SEED);
@@ -262,7 +240,6 @@ void ChannelFeaturePool::fill(int desired)
         if (std::find(pool.begin(), pool.end(),f) == pool.end())
         {
             pool.push_back(f);
-            std::cout << f << std::endl;
         }
     }
 }
index 2706319..cb20a26 100644 (file)
@@ -53,7 +53,6 @@
 #include "opencv2/core/core_c.h"
 #include "opencv2/core/internal.hpp"
 #include "opencv2/ml/ml.hpp"
-
-#include "opencv2/opencv_modules.hpp"
+#include "_random.hpp"
 
 #endif
index 4347394..41e4a9b 100644 (file)
 #include "precomp.hpp"
 #include <queue>
 #include <string>
-#include "_random.hpp"
-
-#define WITH_DEBUG_OUT
-
-#if defined WITH_DEBUG_OUT
-# include <stdio.h>
-# define dprintf(format, ...)  printf(format, ##__VA_ARGS__)
-#else
-# define dprintf(format, ...)
-#endif
-
 
 using cv::Dataset;
 using cv::FeaturePool;
@@ -90,7 +79,7 @@ protected:
     float predict( const Mat& _sample, const cv::Range range) const;
 private:
     void traverse(const CvBoostTree* tree, cv::FileStorage& fs, int& nfeatures, int* used, const double* th) const;
-    virtual void initial_weights(double (&p)[2]);
+    virtual void initialize_weights(double (&p)[2]);
 
     int logScale;
     cv::Rect boundingBox;
@@ -159,8 +148,6 @@ bool BoostedSoftCascadeOctave::train( const cv::Mat& _trainData, const cv::Mat&
 
 void BoostedSoftCascadeOctave::setRejectThresholds(cv::OutputArray _thresholds)
 {
-    dprintf("set thresholds according to DBP strategy\n");
-
     // labels decided by classifier
     cv::Mat desisions(responses.cols, responses.rows, responses.type());
     float* dptr = desisions.ptr<float>(0);
@@ -223,33 +210,10 @@ void BoostedSoftCascadeOctave::processPositives(const Dataset* dataset)
 
         if (++total >= npositives) break;
     }
-
-    dprintf("Processing positives finished:\n\trequested %d positives, collected %d samples.\n", npositives, total);
-
     npositives  = total;
     nnegatives = cvRound(nnegatives * total / (double)npositives);
 }
 
-#if defined _WIN32 && (_WIN32 || _WIN64)
-# if _WIN64
-#  define USE_LONG_SEEDS
-# endif
-#endif
-#if defined (__GNUC__) &&__GNUC__
-# if defined(__x86_64__) || defined(__ppc64__)
-#  define USE_LONG_SEEDS
-# endif
-#endif
-
-#if defined USE_LONG_SEEDS
-# define INDEX_ENGINE_SEED      764224349868LU
-#else
-# define INDEX_ENGINE_SEED      76422434LU
-#endif
-# define DX_DY_SEED             65633343LU
-#undef USE_LONG_SEEDS
-
-
 void BoostedSoftCascadeOctave::generateNegatives(const Dataset* dataset)
 {
     // ToDo: set seed, use offsets
@@ -285,15 +249,12 @@ void BoostedSoftCascadeOctave::generateNegatives(const Dataset* dataset)
         cv::Mat channels = integrals.row(i).reshape(0, h / shrinkage * 10 + 1);
         _builder(frame, channels);
 
-        dprintf("generated %d %d\n", dx, dy);
         // // if (predict(sum))
         {
             responses.ptr<float>(i)[0] = 0.f;
             ++i;
         }
     }
-
-    dprintf("Processing negatives finished:\n\trequested %d negatives, viewed %d samples.\n", nnegatives, total);
 }
 
 
@@ -390,7 +351,7 @@ void BoostedSoftCascadeOctave::write( cv::FileStorage &fso, const FeaturePool* p
         << "}";
 }
 
-void BoostedSoftCascadeOctave::initial_weights(double (&p)[2])
+void BoostedSoftCascadeOctave::initialize_weights(double (&p)[2])
 {
     double n = data->sample_count;
     p[0] =  n / (2. * (double)(nnegatives));
diff --git a/modules/softcascade/test/test_training.cpp b/modules/softcascade/test/test_training.cpp
new file mode 100644 (file)
index 0000000..b6a282c
--- /dev/null
@@ -0,0 +1,246 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2008-2013, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and / or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#if !defined(ANDROID)
+
+#include <string>
+#include <fstream>
+#include <vector>
+
+#include "test_precomp.hpp"
+#if !defined (_WIN32) && ! defined(__MINGW32__)
+# include <glob.h>
+#else
+# include <windows.h>
+#endif
+
+using namespace std;
+
+namespace {
+
+typedef vector<string> svector;
+class ScaledDataset : public cv::Dataset
+{
+public:
+    ScaledDataset(const string& path, const int octave);
+
+    virtual cv::Mat get(SampleType type, int idx) const;
+    virtual int available(SampleType type) const;
+    virtual ~ScaledDataset();
+
+private:
+    svector pos;
+    svector neg;
+};
+
+string itoa(long i)
+{
+    char s[65];
+    sprintf(s, "%ld", i);
+    return std::string(s);
+}
+
+
+#if !defined (_WIN32) && ! defined(__MINGW32__)
+
+void glob(const string& path, svector& ret)
+{
+    glob_t glob_result;
+    glob(path.c_str(), GLOB_TILDE, 0, &glob_result);
+
+    ret.clear();
+    ret.reserve(glob_result.gl_pathc);
+
+    for(unsigned int i = 0; i < glob_result.gl_pathc; ++i)
+    {
+        ret.push_back(std::string(glob_result.gl_pathv[i]));
+    }
+
+    globfree(&glob_result);
+}
+
+#else
+
+void glob(const string& refRoot, const string& refExt, svector &refvecFiles)
+{
+    std::string     strFilePath;             // File path
+    std::string     strExtension;            // Extension
+
+    std::string strPattern = refRoot + "\\*.*";
+
+    WIN32_FIND_DATA FileInformation;         // File information
+    HANDLE hFile = ::FindFirstFile(strPattern.c_str(), &FileInformation);
+
+    if(hFile == INVALID_HANDLE_VALUE)
+        CV_Error(CV_StsBadArg, "Your dataset search path is incorrect");
+
+    do
+    {
+        if(FileInformation.cFileName[0] != '.')
+        {
+            strFilePath.erase();
+            strFilePath = refRoot + "\\" + FileInformation.cFileName;
+
+            if( !(FileInformation.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
+            {
+                // Check extension
+                strExtension = FileInformation.cFileName;
+                strExtension = strExtension.substr(strExtension.rfind(".") + 1);
+
+                if(strExtension == refExt)
+                    // Save filename
+                    refvecFiles.push_back(strFilePath);
+            }
+        }
+    }
+    while(::FindNextFile(hFile, &FileInformation) == TRUE);
+
+    // Close handle
+    ::FindClose(hFile);
+
+    DWORD dwError = ::GetLastError();
+    if(dwError != ERROR_NO_MORE_FILES)
+        CV_Error(CV_StsBadArg, "Your dataset search path is incorrect");
+}
+
+#endif
+
+ScaledDataset::ScaledDataset(const string& path, const int oct)
+{
+
+#if !defined (_WIN32) && ! defined(__MINGW32__)
+    glob(path + "/pos/octave_" + itoa(oct) + "/*.png", pos);
+#else
+    glob(path + "/pos/octave_" + itoa(oct),     "png", pos);
+#endif
+
+#if !defined (_WIN32) && ! defined(__MINGW32__)
+    glob(path + "/neg/octave_" + itoa(oct) + "/*.png", neg);
+#else
+    glob(path + "/neg/octave_" + itoa(oct),     "png", neg);
+#endif
+
+    // Check: files not empty
+    CV_Assert(pos.size() != size_t(0));
+    CV_Assert(neg.size() != size_t(0));
+}
+
+cv::Mat ScaledDataset::get(SampleType type, int idx) const
+{
+    const std::string& src = (type == POSITIVE)? pos[idx]: neg[idx];
+    return cv::imread(src);
+}
+
+int ScaledDataset::available(SampleType type) const
+{
+    return (int)((type == POSITIVE)? pos.size():neg.size());
+}
+
+ScaledDataset::~ScaledDataset(){}
+
+}
+
+TEST(DISABLED_SoftCascade, training)
+{
+    // // 2. check and open output file
+    string outXmlPath = cv::tempfile(".xml");
+    cv::FileStorage fso(outXmlPath, cv::FileStorage::WRITE);
+
+    ASSERT_TRUE(fso.isOpened());
+
+    std::vector<int> octaves;
+    {
+        octaves.push_back(-1);
+        octaves.push_back(0);
+    }
+
+    fso << "regression-cascade"
+        << "{"
+        << "stageType"   << "BOOST"
+        << "featureType" << "ICF"
+        << "octavesNum"  << 2
+        << "width"       << 64
+        << "height"      << 128
+        << "shrinkage"   << 4
+        << "octaves"     << "[";
+
+    for (std::vector<int>::const_iterator it = octaves.begin(); it != octaves.end(); ++it)
+    {
+        int nfeatures  = 100;
+        int shrinkage = 4;
+        float octave = powf(2.f, (float)(*it));
+        cv::Size model = cv::Size( cvRound(64 * octave) / shrinkage, cvRound(128 * octave) / shrinkage );
+
+        cv::Ptr<cv::FeaturePool> pool = cv::FeaturePool::create(model, nfeatures);
+        nfeatures = pool->size();
+        int npositives = 20;
+        int nnegatives = 40;
+
+        cv::Rect boundingBox = cv::Rect( cvRound(20 * octave), cvRound(20  * octave),
+                                         cvRound(64 * octave), cvRound(128 * octave));
+
+        typedef cv::SoftCascadeOctave Octave;
+        cv::Ptr<Octave> boost = Octave::create(boundingBox, npositives, nnegatives, *it, shrinkage, nfeatures);
+
+        std::string path = cvtest::TS::ptr()->get_data_path() + "softcascade/sample_training_set";
+        ScaledDataset dataset(path, *it);
+
+        if (boost->train(&dataset, pool, 3, 2))
+        {
+            cv::Mat thresholds;
+            boost->setRejectThresholds(thresholds);
+            boost->write(fso, pool, thresholds);
+        }
+    }
+
+    fso << "]" << "}";
+    fso.release();
+
+
+    cv::FileStorage actual(outXmlPath, cv::FileStorage::READ);
+    cv::FileNode root = actual.getFirstTopLevelNode();
+
+    cv::FileNode fn = root["octaves"];
+    ASSERT_FALSE(fn.empty());
+}
+
+#endif
\ No newline at end of file