diff --git a/modules/xobjdetect/include/opencv2/xobjdetect.hpp b/modules/xobjdetect/include/opencv2/xobjdetect.hpp index d84f7b240..88f21e58f 100644 --- a/modules/xobjdetect/include/opencv2/xobjdetect.hpp +++ b/modules/xobjdetect/include/opencv2/xobjdetect.hpp @@ -58,9 +58,9 @@ namespace xobjdetect channels — output array for computed channels */ -void computeChannels(InputArray image, std::vector& channels); +CV_EXPORTS void computeChannels(InputArray image, std::vector& channels); -class CV_EXPORTS ACFFeatureEvaluator : public Algorithm +class CV_EXPORTS FeatureEvaluator : public Algorithm { public: /* Set channels for feature evaluation */ @@ -69,8 +69,6 @@ public: /* Set window position */ virtual void setPosition(Size position) = 0; - virtual void assertChannels() = 0; - /* Evaluate feature with given index for current channels and window position */ virtual int evaluate(size_t feature_ind) const = 0; @@ -81,23 +79,28 @@ public: */ virtual void evaluateAll(OutputArray feature_values) const = 0; + virtual void assertChannels() = 0; }; -/* Construct evaluator, set features to evaluate */ -CV_EXPORTS Ptr -createACFFeatureEvaluator(const std::vector& features); +/* Construct feature evaluator, set features to evaluate + type can "icf" or "acf" */ +CV_EXPORTS Ptr +createFeatureEvaluator(const std::vector >& features, + const std::string& type); /* Generate acf features window_size — size of window in which features should be evaluated + type — type of features, can be "icf" or "acf" count — number of features to generate. Max number of features is min(count, # possible distinct features) Returns vector of distinct acf features */ -std::vector -generateFeatures(Size window_size, int count = INT_MAX); +std::vector > +generateFeatures(Size window_size, const std::string& type, + int count = INT_MAX, int channel_count = 10); struct CV_EXPORTS WaldBoostParams @@ -135,7 +138,7 @@ public: is from class +1 */ virtual float predict( - const Ptr& /*feature_evaluator*/) const + const Ptr& /*feature_evaluator*/) const {return 0.0f;} /* Write WaldBoost to FileStorage */ @@ -207,7 +210,7 @@ public: private: Ptr waldboost_; - std::vector features_; + std::vector > features_; int model_n_rows_; int model_n_cols_; }; diff --git a/modules/xobjdetect/src/acffeature.cpp b/modules/xobjdetect/src/acffeature.cpp index addffae40..30bc9fbc6 100644 --- a/modules/xobjdetect/src/acffeature.cpp +++ b/modules/xobjdetect/src/acffeature.cpp @@ -54,75 +54,126 @@ namespace cv namespace xobjdetect { -class ACFFeatureEvaluatorImpl : public ACFFeatureEvaluator +static bool isNull(const Mat_ &m) +{ + bool null_data = true; + for( int row = 0; row < m.rows; ++row ) + { + for( int col = 0; col < m.cols; ++col ) + if( m.at(row, col) ) + null_data = false; + } + return null_data; +} + +class FeatureEvaluatorImpl : public FeatureEvaluator { public: - ACFFeatureEvaluatorImpl(const vector& features): + FeatureEvaluatorImpl(const vector >& features): features_(features), channels_(), position_() { CV_Assert(features.size() > 0); } - virtual void setChannels(InputArrayOfArrays channels); - virtual void assertChannels(); - virtual void setPosition(Size position); - virtual int evaluate(size_t feature_ind) const; - virtual void evaluateAll(OutputArray feature_values) const; + virtual void assertChannels() + { + bool null_data = true; + for( size_t i = 0; i < channels_.size(); ++i ) + null_data &= isNull(channels_[i]); + CV_Assert(!null_data); + } + + virtual void evaluateAll(OutputArray feature_values) const + { + Mat_ feature_vals(1, (int)features_.size()); + for( int i = 0; i < (int)features_.size(); ++i ) + { + feature_vals(0, i) = evaluate(i); + } + feature_values.assign(feature_vals); + } -private: +protected: /* Features to evaluate */ - std::vector features_; + vector > features_; /* Channels for feature evaluation */ std::vector channels_; /* Channels window position */ Size position_; }; - -static bool isNull(const Mat_ &m) +class ICFFeatureEvaluatorImpl : public FeatureEvaluatorImpl { - bool null_data = true; - for( int row = 0; row < m.rows; ++row ) +public: + ICFFeatureEvaluatorImpl(const vector >& features): + FeatureEvaluatorImpl(features) { - for( int col = 0; col < m.cols; ++col ) - if( m.at(row, col) ) - null_data = false; } - return null_data; -} -void ACFFeatureEvaluatorImpl::assertChannels() -{ - bool null_data = true; - for( size_t i = 0; i < channels_.size(); ++i ) - null_data &= isNull(channels_[i]); - CV_Assert(!null_data); -} + virtual void setChannels(InputArrayOfArrays channels); + virtual void setPosition(Size position); + virtual int evaluate(size_t feature_ind) const; +}; -void ACFFeatureEvaluatorImpl::setChannels(cv::InputArrayOfArrays channels) +void ICFFeatureEvaluatorImpl::setChannels(InputArrayOfArrays channels) { channels_.clear(); vector ch; channels.getMatVector(ch); CV_Assert(ch.size() == 10); - /*int min_val = 100500, max_val = -1; for( size_t i = 0; i < ch.size(); ++i ) { const Mat &channel = ch[i]; - for( int row = 0; row < channel.rows; ++row ) - for( int col = 0; col < channel.cols; ++col ) - { - int val = (int)channel.at(row, col); - if( val < min_val ) - min_val = val; - else if( val > max_val ) - max_val = val; - } + Mat integral_channel; + integral(channel, integral_channel, CV_32F); + Mat_ chan(integral_channel.rows, integral_channel.cols); + for( int row = 0; row < integral_channel.rows; ++row ) + for( int col = 0; col < integral_channel.cols; ++col ) + chan(row, col) = (int)integral_channel.at(row, col); + channels_.push_back(chan.clone()); } +} + +void ICFFeatureEvaluatorImpl::setPosition(Size position) +{ + position_ = position; +} + +int ICFFeatureEvaluatorImpl::evaluate(size_t feature_ind) const +{ + CV_Assert(channels_.size() == 10); + CV_Assert(feature_ind < features_.size()); + + const vector& feature = features_[feature_ind]; + int x = feature[0] + position_.height; + int y = feature[1] + position_.width; + int x_to = feature[2] + position_.height; + int y_to = feature[3] + position_.width; + int n = feature[4]; + const Mat_& ch = channels_[n]; + return ch(y_to + 1, x_to + 1) - ch(y, x_to + 1) - ch(y_to + 1, x) + ch(y, x); +} + +class ACFFeatureEvaluatorImpl : public FeatureEvaluatorImpl +{ +public: + ACFFeatureEvaluatorImpl(const vector >& features): + FeatureEvaluatorImpl(features) + { + } + + virtual void setChannels(InputArrayOfArrays channels); + virtual void setPosition(Size position); + virtual int evaluate(size_t feature_ind) const; +}; - cout << "SET " << min_val << " " << max_val << endl; - */ +void ACFFeatureEvaluatorImpl::setChannels(InputArrayOfArrays channels) +{ + channels_.clear(); + vector ch; + channels.getMatVector(ch); + CV_Assert(ch.size() == 10); for( size_t i = 0; i < ch.size(); ++i ) { @@ -135,11 +186,7 @@ void ACFFeatureEvaluatorImpl::setChannels(cv::InputArrayOfArrays channels) int sum = 0; for( int cell_row = row; cell_row < row + 4; ++cell_row ) for( int cell_col = col; cell_col < col + 4; ++cell_col ) - { - //cout << channel.rows << " " << channel.cols << endl; - //cout << cell_row << " " << cell_col << endl; sum += (int)channel.at(cell_row, cell_col); - } acf_channel(row / 4, col / 4) = sum; } @@ -159,49 +206,66 @@ int ACFFeatureEvaluatorImpl::evaluate(size_t feature_ind) const CV_Assert(channels_.size() == 10); CV_Assert(feature_ind < features_.size()); - Point3i feature = features_.at(feature_ind); - int x = feature.x; - int y = feature.y; - int n = feature.z; + const vector& feature = features_[feature_ind]; + int x = feature[0]; + int y = feature[1]; + int n = feature[2]; return channels_[n].at(y + position_.width, x + position_.height); } -void ACFFeatureEvaluatorImpl::evaluateAll(OutputArray feature_values) const +Ptr createFeatureEvaluator( + const vector >& features, const std::string& type) { - Mat_ feature_vals(1, (int)features_.size()); - for( int i = 0; i < (int)features_.size(); ++i ) - { - feature_vals(0, i) = evaluate(i); - } - feature_values.assign(feature_vals); + FeatureEvaluator *evaluator = NULL; + if( type == "acf" ) + evaluator = new ACFFeatureEvaluatorImpl(features); + else if( type == "icf" ) + evaluator = new ICFFeatureEvaluatorImpl(features); + else + CV_Assert(false); + + return Ptr(evaluator); } -Ptr -createACFFeatureEvaluator(const vector& features) -{ - return Ptr(new ACFFeatureEvaluatorImpl(features)); -} - -vector generateFeatures(Size window_size, int count) +vector > generateFeatures(Size window_size, const std::string& type, + int count, int channel_count) { CV_Assert(count > 0); - int cur_count = 0; - int max_count = window_size.width * window_size.height / 16; - count = min(count, max_count); - vector features; - for( int x = 0; x < window_size.width / 4; ++x ) + vector > features; + if( type == "acf" ) { - for( int y = 0; y < window_size.height / 4; ++y ) + int cur_count = 0; + int max_count = window_size.width * window_size.height / 16; + count = min(count, max_count); + for( int x = 0; x < window_size.width / 4; ++x ) + for( int y = 0; y < window_size.height / 4; ++y ) + for( int n = 0; n < channel_count; ++n ) + { + int f[] = {x, y, n}; + vector feature(f, f + sizeof(f) / sizeof(*f)); + features.push_back(feature); + if( (cur_count += 1) == count ) + break; + } + } + else if( type == "icf" ) + { + RNG rng; + for( int i = 0; i < count; ++i ) { - /* Assume there are 10 channel types */ - for( int n = 0; n < 10; ++n ) - { - features.push_back(Point3i(x, y, n)); - if( (cur_count += 1) == count ) - break; - } + int x = rng.uniform(0, window_size.width - 1); + int y = rng.uniform(0, window_size.height - 1); + int x_to = rng.uniform(x, window_size.width - 1); + int y_to = rng.uniform(y, window_size.height - 1); + int n = rng.uniform(0, channel_count - 1); + int f[] = {x, y, x_to, y_to, n}; + vector feature(f, f + sizeof(f) / sizeof(*f)); + features.push_back(feature); } } + else + CV_Assert(false); + return features; } diff --git a/modules/xobjdetect/src/icfdetector.cpp b/modules/xobjdetect/src/icfdetector.cpp index 32a3a748f..d2f28c143 100644 --- a/modules/xobjdetect/src/icfdetector.cpp +++ b/modules/xobjdetect/src/icfdetector.cpp @@ -118,8 +118,9 @@ void ICFDetector::train(const String& pos_path, for( int i = pos_count; i < pos_count + neg_count; ++i ) labels(0, i) = -1; - vector features = generateFeatures(model_size); - Ptr feature_evaluator = createACFFeatureEvaluator(features); + vector > features = generateFeatures(model_size, "icf", + params.feature_count); + Ptr evaluator = createFeatureEvaluator(features, "icf"); Mat_ data = Mat_::zeros((int)features.size(), (int)samples.size()); Mat_ feature_col(1, (int)samples.size()); @@ -129,9 +130,9 @@ void ICFDetector::train(const String& pos_path, { cout << setw(6) << i << "/" << samples.size() << "\r"; computeChannels(samples[i], channels); - feature_evaluator->setChannels(channels); - //feature_evaluator->assertChannels(); - feature_evaluator->evaluateAll(feature_col); + evaluator->setChannels(channels); + //evaluator->assertChannels(); + evaluator->evaluateAll(feature_col); CV_Assert(feature_col.cols == (int)features.size()); @@ -180,7 +181,7 @@ void ICFDetector::read(const FileNode& node) node["waldboost"] >> *waldboost_; FileNode features = node["features"]; features_.clear(); - Point3i p; + vector p; for( FileNodeIterator n = features.begin(); n != features.end(); ++n ) { (*n) >> p; @@ -196,7 +197,7 @@ void ICFDetector::detect(const Mat& img, vector& objects, float scale_to = max(model_n_cols_ / (float)minSize.width, model_n_rows_ / (float)minSize.height); objects.clear(); - Ptr evaluator = createACFFeatureEvaluator(features_); + Ptr evaluator = createFeatureEvaluator(features_, "icf"); Mat rescaled_image; int step = 8; vector channels; diff --git a/modules/xobjdetect/src/waldboost.cpp b/modules/xobjdetect/src/waldboost.cpp index 6b52c766c..39bd7c15d 100644 --- a/modules/xobjdetect/src/waldboost.cpp +++ b/modules/xobjdetect/src/waldboost.cpp @@ -67,7 +67,7 @@ public: const Mat& labels); virtual float predict( - const Ptr& feature_evaluator) const; + const Ptr& feature_evaluator) const; virtual void write(FileStorage& fs) const; @@ -299,7 +299,7 @@ vector WaldBoostImpl::train(const Mat& data_, const Mat& labels_) } float WaldBoostImpl::predict( - const Ptr& feature_evaluator) const + const Ptr& feature_evaluator) const { float trace = 0; CV_Assert(stumps_.size() == thresholds_.size());