From dd8de0c41f50a9b26d5ee2771bd10b60d976e9a9 Mon Sep 17 00:00:00 2001 From: "marina.kolpakova" Date: Wed, 9 Jan 2013 16:03:53 +0400 Subject: [PATCH] move soft cascade octave to ml module --- apps/sft/include/sft/octave.hpp | 72 +----- apps/sft/octave.cpp | 347 +---------------------------- apps/sft/sft.cpp | 6 +- modules/ml/include/opencv2/ml/ml.hpp | 67 +++++- modules/ml/src/octave.cpp | 416 ++++++++++++++++++++++++++++++++++- 5 files changed, 498 insertions(+), 410 deletions(-) diff --git a/apps/sft/include/sft/octave.hpp b/apps/sft/include/sft/octave.hpp index 1d19cdb..5d5d3b3 100644 --- a/apps/sft/include/sft/octave.hpp +++ b/apps/sft/include/sft/octave.hpp @@ -155,6 +155,9 @@ private: void write(cv::FileStorage& fs, const std::string&, const ICF& f); std::ostream& operator<<(std::ostream& out, const ICF& m); +using cv::FeaturePool; +using cv::Dataset; + class ICFFeaturePool : public cv::FeaturePool { public: @@ -184,79 +187,20 @@ private: }; -using cv::FeaturePool; - - -class Dataset +class ScaledDataset : public Dataset { public: - typedef enum {POSITIVE = 1, NEGATIVE = 2} SampleType; - Dataset(const sft::string& path, const int octave); + ScaledDataset(const sft::string& path, const int octave); - cv::Mat get(SampleType type, int idx) const; - int available(SampleType type) const; + virtual cv::Mat get(SampleType type, int idx) const; + virtual int available(SampleType type) const; + virtual ~ScaledDataset(); private: svector pos; svector neg; }; - -// used for traning single octave scale -class Octave : cv::Boost -{ -public: - - enum - { - // Direct backward pruning. (Cha Zhang and Paul Viola) - DBP = 1, - // Multiple instance pruning. (Cha Zhang and Paul Viola) - MIP = 2, - // Originally proposed by L. bourdev and J. brandt - HEURISTIC = 4 - }; - - Octave(cv::Rect boundingBox, int npositives, int nnegatives, int logScale, int shrinkage); - virtual ~Octave(); - - virtual bool train(const Dataset& dataset, const FeaturePool* pool, int weaks, int treeDepth); - - virtual float predict( const Mat& _sample, Mat& _votes, bool raw_mode, bool return_sum ) const; - virtual void setRejectThresholds(cv::Mat& thresholds); - virtual void write( CvFileStorage* fs, string name) const; - - virtual void write( cv::FileStorage &fs, const FeaturePool* pool, const Mat& thresholds) const; - - int logScale; - -protected: - virtual bool train( const cv::Mat& trainData, const cv::Mat& responses, const cv::Mat& varIdx=cv::Mat(), - const cv::Mat& sampleIdx=cv::Mat(), const cv::Mat& varType=cv::Mat(), const cv::Mat& missingDataMask=cv::Mat()); - - void processPositives(const Dataset& dataset, const FeaturePool* pool); - void generateNegatives(const Dataset& dataset, const FeaturePool* pool); - - 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]); - - cv::Rect boundingBox; - - int npositives; - int nnegatives; - - int shrinkage; - - Mat integrals; - Mat responses; - - CvBoostParams params; - - Mat trainData; -}; - } #endif \ No newline at end of file diff --git a/apps/sft/octave.cpp b/apps/sft/octave.cpp index eac165d..01e91a3 100644 --- a/apps/sft/octave.cpp +++ b/apps/sft/octave.cpp @@ -46,343 +46,6 @@ #include #include -// ============ Octave ============ // -sft::Octave::Octave(cv::Rect bb, int np, int nn, int ls, int shr) -: logScale(ls), boundingBox(bb), npositives(np), nnegatives(nn), shrinkage(shr) -{ - int maxSample = npositives + nnegatives; - responses.create(maxSample, 1, CV_32FC1); - - CvBoostParams _params; - { - // tree params - _params.max_categories = 10; - _params.max_depth = 2; - _params.cv_folds = 0; - _params.truncate_pruned_tree = false; - _params.use_surrogates = false; - _params.use_1se_rule = false; - _params.regression_accuracy = 1.0e-6; - - // boost params - _params.boost_type = CvBoost::GENTLE; - _params.split_criteria = CvBoost::SQERR; - _params.weight_trim_rate = 0.95; - - // simple defaults - _params.min_sample_count = 2; - _params.weak_count = 1; - } - - params = _params; -} - -sft::Octave::~Octave(){} - -bool sft::Octave::train( const cv::Mat& _trainData, const cv::Mat& _responses, const cv::Mat& varIdx, - const cv::Mat& sampleIdx, const cv::Mat& varType, const cv::Mat& missingDataMask) -{ - bool update = false; - return cv::Boost::train(_trainData, CV_COL_SAMPLE, _responses, varIdx, sampleIdx, varType, missingDataMask, params, - update); -} - -void sft::Octave::setRejectThresholds(cv::Mat& thresholds) -{ - dprintf("set thresholds according to DBP strategy\n"); - - // labels desided by classifier - cv::Mat desisions(responses.cols, responses.rows, responses.type()); - float* dptr = desisions.ptr(0); - - // mask of samples satisfying the condition - cv::Mat ppmask(responses.cols, responses.rows, CV_8UC1); - uchar* mptr = ppmask.ptr(0); - - int nsamples = npositives + nnegatives; - - cv::Mat stab; - - for (int si = 0; si < nsamples; ++si) - { - float decision = dptr[si] = predict(trainData.col(si), stab, false, false); - mptr[si] = cv::saturate_cast((uint)( (responses.ptr(si)[0] == 1.f) && (decision == 1.f))); - } - - int weaks = weak->total; - thresholds.create(1, weaks, CV_64FC1); - double* thptr = thresholds.ptr(0); - - cv::Mat traces(weaks, nsamples, CV_64FC1, cv::Scalar::all(FLT_MAX)); - - for (int w = 0; w < weaks; ++w) - { - double* rptr = traces.ptr(w); - for (int si = 0; si < nsamples; ++si) - { - cv::Range curr(0, w + 1); - if (mptr[si]) - { - float trace = predict(trainData.col(si), curr); - rptr[si] = trace; - } - } - double mintrace = 0.; - cv::minMaxLoc(traces.row(w), &mintrace); - thptr[w] = mintrace; - } -} - -namespace { -using namespace sft; - -} - -void sft::Octave::processPositives(const Dataset& dataset, const FeaturePool* pool) -{ - int w = boundingBox.width; - int h = boundingBox.height; - - integrals.create(pool->size(), (w / shrinkage + 1) * (h / shrinkage * 10 + 1), CV_32SC1); - - int total = 0; - // for (svector::const_iterator it = dataset.pos.begin(); it != dataset.pos.end(); ++it) - for (int curr = 0; curr < dataset.available( Dataset::POSITIVE); ++curr) - { - cv::Mat sample = dataset.get( Dataset::POSITIVE, curr); - - cv::Mat channels = integrals.row(total).reshape(0, h / shrinkage * 10 + 1); - sample = sample(boundingBox); - - pool->preprocess(sample, channels); - responses.ptr(total)[0] = 1.f; - - 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); -} - -void sft::Octave::generateNegatives(const Dataset& dataset, const FeaturePool* pool) -{ - // ToDo: set seed, use offsets - sft::Random::engine eng(65633343L); - sft::Random::engine idxEng(764224349868L); - - // int w = boundingBox.width; - int h = boundingBox.height; - - int nimages = dataset.available(Dataset::NEGATIVE); - sft::Random::uniform iRand(0, nimages - 1); - - int total = 0; - Mat sum; - for (int i = npositives; i < nnegatives + npositives; ++total) - { - int curr = iRand(idxEng); - - Mat frame = dataset.get(Dataset::NEGATIVE, curr); - - int maxW = frame.cols - 2 * boundingBox.x - boundingBox.width; - int maxH = frame.rows - 2 * boundingBox.y - boundingBox.height; - - sft::Random::uniform wRand(0, maxW -1); - sft::Random::uniform hRand(0, maxH -1); - - int dx = wRand(eng); - int dy = hRand(eng); - - frame = frame(cv::Rect(dx, dy, boundingBox.width, boundingBox.height)); - - cv::Mat channels = integrals.row(i).reshape(0, h / shrinkage * 10 + 1); - pool->preprocess(frame, channels); - - dprintf("generated %d %d\n", dx, dy); - - // // if (predict(sum)) - { - responses.ptr(i)[0] = 0.f; - ++i; - } - } - - dprintf("Processing negatives finished:\n\trequested %d negatives, viewed %d samples.\n", nnegatives, total); -} - - -template int sgn(T val) { - return (T(0) < val) - (val < T(0)); -} - -void sft::Octave::traverse(const CvBoostTree* tree, cv::FileStorage& fs, int& nfeatures, int* used, const double* th) const -{ - std::queue nodes; - nodes.push( tree->get_root()); - const CvDTreeNode* tempNode; - int leafValIdx = 0; - int internalNodeIdx = 1; - float* leafs = new float[(int)pow(2.f, get_params().max_depth)]; - - fs << "{"; - fs << "treeThreshold" << *th; - fs << "internalNodes" << "["; - while (!nodes.empty()) - { - tempNode = nodes.front(); - CV_Assert( tempNode->left ); - if ( !tempNode->left->left && !tempNode->left->right) - { - leafs[-leafValIdx] = (float)tempNode->left->value; - fs << leafValIdx-- ; - } - else - { - nodes.push( tempNode->left ); - fs << internalNodeIdx++; - } - CV_Assert( tempNode->right ); - if ( !tempNode->right->left && !tempNode->right->right) - { - leafs[-leafValIdx] = (float)tempNode->right->value; - fs << leafValIdx--; - } - else - { - nodes.push( tempNode->right ); - fs << internalNodeIdx++; - } - - int fidx = tempNode->split->var_idx; - fs << nfeatures; - used[nfeatures++] = fidx; - - fs << tempNode->split->ord.c; - - nodes.pop(); - } - fs << "]"; - - fs << "leafValues" << "["; - for (int ni = 0; ni < -leafValIdx; ni++) - fs << leafs[ni]; - fs << "]"; - - - fs << "}"; -} - -void sft::Octave::write( cv::FileStorage &fso, const FeaturePool* pool, const Mat& thresholds) const -{ - CV_Assert(!thresholds.empty()); - cv::Mat used( 1, weak->total * (pow(2, params.max_depth) - 1), CV_32SC1); - int* usedPtr = used.ptr(0); - int nfeatures = 0; - fso << "{" - << "scale" << logScale - << "weaks" << weak->total - << "trees" << "["; - // should be replased with the H.L. one - CvSeqReader reader; - cvStartReadSeq( weak, &reader); - - for(int i = 0; i < weak->total; i++ ) - { - CvBoostTree* tree; - CV_READ_SEQ_ELEM( tree, reader ); - - traverse(tree, fso, nfeatures, usedPtr, thresholds.ptr(0) + i); - } - fso << "]"; - // features - - fso << "features" << "["; - for (int i = 0; i < nfeatures; ++i) - pool->write(fso, usedPtr[i]); - fso << "]" - << "}"; -} - -void sft::Octave::initial_weights(double (&p)[2]) -{ - double n = data->sample_count; - p[0] = n / (2. * (double)(nnegatives)); - p[1] = n / (2. * (double)(npositives)); -} - -bool sft::Octave::train(const Dataset& dataset, const FeaturePool* pool, int weaks, int treeDepth) -{ - CV_Assert(treeDepth == 2); - CV_Assert(weaks > 0); - - params.max_depth = treeDepth; - params.weak_count = weaks; - - // 1. fill integrals and classes - processPositives(dataset, pool); - generateNegatives(dataset, pool); - - // 2. only sumple case (all features used) - int nfeatures = pool->size(); - cv::Mat varIdx(1, nfeatures, CV_32SC1); - int* ptr = varIdx.ptr(0); - - for (int x = 0; x < nfeatures; ++x) - ptr[x] = x; - - // 3. only sumple case (all samples used) - int nsamples = npositives + nnegatives; - cv::Mat sampleIdx(1, nsamples, CV_32SC1); - ptr = sampleIdx.ptr(0); - - for (int x = 0; x < nsamples; ++x) - ptr[x] = x; - - // 4. ICF has an orderable responce. - cv::Mat varType(1, nfeatures + 1, CV_8UC1); - uchar* uptr = varType.ptr(0); - for (int x = 0; x < nfeatures; ++x) - uptr[x] = CV_VAR_ORDERED; - uptr[nfeatures] = CV_VAR_CATEGORICAL; - - trainData.create(nfeatures, nsamples, CV_32FC1); - for (int fi = 0; fi < nfeatures; ++fi) - { - float* dptr = trainData.ptr(fi); - for (int si = 0; si < nsamples; ++si) - { - dptr[si] = pool->apply(fi, si, integrals); - } - } - - cv::Mat missingMask; - - bool ok = train(trainData, responses, varIdx, sampleIdx, varType, missingMask); - if (!ok) - std::cout << "ERROR: tree can not be trained " << std::endl; - return ok; - -} - -float sft::Octave::predict( const Mat& _sample, Mat& _votes, bool raw_mode, bool return_sum ) const -{ - CvMat sample = _sample, votes = _votes; - return CvBoost::predict(&sample, 0, (_votes.empty())? 0 : &votes, CV_WHOLE_SEQ, raw_mode, return_sum); -} - -float sft::Octave::predict( const Mat& _sample, const cv::Range range) const -{ - CvMat sample = _sample; - return CvBoost::predict(&sample, 0, 0, range, false, true); -} - -void sft::Octave::write( CvFileStorage* fs, string name) const -{ - CvBoost::write(fs, name.c_str()); -} - // ========= FeaturePool ========= // sft::ICFFeaturePool::ICFFeaturePool(cv::Size m, int n) : FeaturePool(), model(m), nfeatures(n) @@ -499,7 +162,7 @@ void glob(const string& path, svector& ret) // in the default case data folders should be alligned as following: // 1. positives: /octave_/pos/*.png // 2. negatives: /octave_/neg/*.png -Dataset::Dataset(const string& path, const int oct) +ScaledDataset::ScaledDataset(const string& path, const int oct) { dprintf("%s\n", "get dataset file names..."); @@ -514,13 +177,15 @@ Dataset::Dataset(const string& path, const int oct) CV_Assert(neg.size() != size_t(0)); } -cv::Mat Dataset::get(SampleType type, int idx) const +cv::Mat ScaledDataset::get(SampleType type, int idx) const { const std::string& src = (type == POSITIVE)? pos[idx]: neg[idx]; return cv::imread(src); } -int Dataset::available(SampleType type) const +int ScaledDataset::available(SampleType type) const { return (int)((type == POSITIVE)? pos.size():neg.size()); -} \ No newline at end of file +} + +ScaledDataset::~ScaledDataset(){} \ No newline at end of file diff --git a/apps/sft/sft.cpp b/apps/sft/sft.cpp index 8c40039..acc89f2 100644 --- a/apps/sft/sft.cpp +++ b/apps/sft/sft.cpp @@ -127,12 +127,12 @@ int main(int argc, char** argv) cv::Rect boundingBox = cfg.bbox(it); std::cout << "Object bounding box" << boundingBox << std::endl; - sft::Octave boost(boundingBox, npositives, nnegatives, *it, shrinkage); + cv::Octave boost(boundingBox, npositives, nnegatives, *it, shrinkage); std::string path = cfg.trainPath; - sft::Dataset dataset(path, boost.logScale); + sft::ScaledDataset dataset(path, boost.logScale); - if (boost.train(dataset, &pool, cfg.weaks, cfg.treeDepth)) + if (boost.train(&dataset, &pool, cfg.weaks, cfg.treeDepth)) { CvFileStorage* fout = cvOpenFileStorage(cfg.resPath(it).c_str(), 0, CV_STORAGE_WRITE); boost.write(fout, cfg.cascadeName); diff --git a/modules/ml/include/opencv2/ml/ml.hpp b/modules/ml/include/opencv2/ml/ml.hpp index ebc5814..98019eb 100644 --- a/modules/ml/include/opencv2/ml/ml.hpp +++ b/modules/ml/include/opencv2/ml/ml.hpp @@ -2142,7 +2142,72 @@ public: virtual void preprocess(const Mat& frame, Mat& integrals) const = 0; - virtual ~FeaturePool() = 0; + virtual ~FeaturePool(); +}; + +class Dataset +{ +public: + typedef enum {POSITIVE = 1, NEGATIVE = 2} SampleType; + + virtual cv::Mat get(SampleType type, int idx) const = 0; + virtual int available(SampleType type) const = 0; + virtual ~Dataset(); +}; + +// used for traning single octave scale +class Octave : cv::Boost +{ +public: + + enum + { + // Direct backward pruning. (Cha Zhang and Paul Viola) + DBP = 1, + // Multiple instance pruning. (Cha Zhang and Paul Viola) + MIP = 2, + // Originally proposed by L. bourdev and J. brandt + HEURISTIC = 4 + }; + + Octave(cv::Rect boundingBox, int npositives, int nnegatives, int logScale, int shrinkage); + virtual ~Octave(); + + virtual bool train(const Dataset* dataset, const FeaturePool* pool, int weaks, int treeDepth); + + virtual float predict( const Mat& _sample, Mat& _votes, bool raw_mode, bool return_sum ) const; + virtual void setRejectThresholds(cv::Mat& thresholds); + virtual void write( CvFileStorage* fs, string name) const; + + virtual void write( cv::FileStorage &fs, const FeaturePool* pool, const Mat& thresholds) const; + + int logScale; + +protected: + virtual bool train( const cv::Mat& trainData, const cv::Mat& responses, const cv::Mat& varIdx=cv::Mat(), + const cv::Mat& sampleIdx=cv::Mat(), const cv::Mat& varType=cv::Mat(), const cv::Mat& missingDataMask=cv::Mat()); + + void processPositives(const Dataset* dataset, const FeaturePool* pool); + void generateNegatives(const Dataset* dataset, const FeaturePool* pool); + + 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]); + + cv::Rect boundingBox; + + int npositives; + int nnegatives; + + int shrinkage; + + Mat integrals; + Mat responses; + + CvBoostParams params; + + Mat trainData; }; } diff --git a/modules/ml/src/octave.cpp b/modules/ml/src/octave.cpp index a7b7179..e8fc600 100644 --- a/modules/ml/src/octave.cpp +++ b/modules/ml/src/octave.cpp @@ -41,5 +41,419 @@ //M*/ #include "precomp.hpp" +#include -cv::FeaturePool::~FeaturePool(){} \ No newline at end of file +#define WITH_DEBUG_OUT + +#if defined WITH_DEBUG_OUT +# include +# define dprintf(format, ...) \ + do { printf(format, ##__VA_ARGS__); } while (0) +#else +# define dprintf(format, ...) +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1600 + +# include +namespace sft { +struct Random +{ + typedef std::mt19937 engine; + typedef std::uniform_int uniform; +}; +} + +#elif (__GNUC__) && __GNUC__ > 3 && __GNUC_MINOR__ > 1 + +# if defined (__cplusplus) && __cplusplus > 201100L +# include +namespace sft { +struct Random +{ + typedef std::mt19937 engine; + typedef std::uniform_int uniform; +}; +} +# else +# include + +namespace sft { +struct Random +{ + typedef std::tr1::mt19937 engine; + typedef std::tr1::uniform_int uniform; +}; +} +# endif + +#else +#include +namespace rnd { + +typedef cv::RNG engine; + +template +struct uniform_int +{ + uniform_int(const int _min, const int _max) : min(_min), max(_max) {} + T operator() (engine& eng, const int bound) const + { + return (T)eng.uniform(min, bound); + } + + T operator() (engine& eng) const + { + return (T)eng.uniform(min, max); + } + +private: + int min; + int max; +}; + +} + +namespace sft { +struct Random +{ + typedef rnd::engine engine; + typedef rnd::uniform_int uniform; +}; +} + +#endif + +cv::FeaturePool::~FeaturePool(){} +cv::Dataset::~Dataset(){} + +cv::Octave::Octave(cv::Rect bb, int np, int nn, int ls, int shr) +: logScale(ls), boundingBox(bb), npositives(np), nnegatives(nn), shrinkage(shr) +{ + int maxSample = npositives + nnegatives; + responses.create(maxSample, 1, CV_32FC1); + + CvBoostParams _params; + { + // tree params + _params.max_categories = 10; + _params.max_depth = 2; + _params.cv_folds = 0; + _params.truncate_pruned_tree = false; + _params.use_surrogates = false; + _params.use_1se_rule = false; + _params.regression_accuracy = 1.0e-6; + + // boost params + _params.boost_type = CvBoost::GENTLE; + _params.split_criteria = CvBoost::SQERR; + _params.weight_trim_rate = 0.95; + + // simple defaults + _params.min_sample_count = 2; + _params.weak_count = 1; + } + + params = _params; +} + +cv::Octave::~Octave(){} + +bool cv::Octave::train( const cv::Mat& _trainData, const cv::Mat& _responses, const cv::Mat& varIdx, + const cv::Mat& sampleIdx, const cv::Mat& varType, const cv::Mat& missingDataMask) +{ + bool update = false; + return cv::Boost::train(_trainData, CV_COL_SAMPLE, _responses, varIdx, sampleIdx, varType, missingDataMask, params, + update); +} + +void cv::Octave::setRejectThresholds(cv::Mat& thresholds) +{ + dprintf("set thresholds according to DBP strategy\n"); + + // labels desided by classifier + cv::Mat desisions(responses.cols, responses.rows, responses.type()); + float* dptr = desisions.ptr(0); + + // mask of samples satisfying the condition + cv::Mat ppmask(responses.cols, responses.rows, CV_8UC1); + uchar* mptr = ppmask.ptr(0); + + int nsamples = npositives + nnegatives; + + cv::Mat stab; + + for (int si = 0; si < nsamples; ++si) + { + float decision = dptr[si] = predict(trainData.col(si), stab, false, false); + mptr[si] = cv::saturate_cast((uint)( (responses.ptr(si)[0] == 1.f) && (decision == 1.f))); + } + + int weaks = weak->total; + thresholds.create(1, weaks, CV_64FC1); + double* thptr = thresholds.ptr(0); + + cv::Mat traces(weaks, nsamples, CV_64FC1, cv::Scalar::all(FLT_MAX)); + + for (int w = 0; w < weaks; ++w) + { + double* rptr = traces.ptr(w); + for (int si = 0; si < nsamples; ++si) + { + cv::Range curr(0, w + 1); + if (mptr[si]) + { + float trace = predict(trainData.col(si), curr); + rptr[si] = trace; + } + } + double mintrace = 0.; + cv::minMaxLoc(traces.row(w), &mintrace); + thptr[w] = mintrace; + } +} + +void cv::Octave::processPositives(const Dataset* dataset, const FeaturePool* pool) +{ + int w = boundingBox.width; + int h = boundingBox.height; + + integrals.create(pool->size(), (w / shrinkage + 1) * (h / shrinkage * 10 + 1), CV_32SC1); + + int total = 0; + // for (svector::const_iterator it = dataset.pos.begin(); it != dataset.pos.end(); ++it) + for (int curr = 0; curr < dataset->available( Dataset::POSITIVE); ++curr) + { + cv::Mat sample = dataset->get( Dataset::POSITIVE, curr); + + cv::Mat channels = integrals.row(total).reshape(0, h / shrinkage * 10 + 1); + sample = sample(boundingBox); + + pool->preprocess(sample, channels); + responses.ptr(total)[0] = 1.f; + + 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); +} + +void cv::Octave::generateNegatives(const Dataset* dataset, const FeaturePool* pool) +{ + // ToDo: set seed, use offsets + sft::Random::engine eng(65633343L); + sft::Random::engine idxEng(764224349868L); + + // int w = boundingBox.width; + int h = boundingBox.height; + + int nimages = dataset->available(Dataset::NEGATIVE); + sft::Random::uniform iRand(0, nimages - 1); + + int total = 0; + Mat sum; + for (int i = npositives; i < nnegatives + npositives; ++total) + { + int curr = iRand(idxEng); + + Mat frame = dataset->get(Dataset::NEGATIVE, curr); + + int maxW = frame.cols - 2 * boundingBox.x - boundingBox.width; + int maxH = frame.rows - 2 * boundingBox.y - boundingBox.height; + + sft::Random::uniform wRand(0, maxW -1); + sft::Random::uniform hRand(0, maxH -1); + + int dx = wRand(eng); + int dy = hRand(eng); + + frame = frame(cv::Rect(dx, dy, boundingBox.width, boundingBox.height)); + + cv::Mat channels = integrals.row(i).reshape(0, h / shrinkage * 10 + 1); + pool->preprocess(frame, channels); + + dprintf("generated %d %d\n", dx, dy); + + // // if (predict(sum)) + { + responses.ptr(i)[0] = 0.f; + ++i; + } + } + + dprintf("Processing negatives finished:\n\trequested %d negatives, viewed %d samples.\n", nnegatives, total); +} + + +template int sgn(T val) { + return (T(0) < val) - (val < T(0)); +} + +void cv::Octave::traverse(const CvBoostTree* tree, cv::FileStorage& fs, int& nfeatures, int* used, const double* th) const +{ + std::queue nodes; + nodes.push( tree->get_root()); + const CvDTreeNode* tempNode; + int leafValIdx = 0; + int internalNodeIdx = 1; + float* leafs = new float[(int)pow(2.f, get_params().max_depth)]; + + fs << "{"; + fs << "treeThreshold" << *th; + fs << "internalNodes" << "["; + while (!nodes.empty()) + { + tempNode = nodes.front(); + CV_Assert( tempNode->left ); + if ( !tempNode->left->left && !tempNode->left->right) + { + leafs[-leafValIdx] = (float)tempNode->left->value; + fs << leafValIdx-- ; + } + else + { + nodes.push( tempNode->left ); + fs << internalNodeIdx++; + } + CV_Assert( tempNode->right ); + if ( !tempNode->right->left && !tempNode->right->right) + { + leafs[-leafValIdx] = (float)tempNode->right->value; + fs << leafValIdx--; + } + else + { + nodes.push( tempNode->right ); + fs << internalNodeIdx++; + } + + int fidx = tempNode->split->var_idx; + fs << nfeatures; + used[nfeatures++] = fidx; + + fs << tempNode->split->ord.c; + + nodes.pop(); + } + fs << "]"; + + fs << "leafValues" << "["; + for (int ni = 0; ni < -leafValIdx; ni++) + fs << leafs[ni]; + fs << "]"; + + + fs << "}"; +} + +void cv::Octave::write( cv::FileStorage &fso, const FeaturePool* pool, const Mat& thresholds) const +{ + CV_Assert(!thresholds.empty()); + cv::Mat used( 1, weak->total * (pow(2, params.max_depth) - 1), CV_32SC1); + int* usedPtr = used.ptr(0); + int nfeatures = 0; + fso << "{" + << "scale" << logScale + << "weaks" << weak->total + << "trees" << "["; + // should be replased with the H.L. one + CvSeqReader reader; + cvStartReadSeq( weak, &reader); + + for(int i = 0; i < weak->total; i++ ) + { + CvBoostTree* tree; + CV_READ_SEQ_ELEM( tree, reader ); + + traverse(tree, fso, nfeatures, usedPtr, thresholds.ptr(0) + i); + } + fso << "]"; + // features + + fso << "features" << "["; + for (int i = 0; i < nfeatures; ++i) + pool->write(fso, usedPtr[i]); + fso << "]" + << "}"; +} + +void cv::Octave::initial_weights(double (&p)[2]) +{ + double n = data->sample_count; + p[0] = n / (2. * (double)(nnegatives)); + p[1] = n / (2. * (double)(npositives)); +} + +bool cv::Octave::train(const Dataset* dataset, const FeaturePool* pool, int weaks, int treeDepth) +{ + CV_Assert(treeDepth == 2); + CV_Assert(weaks > 0); + + params.max_depth = treeDepth; + params.weak_count = weaks; + + // 1. fill integrals and classes + processPositives(dataset, pool); + generateNegatives(dataset, pool); + + // 2. only sumple case (all features used) + int nfeatures = pool->size(); + cv::Mat varIdx(1, nfeatures, CV_32SC1); + int* ptr = varIdx.ptr(0); + + for (int x = 0; x < nfeatures; ++x) + ptr[x] = x; + + // 3. only sumple case (all samples used) + int nsamples = npositives + nnegatives; + cv::Mat sampleIdx(1, nsamples, CV_32SC1); + ptr = sampleIdx.ptr(0); + + for (int x = 0; x < nsamples; ++x) + ptr[x] = x; + + // 4. ICF has an orderable responce. + cv::Mat varType(1, nfeatures + 1, CV_8UC1); + uchar* uptr = varType.ptr(0); + for (int x = 0; x < nfeatures; ++x) + uptr[x] = CV_VAR_ORDERED; + uptr[nfeatures] = CV_VAR_CATEGORICAL; + + trainData.create(nfeatures, nsamples, CV_32FC1); + for (int fi = 0; fi < nfeatures; ++fi) + { + float* dptr = trainData.ptr(fi); + for (int si = 0; si < nsamples; ++si) + { + dptr[si] = pool->apply(fi, si, integrals); + } + } + + cv::Mat missingMask; + + bool ok = train(trainData, responses, varIdx, sampleIdx, varType, missingMask); + if (!ok) + std::cout << "ERROR: tree can not be trained " << std::endl; + return ok; + +} + +float cv::Octave::predict( const Mat& _sample, Mat& _votes, bool raw_mode, bool return_sum ) const +{ + CvMat sample = _sample, votes = _votes; + return CvBoost::predict(&sample, 0, (_votes.empty())? 0 : &votes, CV_WHOLE_SEQ, raw_mode, return_sum); +} + +float cv::Octave::predict( const Mat& _sample, const cv::Range range) const +{ + CvMat sample = _sample; + return CvBoost::predict(&sample, 0, 0, range, false, true); +} + +void cv::Octave::write( CvFileStorage* fs, string name) const +{ + CvBoost::write(fs, name.c_str()); +} -- 2.7.4