From a0e93d04826d20d486654e5d9f4afe41532b04cd Mon Sep 17 00:00:00 2001 From: "marina.kolpakova" Date: Wed, 9 Jan 2013 15:21:04 +0400 Subject: [PATCH] move image extraction logic from Octave to Dataset class --- apps/sft/include/sft/octave.hpp | 92 +++++++++++++++++++++++--- apps/sft/octave.cpp | 98 +++++++--------------------- modules/ml/include/opencv2/ml/ml.hpp | 2 + 3 files changed, 109 insertions(+), 83 deletions(-) diff --git a/apps/sft/include/sft/octave.hpp b/apps/sft/include/sft/octave.hpp index 1ab5e40300..1d19cdba0b 100644 --- a/apps/sft/include/sft/octave.hpp +++ b/apps/sft/include/sft/octave.hpp @@ -46,17 +46,70 @@ #include #include +#include +#include namespace sft { -class Dataset +class Preprocessor { public: - Dataset(const sft::string& path, const int octave); + Preprocessor() {} -// private: - svector pos; - svector neg; + void apply(const cv::Mat& frame, cv::Mat& integrals) const + { + CV_Assert(frame.type() == CV_8UC3); + + int h = frame.rows; + int w = frame.cols; + + cv::Mat channels, gray; + + channels.create(h * BINS, w, CV_8UC1); + channels.setTo(0); + + cvtColor(frame, gray, CV_BGR2GRAY); + + cv::Mat df_dx, df_dy, mag, angle; + cv::Sobel(gray, df_dx, CV_32F, 1, 0); + cv::Sobel(gray, df_dy, CV_32F, 0, 1); + + cv::cartToPolar(df_dx, df_dy, mag, angle, true); + mag *= (1.f / (8 * sqrt(2.f))); + + cv::Mat nmag; + mag.convertTo(nmag, CV_8UC1); + + angle *= 6 / 360.f; + + for (int y = 0; y < h; ++y) + { + uchar* magnitude = nmag.ptr(y); + float* ang = angle.ptr(y); + + for (int x = 0; x < w; ++x) + { + channels.ptr(y + (h * (int)ang[x]))[x] = magnitude[x]; + } + } + + cv::Mat luv, shrunk; + cv::cvtColor(frame, luv, CV_BGR2Luv); + + std::vector splited; + for (int i = 0; i < 3; ++i) + splited.push_back(channels(cv::Rect(0, h * (7 + i), w, h))); + split(luv, splited); + + float shrinkage = static_cast(integrals.cols - 1) / channels.cols; + + CV_Assert(shrinkage == 0.25); + + cv::resize(channels, shrunk, cv::Size(), shrinkage, shrinkage, CV_INTER_AREA); + cv::integral(shrunk, integrals, cv::noArray(), CV_32S); + } + + enum {BINS = 10}; }; struct ICF @@ -74,7 +127,7 @@ struct ICF } - float operator() (const Mat& integrals, const cv::Size& model) const + float operator() (const cv::Mat& integrals, const cv::Size& model) const { int step = model.width + 1; @@ -95,11 +148,11 @@ private: cv::Rect bb; int channel; - friend void write(cv::FileStorage& fs, const string&, const ICF& f); + friend void write(cv::FileStorage& fs, const std::string&, const ICF& f); friend std::ostream& operator<<(std::ostream& out, const ICF& f); }; -void write(cv::FileStorage& fs, const string&, const ICF& f); +void write(cv::FileStorage& fs, const std::string&, const ICF& f); std::ostream& operator<<(std::ostream& out, const ICF& m); class ICFFeaturePool : public cv::FeaturePool @@ -108,7 +161,8 @@ public: ICFFeaturePool(cv::Size model, int nfeatures); virtual int size() const { return (int)pool.size(); } - virtual float apply(int fi, int si, const Mat& integrals) const; + virtual float apply(int fi, int si, const cv::Mat& integrals) const; + virtual void preprocess(const cv::Mat& frame, cv::Mat& integrals) const; virtual void write( cv::FileStorage& fs, int index) const; virtual ~ICFFeaturePool(); @@ -124,12 +178,30 @@ private: static const unsigned int seed = 0; + Preprocessor preprocessor; + enum { N_CHANNELS = 10 }; }; using cv::FeaturePool; + + +class Dataset +{ +public: + typedef enum {POSITIVE = 1, NEGATIVE = 2} SampleType; + Dataset(const sft::string& path, const int octave); + + cv::Mat get(SampleType type, int idx) const; + int available(SampleType type) const; + +private: + svector pos; + svector neg; +}; + // used for traning single octave scale class Octave : cv::Boost { @@ -163,7 +235,7 @@ protected: 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); + void generateNegatives(const Dataset& dataset, const FeaturePool* pool); float predict( const Mat& _sample, const cv::Range range) const; private: diff --git a/apps/sft/octave.cpp b/apps/sft/octave.cpp index 693b7b90d9..eac165d7f8 100644 --- a/apps/sft/octave.cpp +++ b/apps/sft/octave.cpp @@ -44,9 +44,6 @@ #include #include -#include -#include - #include // ============ Octave ============ // @@ -138,85 +135,26 @@ void sft::Octave::setRejectThresholds(cv::Mat& thresholds) namespace { using namespace sft; -class Preprocessor -{ -public: - Preprocessor(int shr) : shrinkage(shr) {} - void apply(const Mat& frame, Mat& integrals) - { - CV_Assert(frame.type() == CV_8UC3); - - int h = frame.rows; - int w = frame.cols; - - cv::Mat channels, gray; - - channels.create(h * BINS, w, CV_8UC1); - channels.setTo(0); - - cvtColor(frame, gray, CV_BGR2GRAY); - - cv::Mat df_dx, df_dy, mag, angle; - cv::Sobel(gray, df_dx, CV_32F, 1, 0); - cv::Sobel(gray, df_dy, CV_32F, 0, 1); - - cv::cartToPolar(df_dx, df_dy, mag, angle, true); - mag *= (1.f / (8 * sqrt(2.f))); - - cv::Mat nmag; - mag.convertTo(nmag, CV_8UC1); - - angle *= 6 / 360.f; - - for (int y = 0; y < h; ++y) - { - uchar* magnitude = nmag.ptr(y); - float* ang = angle.ptr(y); - - for (int x = 0; x < w; ++x) - { - channels.ptr(y + (h * (int)ang[x]))[x] = magnitude[x]; - } - } - - cv::Mat luv, shrunk; - cv::cvtColor(frame, luv, CV_BGR2Luv); - - std::vector splited; - for (int i = 0; i < 3; ++i) - splited.push_back(channels(cv::Rect(0, h * (7 + i), w, h))); - split(luv, splited); - - cv::resize(channels, shrunk, cv::Size(), 1.0 / shrinkage, 1.0 / shrinkage, CV_INTER_AREA); - cv::integral(shrunk, integrals, cv::noArray(), CV_32S); - } - - int shrinkage; - enum {BINS = 10}; -}; } void sft::Octave::processPositives(const Dataset& dataset, const FeaturePool* pool) { - Preprocessor prepocessor(shrinkage); - 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 (svector::const_iterator it = dataset.pos.begin(); it != dataset.pos.end(); ++it) + for (int curr = 0; curr < dataset.available( Dataset::POSITIVE); ++curr) { - const string& curr = *it; - - cv::Mat sample = cv::imread(curr); + cv::Mat sample = dataset.get( Dataset::POSITIVE, curr); cv::Mat channels = integrals.row(total).reshape(0, h / shrinkage * 10 + 1); sample = sample(boundingBox); - prepocessor.apply(sample, channels); + pool->preprocess(sample, channels); responses.ptr(total)[0] = 1.f; if (++total >= npositives) break; @@ -228,7 +166,7 @@ void sft::Octave::processPositives(const Dataset& dataset, const FeaturePool* po nnegatives = cvRound(nnegatives * total / (double)npositives); } -void sft::Octave::generateNegatives(const Dataset& dataset) +void sft::Octave::generateNegatives(const Dataset& dataset, const FeaturePool* pool) { // ToDo: set seed, use offsets sft::Random::engine eng(65633343L); @@ -237,9 +175,7 @@ void sft::Octave::generateNegatives(const Dataset& dataset) // int w = boundingBox.width; int h = boundingBox.height; - Preprocessor prepocessor(shrinkage); - - int nimages = (int)dataset.neg.size(); + int nimages = dataset.available(Dataset::NEGATIVE); sft::Random::uniform iRand(0, nimages - 1); int total = 0; @@ -248,7 +184,7 @@ void sft::Octave::generateNegatives(const Dataset& dataset) { int curr = iRand(idxEng); - Mat frame = cv::imread(dataset.neg[curr]); + 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; @@ -262,7 +198,7 @@ void sft::Octave::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); - prepocessor.apply(frame, channels); + pool->preprocess(frame, channels); dprintf("generated %d %d\n", dx, dy); @@ -386,7 +322,7 @@ bool sft::Octave::train(const Dataset& dataset, const FeaturePool* pool, int wea // 1. fill integrals and classes processPositives(dataset, pool); - generateNegatives(dataset); + generateNegatives(dataset, pool); // 2. only sumple case (all features used) int nfeatures = pool->size(); @@ -455,6 +391,11 @@ sft::ICFFeaturePool::ICFFeaturePool(cv::Size m, int n) : FeaturePool(), model(m) fill(nfeatures); } +void sft::ICFFeaturePool::preprocess(const Mat& frame, Mat& integrals) const +{ + preprocessor.apply(frame, integrals); +} + float sft::ICFFeaturePool::apply(int fi, int si, const Mat& integrals) const { return pool[fi](integrals.row(si), model); @@ -571,4 +512,15 @@ Dataset::Dataset(const string& path, const int oct) // Check: files not empty CV_Assert(pos.size() != size_t(0)); CV_Assert(neg.size() != size_t(0)); +} + +cv::Mat Dataset::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 +{ + return (int)((type == POSITIVE)? pos.size():neg.size()); } \ No newline at end of file diff --git a/modules/ml/include/opencv2/ml/ml.hpp b/modules/ml/include/opencv2/ml/ml.hpp index 775fab535e..ebc5814d21 100644 --- a/modules/ml/include/opencv2/ml/ml.hpp +++ b/modules/ml/include/opencv2/ml/ml.hpp @@ -2140,6 +2140,8 @@ public: virtual float apply(int fi, int si, const Mat& integrals) const = 0; virtual void write( cv::FileStorage& fs, int index) const = 0; + virtual void preprocess(const Mat& frame, Mat& integrals) const = 0; + virtual ~FeaturePool() = 0; };