Commit cdbe3352 authored by Vadim Pisarevsky's avatar Vadim Pisarevsky

Merge pull request #291 from shahurik:master

parents 2b64abdb ab72b24a
if(IOS)
ocv_module_disable(adas)
endif()
set(the_description "Automatic driver assistance algorithms")
ocv_define_module(adas opencv_xobjdetect)
add_subdirectory(tools)
ADAS: Advanced Driver Assistance Systems module with Forward Collision Warning
==============================================================================
\ No newline at end of file
add_subdirectory(fcw_train)
add_subdirectory(fcw_detect)
set(name fcw_detect)
set(the_target opencv_${name})
set(OPENCV_${the_target}_DEPS opencv_core opencv_imgcodecs opencv_videoio
opencv_highgui opencv_xobjdetect)
ocv_check_dependencies(${OPENCV_${the_target}_DEPS})
if(NOT OCV_DEPENDENCIES_FOUND)
return()
endif()
project(${the_target})
ocv_include_directories("${OpenCV_SOURCE_DIR}/include/opencv")
ocv_include_modules_recurse(${OPENCV_${the_target}_DEPS})
file(GLOB ${the_target}_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
add_executable(${the_target} ${${the_target}_SOURCES})
target_link_libraries(${the_target} ${OPENCV_${the_target}_DEPS})
set_target_properties(${the_target} PROPERTIES
DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}"
ARCHIVE_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH}
RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}
INSTALL_NAME_DIR lib
OUTPUT_NAME ${the_target})
if(ENABLE_SOLUTION_FOLDERS)
set_target_properties(${the_target} PROPERTIES FOLDER "applications")
endif()
install(TARGETS ${the_target} OPTIONAL RUNTIME DESTINATION bin COMPONENT main)
#include <string>
using std::string;
#include <vector>
using std::vector;
#include <iostream>
using std::cerr;
using std::endl;
#include <opencv2/core.hpp>
using cv::Rect;
using cv::Size;
using cv::Mat;
using cv::Mat_;
using cv::Vec3b;
#include <opencv2/highgui.hpp>
using cv::imread;
using cv::imwrite;
#include <opencv2/core/utility.hpp>
using cv::CommandLineParser;
using cv::FileStorage;
#include <opencv2/xobjdetect.hpp>
using cv::xobjdetect::ICFDetector;
static Mat visualize(const Mat &image, const vector<Rect> &objects)
{
CV_Assert(image.type() == CV_8UC3);
Mat_<Vec3b> img = image.clone();
for( size_t j = 0; j < objects.size(); ++j )
{
Rect obj = objects[j];
int x = obj.x;
int y = obj.y;
int width = obj.width;
int height = obj.height;
for( int i = y; i <= y + height; ++i ) {
img(i, x) = Vec3b(255, 0, 0);
img(i, x + width) = Vec3b(255, 0, 0);
}
for( int i = x; i <= x + width; ++i) {
img(y, i) = Vec3b(255, 0, 0);
img(y + height, i) = Vec3b(255, 0, 0);
}
}
return img;
}
static bool read_window_size(const char *str, int *rows, int *cols)
{
int pos = 0;
if( sscanf(str, "%dx%d%n", rows, cols, &pos) != 2 || str[pos] != '\0' ||
*rows <= 0 || *cols <= 0)
{
return false;
}
return true;
}
int main(int argc, char *argv[])
{
const string keys =
"{help | | print this message}"
"{model_filename | model.xml | filename for reading model}"
"{image_path | test.png | path to image for detection}"
"{out_image_path | out.png | path to image for output}"
"{threshold | 0.0 | threshold for cascade}"
"{step | 8 | sliding window step}"
"{min_window_size | 40x40 | min window size in pixels}"
"{max_window_size | 300x300 | max window size in pixels}"
"{is_grayscale | false | read the image as grayscale}"
;
CommandLineParser parser(argc, argv, keys);
parser.about("FCW detection");
if( parser.has("help") || argc == 1)
{
parser.printMessage();
return 0;
}
string model_filename = parser.get<string>("model_filename");
string image_path = parser.get<string>("image_path");
string out_image_path = parser.get<string>("out_image_path");
bool is_grayscale = parser.get<bool>("is_grayscale");
float threshold = parser.get<float>("threshold");
int step = parser.get<int>("step");
int min_rows, min_cols, max_rows, max_cols;
string min_window_size = parser.get<string>("min_window_size");
if( !read_window_size(min_window_size.c_str(), &min_rows,
&min_cols) )
{
cerr << "Error reading min window size from `" << min_window_size << "`" << endl;
return 1;
}
string max_window_size = parser.get<string>("max_window_size");
if( !read_window_size(max_window_size.c_str(), &max_rows,
&max_cols) )
{
cerr << "Error reading max window size from `" << max_window_size << "`" << endl;
return 1;
}
int color;
if(is_grayscale == false)
color = cv::IMREAD_COLOR;
else
color = cv::IMREAD_GRAYSCALE;
if( !parser.check() )
{
parser.printErrors();
return 1;
}
ICFDetector detector;
FileStorage fs(model_filename, FileStorage::READ);
detector.read(fs["icfdetector"]);
fs.release();
vector<Rect> objects;
Mat img = imread(image_path, color);
std::vector<float> values;
detector.detect(img, objects, 1.1f, Size(min_cols, min_rows), Size(max_cols, max_rows), threshold, step, values);
imwrite(out_image_path, visualize(img, objects));
}
#include <cstdio>
#include <cstring>
#include <string>
using std::string;
#include <vector>
using std::vector;
#include <fstream>
using std::ifstream;
using std::getline;
#include <sstream>
using std::stringstream;
#include <iostream>
using std::cerr;
using std::endl;
#include <opencv2/core.hpp>
using cv::Rect;
using cv::Size;
#include <opencv2/highgui.hpp>
using cv::imread;
#include <opencv2/core/utility.hpp>
using cv::CommandLineParser;
using cv::FileStorage;
#include <opencv2/core/utility.hpp>
#include <ctime> // std::time
#include <cstdlib> // std::rand, std::srand
#include <opencv2/xobjdetect.hpp>
using cv::xobjdetect::ICFDetectorParams;
using cv::xobjdetect::ICFDetector;
using cv::xobjdetect::WaldBoost;
using cv::xobjdetect::WaldBoostParams;
using cv::Mat;
static bool read_model_size(const char *str, int *rows, int *cols)
{
int pos = 0;
if( sscanf(str, "%dx%d%n", rows, cols, &pos) != 2 || str[pos] != '\0' ||
*rows <= 0 || *cols <= 0)
{
return false;
}
return true;
}
static int randomPred (int i) { return std::rand()%i;}
int main(int argc, char *argv[])
{
const string keys =
"{help | | print this message}"
"{pos_path | pos | path to training object samples}"
"{bg_path | bg | path to background images}"
"{bg_per_image | 5 | number of windows to sample per bg image}"
"{feature_count | 10000 | number of features to generate}"
"{weak_count | 100 | number of weak classifiers in cascade}"
"{model_size | 40x40 | model size in pixels}"
"{model_filename | model.xml | filename for saving model}"
"{features_type | icf | features type, \"icf\" or \"acf\"}"
"{alpha | 0.02 | alpha value}"
"{is_grayscale | false | read the image as grayscale}"
"{use_fast_log | false | use fast log function}"
"{limit_ps | -1 | limit to positive samples (-1 means all)}"
"{limit_bg | -1 | limit to negative samples (-1 means all)}"
;
CommandLineParser parser(argc, argv, keys);
parser.about("FCW trainer");
if( parser.has("help") || argc == 1)
{
parser.printMessage();
return 0;
}
string pos_path = parser.get<string>("pos_path");
string bg_path = parser.get<string>("bg_path");
string model_filename = parser.get<string>("model_filename");
ICFDetectorParams params;
params.feature_count = parser.get<int>("feature_count");
params.weak_count = parser.get<int>("weak_count");
params.bg_per_image = parser.get<int>("bg_per_image");
params.features_type = parser.get<string>("features_type");
params.alpha = parser.get<float>("alpha");
params.is_grayscale = parser.get<bool>("is_grayscale");
params.use_fast_log = parser.get<bool>("use_fast_log");
int limit_ps = parser.get<int>("limit_ps");
int limit_bg = parser.get<int>("limit_bg");
string model_size = parser.get<string>("model_size");
if( !read_model_size(model_size.c_str(), &params.model_n_rows,
&params.model_n_cols) )
{
cerr << "Error reading model size from `" << model_size << "`" << endl;
return 1;
}
if( params.feature_count <= 0 )
{
cerr << "feature_count must be positive number" << endl;
return 1;
}
if( params.weak_count <= 0 )
{
cerr << "weak_count must be positive number" << endl;
return 1;
}
if( params.features_type != "icf" && params.features_type != "acf" )
{
cerr << "features_type must be \"icf\" or \"acf\"" << endl;
return 1;
}
if( params.alpha <= 0 )
{
cerr << "alpha must be positive float number" << endl;
return 1;
}
if( !parser.check() )
{
parser.printErrors();
return 1;
}
std::vector<cv::String> pos_filenames;
glob(pos_path, pos_filenames);
std::vector<cv::String> bg_filenames;
glob(bg_path, bg_filenames);
if(limit_ps != -1 && (int)pos_filenames.size() > limit_ps)
pos_filenames.erase(pos_filenames.begin()+limit_ps, pos_filenames.end());
if(limit_bg != -1 && (int)bg_filenames.size() > limit_bg)
bg_filenames.erase(bg_filenames.begin()+limit_bg, bg_filenames.end());
//random pick input images
bool random_shuffle = false;
if(random_shuffle)
{
std::srand ( unsigned ( std::time(0) ) );
std::random_shuffle ( pos_filenames.begin(), pos_filenames.end(), randomPred );
std::random_shuffle ( bg_filenames.begin(), bg_filenames.end(), randomPred );
}
int samples_size = (int)((params.bg_per_image * bg_filenames.size()) + pos_filenames.size());
int features_size = params.feature_count;
int max_features_allowed = (int)(INT_MAX/(sizeof(int)* samples_size));
int max_samples_allowed = (int)(INT_MAX/(sizeof(int)* features_size));
int total_samples = (int)((params.bg_per_image * bg_filenames.size()) + pos_filenames.size());
if(total_samples >max_samples_allowed)
{
CV_Error_(1, ("exceeded maximum number of samples. Maximum number of samples with %d features is %d, you have %d (%d positive samples + (%d bg * %d bg_per_image))\n",features_size,max_samples_allowed,total_samples,pos_filenames.size(),bg_filenames.size(),params.bg_per_image ));
}
if(params.feature_count >max_features_allowed)
{
CV_Error_(1, ("exceeded maximum number of features. Maximum number of features with %d samples is %d, you have %d\n",samples_size,max_features_allowed, features_size ));
}
std::cout<<pos_filenames.size()<<std::endl;
std::cout<<bg_filenames.size()<<std::endl;
ICFDetector detector;
detector.train(pos_filenames, bg_filenames, params);
FileStorage fs(model_filename, FileStorage::WRITE);
fs << "icfdetector";
detector.write(fs);
fs.release();
}
set(the_description "Object detection algorithms")
ocv_define_module(xobjdetect opencv_core opencv_imgproc opencv_highgui WRAP python)
ocv_define_module(xobjdetect opencv_core opencv_imgproc opencv_highgui opencv_objdetect WRAP python)
add_subdirectory(tools)
......@@ -49,201 +49,53 @@ the use of this software, even if advised of the possibility of such damage.
/** @defgroup xobjdetect Extended object detection
*/
namespace cv
{
namespace xobjdetect
{
//! @addtogroup xobjdetect
//! @{
/** @brief Compute channels for integral channel features evaluation
@param image image for which channels should be computed
@param channels output array for computed channels
*/
CV_EXPORTS void computeChannels(InputArray image, std::vector<Mat>& channels);
/** @brief Feature evaluation interface
*/
class CV_EXPORTS FeatureEvaluator : public Algorithm
{
public:
/** @brief Set channels for feature evaluation
@param channels array of channels to be set
*/
virtual void setChannels(InputArrayOfArrays channels) = 0;
/** @brief Set window position to sample features with shift. By default position is (0, 0).
@param position position to be set
*/
virtual void setPosition(Size position) = 0;
/** @brief Evaluate feature value with given index for current channels and window position.
@param feature_ind index of feature to be evaluated
*/
virtual int evaluate(size_t feature_ind) const = 0;
/** @brief Evaluate all features for current channels and window position.
@param feature_values matrix-column of evaluated feature values
*/
virtual void evaluateAll(OutputArray feature_values) const = 0;
virtual void assertChannels() = 0;
};
/** @brief Construct feature evaluator.
@param features features for evaluation
@param type feature type. Can be "icf" or "acf"
*/
CV_EXPORTS Ptr<FeatureEvaluator>
createFeatureEvaluator(const std::vector<std::vector<int> >& features,
const std::string& type);
/** @brief Generate integral features. Returns vector of features.
@param window_size size of window in which features should be evaluated
@param type feature type. Can be "icf" or "acf"
@param count number of features to generate.
@param channel_count number of feature channels
*/
std::vector<std::vector<int> >
generateFeatures(Size window_size, const std::string& type,
int count = INT_MAX, int channel_count = 10);
//sort in-place of columns of the input matrix
void sort_columns_without_copy(Mat& m, Mat indices = Mat());
/** @brief Parameters for WaldBoost. weak_count — number of weak learners, alpha — cascade thresholding param.
*/
struct CV_EXPORTS WaldBoostParams
{
int weak_count;
float alpha;
WaldBoostParams(): weak_count(100), alpha(0.02f)
{}
};
/** @brief WaldBoost object detector from @cite Sochman05 .
/** @brief WaldBoost detector
*/
class CV_EXPORTS WaldBoost : public Algorithm
{
class CV_EXPORTS WBDetector {
public:
/** @brief Train WaldBoost cascade for given data.
Returns feature indices chosen for cascade. Feature enumeration starts from 0.
@param data matrix of feature values, size M x N, one feature per row
@param labels matrix of samples class labels, size 1 x N. Labels can be from {-1, +1}
@param use_fast_log
/** @brief Read detector from FileNode.
@param node FileNode for input
*/
virtual std::vector<int> train(Mat& data,
const Mat& labels, bool use_fast_log=false) = 0;
virtual void read(const FileNode &node) = 0;
/** @brief Predict objects class given object that can compute object features.
Returns unnormed confidence value — measure of confidence that object is from class +1.
@param feature_evaluator object that can compute features by demand
/** @brief Write detector to FileStorage.
@param fs FileStorage for output
*/
virtual float predict(
const Ptr<FeatureEvaluator>& feature_evaluator) const = 0;
};
virtual void write(FileStorage &fs) const = 0;
/** @brief Construct WaldBoost object.
/** @brief Train WaldBoost detector
@param pos_samples Path to directory with cropped positive samples
@param neg_imgs Path to directory with negative (background) images
*/
CV_EXPORTS Ptr<WaldBoost>
createWaldBoost(const WaldBoostParams& params = WaldBoostParams());
virtual void train(
const std::string& pos_samples,
const std::string& neg_imgs) = 0;
/** @brief Params for ICFDetector training.
/** @brief Detect objects on image using WaldBoost detector
@param img Input image for detection
@param bboxes Bounding boxes coordinates output vector
@param confidences Confidence values for bounding boxes output vector
*/
struct CV_EXPORTS ICFDetectorParams
{
int feature_count;
int weak_count;
int model_n_rows;
int model_n_cols;
int bg_per_image;
std::string features_type;
float alpha;
bool is_grayscale;
bool use_fast_log;
ICFDetectorParams(): feature_count(UINT_MAX), weak_count(100),
model_n_rows(56), model_n_cols(56), bg_per_image(5), alpha(0.02f), is_grayscale(false), use_fast_log(false)
{}
};
virtual void detect(
const Mat& img,
std::vector<Rect> &bboxes,
std::vector<double> &confidences) = 0;
/** @brief Integral Channel Features from @cite Dollar09 .
*/
class CV_EXPORTS ICFDetector
{
public:
ICFDetector(): waldboost_(), features_(), ftype_() {}
/** @brief Train detector.
@param pos_filenames path to folder with images of objects (wildcards like /my/path/\*.png are allowed)
@param bg_filenames path to folder with background images
@param params parameters for detector training
*/
void train(const std::vector<String>& pos_filenames,
const std::vector<String>& bg_filenames,
ICFDetectorParams params = ICFDetectorParams());
/** @brief Detect objects on image.
@param image image for detection
@param objects output array of bounding boxes
@param scaleFactor scale between layers in detection pyramid
@param minSize min size of objects in pixels
@param maxSize max size of objects in pixels
@param threshold
@param slidingStep sliding window step
@param values output vector with values of positive samples
*/
void detect(const Mat& image, std::vector<Rect>& objects,
float scaleFactor, Size minSize, Size maxSize, float threshold, int slidingStep, std::vector<float>& values);
/** @brief Detect objects on image.
@param img image for detection
@param objects output array of bounding boxes
@param minScaleFactor min factor by which the image will be resized
@param maxScaleFactor max factor by which the image will be resized
@param factorStep scaling factor is incremented each pyramid layer according to this parameter
@param threshold
@param slidingStep sliding window step
@param values output vector with values of positive samples
/** @brief Create instance of WBDetector
*/
void detect(const Mat& img, std::vector<Rect>& objects, float minScaleFactor, float maxScaleFactor, float factorStep, float threshold, int slidingStep, std::vector<float>& values);
static Ptr<WBDetector> create();
/** @brief Write detector to FileStorage.
@param fs FileStorage for output
*/
void write(FileStorage &fs) const;
/** @brief Write ICFDetector to FileNode
@param node FileNode for reading
*/
void read(const FileNode &node);
private:
Ptr<WaldBoost> waldboost_;
std::vector<std::vector<int> > features_;
int model_n_rows_;
int model_n_cols_;
std::string ftype_;
virtual ~WBDetector(){}
};
CV_EXPORTS void write(FileStorage& fs, String&, const ICFDetector& detector);
CV_EXPORTS void read(const FileNode& node, ICFDetector& d,
const ICFDetector& default_value = ICFDetector());
//! @}
......
#ifndef __OPENCV_XOBJDETECT_PRIVATE_HPP__
#define __OPENCV_XOBJDETECT_PRIVATE_HPP__
#ifndef __OPENCV_BUILD
# error this is a private header, do not include it outside OpenCV
#endif
#include <opencv2/core.hpp>
namespace cv
{
namespace xobjdetect
{
class CV_EXPORTS Stump
{
public:
/* Initialize zero stump */
Stump(): threshold_(0), polarity_(1), pos_value_(1), neg_value_(-1) {}
/* Initialize stump with given threshold, polarity
and classification values */
Stump(int threshold, int polarity, float pos_value, float neg_value):
threshold_(threshold), polarity_(polarity),
pos_value_(pos_value), neg_value_(neg_value) {}
/* Train stump for given data
data — matrix of feature values, size M x N, one feature per row
labels — matrix of sample class labels, size 1 x N. Labels can be from
{-1, +1}
weights — matrix of sample weights, size 1 x N
visited_features: vector of already visited features (ignored in successive calls)
Returns chosen feature index. Feature enumeration starts from 0
*/
int train(const Mat& data, const Mat& labels, const Mat& weights, const std::vector<int>& visited_features, bool use_fast_log = false);
/* Predict object class given
value — feature value. Feature must be the same as was chosen
during training stump
Returns real value, sign(value) means class
*/
float predict(int value) const;
/* Write stump in FileStorage */
void write(FileStorage& fs) const
{
fs << "{"
<< "threshold" << threshold_
<< "polarity" << polarity_
<< "pos_value" << pos_value_
<< "neg_value" << neg_value_
<< "}";
}
/* Read stump */
void read(const FileNode& node)
{
threshold_ = (int)node["threshold"];
polarity_ = (int)node["polarity"];
pos_value_ = (float)node["pos_value"];
neg_value_ = (float)node["neg_value"];
}
private:
/* Stump decision threshold */
int threshold_;
/* Stump polarity, can be from {-1, +1} */
int polarity_;
/* Classification values for positive and negative classes */
float pos_value_, neg_value_;
};
void read(const FileNode& node, Stump& s, const Stump& default_value=Stump());
void write(FileStorage& fs, String&, const Stump& s);
} /* namespace xobjdetect */
} /* namespace cv */
#endif // __OPENCV_XOBJDETECT_PRIVATE_HPP__
/*
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
(3-clause BSD License)
Copyright (C) 2013, OpenCV Foundation, 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:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions 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.
* Neither the names of the copyright holders nor the names of the contributors
may 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 copyright holders 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.
*/
#include "precomp.hpp"
using std::vector;
using std::min;
#include <iostream>
using std::cout;
using std::endl;
namespace cv
{
namespace xobjdetect
{
static bool isNull(const Mat_<int> &m)
{
bool null_data = true;
for( int row = 0; row < m.rows; ++row )
{
for( int col = 0; col < m.cols; ++col )
if( m.at<int>(row, col) )
null_data = false;
}
return null_data;
}
class FeatureEvaluatorImpl : public FeatureEvaluator
{
public:
FeatureEvaluatorImpl(const vector<vector<int> >& features):
features_(features), channels_(), position_()
{
CV_Assert(features.size() > 0);
}
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_<int> 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);
}
protected:
/* Features to evaluate */
vector<vector<int> > features_;
/* Channels for feature evaluation */
std::vector<Mat> channels_;
/* Channels window position */
Size position_;
};
class ICFFeatureEvaluatorImpl : public FeatureEvaluatorImpl
{
public:
ICFFeatureEvaluatorImpl(const vector<vector<int> >& features):
FeatureEvaluatorImpl(features)
{
}
virtual void setChannels(InputArrayOfArrays channels);
virtual void setPosition(Size position);
virtual int evaluate(size_t feature_ind) const;
};
void ICFFeatureEvaluatorImpl::setChannels(InputArrayOfArrays channels)
{
channels_.clear();
vector<Mat> ch;
channels.getMatVector(ch);
for( size_t i = 0; i < ch.size(); ++i )
{
const Mat &channel = ch[i];
Mat integral_channel;
integral(channel, integral_channel, CV_32F);
integral_channel.convertTo(integral_channel, CV_32S);
channels_.push_back(integral_channel.clone());
}
}
void ICFFeatureEvaluatorImpl::setPosition(Size position)
{
position_ = position;
}
int ICFFeatureEvaluatorImpl::evaluate(size_t feature_ind) const
{
/*
//following return is equal to this commented code, left here for readability. The new code runs much faster.
*
const vector<int>& 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_<int>& ch = channels_[n];
return ch(y_to + 1, x_to + 1) - ch(y, x_to + 1) - ch(y_to + 1, x) + ch(y, x);
*/
CV_Assert(feature_ind < features_.size());
return *(channels_[features_[feature_ind][4]].ptr<int>()+((channels_[features_[feature_ind][4]].cols*(features_[feature_ind][3] + position_.width+1))+ features_[feature_ind][2] + position_.height + 1)) -
*(channels_[features_[feature_ind][4]].ptr<int>()+((channels_[features_[feature_ind][4]].cols*(features_[feature_ind][1] + position_.width))+ features_[feature_ind][2] + position_.height + 1)) -
*(channels_[features_[feature_ind][4]].ptr<int>()+((channels_[features_[feature_ind][4]].cols*(features_[feature_ind][3] + position_.width+1))+ features_[feature_ind][0] + position_.height)) +
*(channels_[features_[feature_ind][4]].ptr<int>()+((channels_[features_[feature_ind][4]].cols*(features_[feature_ind][1] + position_.width))+ features_[feature_ind][0] + position_.height));
}
class ACFFeatureEvaluatorImpl : public FeatureEvaluatorImpl
{
public:
ACFFeatureEvaluatorImpl(const vector<vector<int> >& features):
FeatureEvaluatorImpl(features)
{
}
virtual void setChannels(InputArrayOfArrays channels);
virtual void setPosition(Size position);
virtual int evaluate(size_t feature_ind) const;
};
void ACFFeatureEvaluatorImpl::setChannels(InputArrayOfArrays channels)
{
channels_.clear();
vector<Mat> ch;
channels.getMatVector(ch);
for( size_t i = 0; i < ch.size(); ++i )
{
const Mat &channel = ch[i];
Mat_<int> acf_channel = Mat_<int>::zeros(channel.rows / 4, channel.cols / 4);
for( int row = 0; row < channel.rows; row += 4 )
{
for( int col = 0; col < channel.cols; col += 4 )
{
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 )
sum += (int)channel.at<float>(cell_row, cell_col);
acf_channel(row / 4, col / 4) = sum;
}
}
channels_.push_back(acf_channel.clone());
}
}
void ACFFeatureEvaluatorImpl::setPosition(Size position)
{
position_ = Size(position.width / 4, position.height / 4);
}
int ACFFeatureEvaluatorImpl::evaluate(size_t feature_ind) const
{
CV_Assert(feature_ind < features_.size());
const vector<int>& feature = features_[feature_ind];
int x = feature[0];
int y = feature[1];
int n = feature[2];
return channels_[n].at<int>(y + position_.width, x + position_.height);
}
Ptr<FeatureEvaluator> createFeatureEvaluator(
const vector<vector<int> >& features, const std::string& type)
{
FeatureEvaluator *evaluator = NULL;
if( type == "acf" )
evaluator = new ACFFeatureEvaluatorImpl(features);
else if( type == "icf" )
evaluator = new ICFFeatureEvaluatorImpl(features);
else
CV_Error(CV_StsBadArg, "type value is either acf or icf");
return Ptr<FeatureEvaluator>(evaluator);
}
vector<vector<int> > generateFeatures(Size window_size, const std::string& type,
int count, int channel_count)
{
CV_Assert(count > 0);
vector<vector<int> > features;
if( type == "acf" )
{
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<int> 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 )
{
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<int> feature(f, f + sizeof(f) / sizeof(*f));
features.push_back(feature);
}
}
else
CV_Error(CV_StsBadArg, "type value is either acf or icf");
return features;
}
void computeChannels(InputArray image, vector<Mat>& channels)
{
Mat_<float> grad;
Mat_<float> angles;
Mat luv, gray, src;
if(image.getMat().channels() > 1)
{
src = Mat(image.getMat().rows, image.getMat().cols, CV_32FC3);
image.getMat().convertTo(src, CV_32FC3, 1./255);
cvtColor(src, gray, CV_RGB2GRAY);
cvtColor(src, luv, CV_RGB2Luv);
}
else
{
src = Mat(image.getMat().rows, image.getMat().cols, CV_32FC1);
image.getMat().convertTo(src, CV_32FC1, 1./255);
src.copyTo(gray);
}
Mat_<float> row_der, col_der;
Sobel(gray, row_der, CV_32F, 0, 1);
Sobel(gray, col_der, CV_32F, 1, 0);
cartToPolar(col_der, row_der, grad, angles, true);
//magnitude(row_der, col_der, grad);
Mat_<Vec6f> hist = Mat_<Vec6f>::zeros(grad.rows, grad.cols);
//const float to_deg = 180 / 3.1415926f;
for (int row = 0; row < grad.rows; ++row) {
for (int col = 0; col < grad.cols; ++col) {
//float angle = atan2(row_der(row, col), col_der(row, col)) * to_deg;
float angle = angles(row, col);
if (angle > 180)
angle -= 180;
if (angle < 0)
angle += 180;
int ind = (int)(angle / 30);
// If angle == 180, prevent index overflow
if (ind == 6)
ind = 5;
hist(row, col)[ind] = grad(row, col) * 255;
}
}
channels.clear();
if(image.getMat().channels() > 1)
{
Mat luv_channels[3];
split(luv, luv_channels);
for( int i = 0; i < 3; ++i )
channels.push_back(luv_channels[i]);
}
channels.push_back(grad);
vector<Mat> hist_channels;
split(hist, hist_channels);
for( size_t i = 0; i < hist_channels.size(); ++i )
channels.push_back(hist_channels[i]);
}
} /* namespace xobjdetect */
} /* namespace cv */
/*
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
(3-clause BSD License)
Copyright (C) 2000-2015, Intel Corporation, all rights reserved.
Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
Copyright (C) 2009-2015, NVIDIA Corporation, all rights reserved.
Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved.
Copyright (C) 2015, OpenCV Foundation, all rights reserved.
Copyright (C) 2015, Itseez 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:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions 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.
* Neither the names of the copyright holders nor the names of the contributors
may 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 copyright holders 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.
*/
#ifndef _OPENCV_CASCADECLASSIFIER_H_
#define _OPENCV_CASCADECLASSIFIER_H_
#include "precomp.hpp"
#define CC_CASCADE_FILENAME "cascade.xml"
#define CC_PARAMS_FILENAME "params.xml"
#define CC_CASCADE_PARAMS "cascadeParams"
#define CC_STAGE_TYPE "stageType"
#define CC_FEATURE_TYPE "featureType"
#define CC_HEIGHT "height"
#define CC_WIDTH "width"
#define CC_STAGE_NUM "stageNum"
#define CC_STAGES "stages"
#define CC_STAGE_PARAMS "stageParams"
#define CC_BOOST "BOOST"
#define CC_BOOST_TYPE "boostType"
#define CC_DISCRETE_BOOST "DAB"
#define CC_REAL_BOOST "RAB"
#define CC_LOGIT_BOOST "LB"
#define CC_GENTLE_BOOST "GAB"
#define CC_MINHITRATE "minHitRate"
#define CC_MAXFALSEALARM "maxFalseAlarm"
#define CC_TRIM_RATE "weightTrimRate"
#define CC_MAX_DEPTH "maxDepth"
#define CC_WEAK_COUNT "maxWeakCount"
#define CC_STAGE_THRESHOLD "stageThreshold"
#define CC_WEAK_CLASSIFIERS "weakClassifiers"
#define CC_INTERNAL_NODES "internalNodes"
#define CC_LEAF_VALUES "leafValues"
#define CC_FEATURES FEATURES
#define CC_FEATURE_PARAMS "featureParams"
#define CC_MAX_CAT_COUNT "maxCatCount"
#define CC_FEATURE_SIZE "featSize"
#define CC_HAAR "HAAR"
#define CC_MODE "mode"
#define CC_MODE_BASIC "BASIC"
#define CC_MODE_CORE "CORE"
#define CC_MODE_ALL "ALL"
#define CC_RECTS "rects"
#define CC_TILTED "tilted"
#define CC_LBP "LBP"
#define CC_RECT "rect"
#endif
/*
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
(3-clause BSD License)
Copyright (C) 2000-2015, Intel Corporation, all rights reserved.
Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
Copyright (C) 2009-2015, NVIDIA Corporation, all rights reserved.
Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved.
Copyright (C) 2015, OpenCV Foundation, all rights reserved.
Copyright (C) 2015, Itseez 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:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions 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.
* Neither the names of the copyright holders nor the names of the contributors
may 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 copyright holders 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.
*/
#include "precomp.hpp"
namespace cv {
namespace xobjdetect {
float calcNormFactor( const Mat& sum, const Mat& sqSum )
{
CV_DbgAssert( sum.cols > 3 && sqSum.rows > 3 );
Rect normrect( 1, 1, sum.cols - 3, sum.rows - 3 );
size_t p0, p1, p2, p3;
CV_SUM_OFFSETS( p0, p1, p2, p3, normrect, sum.step1() )
double area = normrect.width * normrect.height;
const int *sp = sum.ptr<int>();
int valSum = sp[p0] - sp[p1] - sp[p2] + sp[p3];
const double *sqp = sqSum.ptr<double>();
double valSqSum = sqp[p0] - sqp[p1] - sqp[p2] + sqp[p3];
return (float) sqrt( (double) (area * valSqSum - (double)valSum * valSum) );
}
CvParams::CvParams() : name( "params" ) {}
void CvParams::printDefaults() const
{ std::cout << "--" << name << "--" << std::endl; }
void CvParams::printAttrs() const {}
bool CvParams::scanAttr( const std::string, const std::string ) { return false; }
//---------------------------- FeatureParams --------------------------------------
CvFeatureParams::CvFeatureParams() : maxCatCount( 0 ), featSize( 1 )
{
name = CC_FEATURE_PARAMS;
}
void CvFeatureParams::init( const CvFeatureParams& fp )
{
maxCatCount = fp.maxCatCount;
featSize = fp.featSize;
}
void CvFeatureParams::write( FileStorage &fs ) const
{
fs << CC_MAX_CAT_COUNT << maxCatCount;
fs << CC_FEATURE_SIZE << featSize;
}
bool CvFeatureParams::read( const FileNode &node )
{
if ( node.empty() )
return false;
maxCatCount = node[CC_MAX_CAT_COUNT];
featSize = node[CC_FEATURE_SIZE];
return ( maxCatCount >= 0 && featSize >= 1 );
}
Ptr<CvFeatureParams> CvFeatureParams::create()
{
return Ptr<CvFeatureParams>(new CvLBPFeatureParams);
}
//------------------------------------- FeatureEvaluator ---------------------------------------
void CvFeatureEvaluator::init(const CvFeatureParams *_featureParams,
int _maxSampleCount, Size _winSize )
{
CV_Assert(_maxSampleCount > 0);
featureParams = (CvFeatureParams *)_featureParams;
winSize = _winSize;
numFeatures = 0;
cls.create( (int)_maxSampleCount, 1, CV_32FC1 );
generateFeatures();
}
void CvFeatureEvaluator::setImage(const Mat &, uchar clsLabel, int idx, const std::vector<int>&)
{
//CV_Assert(img.cols == winSize.width);
//CV_Assert(img.rows == winSize.height);
CV_Assert(idx < cls.rows);
cls.ptr<float>(idx)[0] = clsLabel;
}
Ptr<CvFeatureEvaluator> CvFeatureEvaluator::create()
{
return Ptr<CvFeatureEvaluator>(new CvLBPEvaluator);
}
}
}
/*
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
(3-clause BSD License)
Copyright (C) 2000-2015, Intel Corporation, all rights reserved.
Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
Copyright (C) 2009-2015, NVIDIA Corporation, all rights reserved.
Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved.
Copyright (C) 2015, OpenCV Foundation, all rights reserved.
Copyright (C) 2015, Itseez 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:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions 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.
* Neither the names of the copyright holders nor the names of the contributors
may 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 copyright holders 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.
*/
#ifndef _OPENCV_FEATURES_H_
#define _OPENCV_FEATURES_H_
#include <stdio.h>
#define FEATURES "features"
#define CV_SUM_OFFSETS( p0, p1, p2, p3, rect, step ) \
/* (x, y) */ \
(p0) = (rect).x + (step) * (rect).y; \
/* (x + w, y) */ \
(p1) = (rect).x + (rect).width + (step) * (rect).y; \
/* (x + w, y) */ \
(p2) = (rect).x + (step) * ((rect).y + (rect).height); \
/* (x + w, y + h) */ \
(p3) = (rect).x + (rect).width + (step) * ((rect).y + (rect).height);
#define CV_TILTED_OFFSETS( p0, p1, p2, p3, rect, step ) \
/* (x, y) */ \
(p0) = (rect).x + (step) * (rect).y; \
/* (x - h, y + h) */ \
(p1) = (rect).x - (rect).height + (step) * ((rect).y + (rect).height);\
/* (x + w, y + w) */ \
(p2) = (rect).x + (rect).width + (step) * ((rect).y + (rect).width); \
/* (x + w - h, y + w + h) */ \
(p3) = (rect).x + (rect).width - (rect).height \
+ (step) * ((rect).y + (rect).width + (rect).height);
namespace cv {
namespace xobjdetect {
float calcNormFactor( const cv::Mat& sum, const cv::Mat& sqSum );
template<class Feature>
void _writeFeatures( const std::vector<Feature> features, cv::FileStorage &fs, const cv::Mat& featureMap )
{
fs << FEATURES << "[";
const cv::Mat_<int>& featureMap_ = (const cv::Mat_<int>&)featureMap;
for ( int fi = 0; fi < featureMap.cols; fi++ )
if ( featureMap_(0, fi) >= 0 )
{
fs << "{";
features[fi].write( fs );
fs << "}";
}
fs << "]";
}
class CvParams
{
public:
CvParams();
virtual ~CvParams() {}
// from|to file
virtual void write( cv::FileStorage &fs ) const = 0;
virtual bool read( const cv::FileNode &node ) = 0;
// from|to screen
virtual void printDefaults() const;
virtual void printAttrs() const;
virtual bool scanAttr( const std::string prmName, const std::string val );
std::string name;
};
class CvFeatureParams : public CvParams
{
public:
enum { HAAR = 0, LBP = 1, HOG = 2 };
CvFeatureParams();
virtual void init( const CvFeatureParams& fp );
virtual void write( cv::FileStorage &fs ) const;
virtual bool read( const cv::FileNode &node );
static cv::Ptr<CvFeatureParams> create();
int maxCatCount; // 0 in case of numerical features
int featSize; // 1 in case of simple features (HAAR, LBP) and N_BINS(9)*N_CELLS(4) in case of Dalal's HOG features
};
class CvFeatureEvaluator
{
public:
virtual ~CvFeatureEvaluator() {}
virtual void init(const CvFeatureParams *_featureParams,
int _maxSampleCount, cv::Size _winSize );
virtual void setImage(const cv::Mat& img, uchar clsLabel, int idx, const std::vector<int> &feature_ind);
virtual void setWindow(const cv::Point& p) = 0;
virtual void writeFeatures( cv::FileStorage &fs, const cv::Mat& featureMap ) const = 0;
virtual float operator()(int featureIdx) = 0;
static cv::Ptr<CvFeatureEvaluator> create();
int getNumFeatures() const { return numFeatures; }
int getMaxCatCount() const { return featureParams->maxCatCount; }
int getFeatureSize() const { return featureParams->featSize; }
const cv::Mat& getCls() const { return cls; }
float getCls(int si) const { return cls.at<float>(si, 0); }
protected:
virtual void generateFeatures() = 0;
int npos, nneg;
int numFeatures;
cv::Size winSize;
CvFeatureParams *featureParams;
cv::Mat cls;
};
}
}
#endif
/*
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
(3-clause BSD License)
Copyright (C) 2013, OpenCV Foundation, 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:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions 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.
* Neither the names of the copyright holders nor the names of the contributors
may 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 copyright holders 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.
*/
#include <sstream>
using std::ostringstream;
#include <iomanip>
using std::setfill;
using std::setw;
#include <iostream>
using std::cout;
using std::endl;
#include "precomp.hpp"
using std::vector;
using std::string;
using std::min;
using std::max;
namespace cv
{
namespace xobjdetect
{
void ICFDetector::train(const vector<String>& pos_filenames,
const vector<String>& bg_filenames,
ICFDetectorParams params)
{
int color;
if(params.is_grayscale == false)
color = IMREAD_COLOR;
else
color = IMREAD_GRAYSCALE;
model_n_rows_ = params.model_n_rows;
model_n_cols_ = params.model_n_cols;
ftype_ = params.features_type;
Size model_size(params.model_n_cols, params.model_n_rows);
vector<Mat> samples; /* positive samples + negative samples */
Mat sample, resized_sample;
int pos_count = 0;
for( size_t i = 0; i < pos_filenames.size(); ++i, ++pos_count )
{
cout << setw(6) << (i + 1) << "/" << pos_filenames.size() << "\r";
Mat img = imread(pos_filenames[i], color);
resize(img, resized_sample, model_size);
samples.push_back(resized_sample.clone());
}
cout << "\n";
int neg_count = 0;
RNG rng;
for( size_t i = 0; i < bg_filenames.size(); ++i )
{
cout << setw(6) << (i + 1) << "/" << bg_filenames.size() << "\r";
Mat img = imread(bg_filenames[i], color);
for( int j = 0; j < params.bg_per_image; ++j, ++neg_count)
{
Rect r;
r.x = rng.uniform(0, img.cols-model_size.width);
r.width = model_size.width;
r.y = rng.uniform(0, img.rows-model_size.height);
r.height = model_size.height;
sample = img.colRange(r.x, r.x + r.width).rowRange(r.y, r.y + r.height);
samples.push_back(sample.clone());
}
}
cout << "\n";
Mat_<int> labels(1, pos_count + neg_count);
for( int i = 0; i < pos_count; ++i)
labels(0, i) = 1;
for( int i = pos_count; i < pos_count + neg_count; ++i )
labels(0, i) = -1;
vector<vector<int> > features;
if(params.is_grayscale == false)
features = generateFeatures(model_size, params.features_type, params.feature_count, 10);
else
features = generateFeatures(model_size, params.features_type, params.feature_count, 7);
Ptr<FeatureEvaluator> evaluator = createFeatureEvaluator(features, params.features_type);
Mat_<int> data = Mat_<int>::zeros((int)features.size(), (int)samples.size());
Mat_<int> feature_col(1, (int)samples.size());
vector<Mat> channels;
for( int i = 0; i < (int)samples.size(); ++i )
{
cout << setw(6) << i << "/" << samples.size() << "\r";
computeChannels(samples[i], channels);
evaluator->setChannels(channels);
//evaluator->assertChannels();
evaluator->evaluateAll(feature_col);
CV_Assert(feature_col.cols == (int)features.size());
for( int j = 0; j < feature_col.cols; ++j )
data(j, i) = feature_col(0, j);
}
cout << "\n";
samples.clear();
WaldBoostParams wparams;
wparams.weak_count = params.weak_count;
wparams.alpha = params.alpha;
waldboost_ = createWaldBoost(wparams);
vector<int> indices = waldboost_->train(data, labels, params.use_fast_log);
cout << "indices: ";
for( size_t i = 0; i < indices.size(); ++i )
cout << indices[i] << " ";
cout << endl;
features_.clear();
for( size_t i = 0; i < indices.size(); ++i )
features_.push_back(features[indices[i]]);
}
void ICFDetector::write(FileStorage& fs) const
{
fs << "{";
fs << "model_n_rows" << model_n_rows_;
fs << "model_n_cols" << model_n_cols_;
fs << "ftype" << String(ftype_.c_str());
fs << "waldboost";
waldboost_->write(fs);
fs << "features" << "[";
for( size_t i = 0; i < features_.size(); ++i )
{
fs << features_[i];
}
fs << "]";
fs << "}";
}
void ICFDetector::read(const FileNode& node)
{
waldboost_ = Ptr<WaldBoost>(createWaldBoost(WaldBoostParams()));
String f_temp;
node["model_n_rows"] >> model_n_rows_;
node["model_n_cols"] >> model_n_cols_;
f_temp = (String)node["ftype"];
this->ftype_ = (string)f_temp.c_str();
waldboost_->read(node["waldboost"]);
FileNode features = node["features"];
features_.clear();
vector<int> p;
for( FileNodeIterator n = features.begin(); n != features.end(); ++n )
{
(*n) >> p;
features_.push_back(p);
}
}
void ICFDetector::detect(const Mat& img, vector<Rect>& objects,
float scaleFactor, Size minSize, Size maxSize, float threshold, int slidingStep, std::vector<float>& values)
{
float scale_from = min(model_n_cols_ / (float)maxSize.width,
model_n_rows_ / (float)maxSize.height);
float scale_to = max(model_n_cols_ / (float)minSize.width,
model_n_rows_ / (float)minSize.height);
objects.clear();
Ptr<FeatureEvaluator> evaluator = createFeatureEvaluator(features_, ftype_);
Mat rescaled_image;
vector<Mat> channels;
for( float scale = scale_from; scale < scale_to + 0.001; scale *= scaleFactor )
{
int new_width = int(img.cols * scale);
new_width -= new_width % 4;
int new_height = int(img.rows * scale);
new_height -= new_height % 4;
resize(img, rescaled_image, Size(new_width, new_height));
computeChannels(rescaled_image, channels);
evaluator->setChannels(channels);
for( int row = 0; row <= rescaled_image.rows - model_n_rows_; row += slidingStep)
{
for( int col = 0; col <= rescaled_image.cols - model_n_cols_;
col += slidingStep )
{
evaluator->setPosition(Size(row, col));
float value = waldboost_->predict(evaluator);
if( value > threshold )
{
values.push_back(value);
int x = (int)(col / scale);
int y = (int)(row / scale);
int width = (int)(model_n_cols_ / scale);
int height = (int)(model_n_rows_ / scale);
objects.push_back(Rect(x, y, width, height));
}
}
}
}
}
void ICFDetector::detect(const Mat& img, vector<Rect>& objects,
float minScaleFactor, float maxScaleFactor, float factorStep, float threshold, int slidingStep, std::vector<float>& values)
{
if(factorStep <= 0)
{
CV_Error_(CV_StsBadArg, ("factorStep must be > 0"));
}
objects.clear();
Ptr<FeatureEvaluator> evaluator = createFeatureEvaluator(features_, ftype_);
Mat rescaled_image;
vector<Mat> channels;
for( float scale = minScaleFactor; scale < maxScaleFactor + 0.001; scale += factorStep )
{
if(scale < 1.0)
resize(img, rescaled_image, Size(),scale, scale, INTER_AREA);
else if (scale > 1.0)
resize(img, rescaled_image, Size(),scale, scale, INTER_CUBIC);
else //scale == 1.0
img.copyTo(rescaled_image);
computeChannels(rescaled_image, channels);
evaluator->setChannels(channels);
for( int row = 0; row <= rescaled_image.rows - model_n_rows_; row += slidingStep)
{
for( int col = 0; col <= rescaled_image.cols - model_n_cols_;
col += slidingStep )
{
evaluator->setPosition(Size(row, col));
float value = waldboost_->predict(evaluator);
if( value > threshold )
{
values.push_back(value);
int x = (int)(col / scale);
int y = (int)(row / scale);
int width = (int)(model_n_cols_ / scale);
int height = (int)(model_n_rows_ / scale);
objects.push_back(Rect(x, y, width, height));
}
}
}
}
}
void write(FileStorage& fs, String&, const ICFDetector& detector)
{
detector.write(fs);
}
void read(const FileNode& node, ICFDetector& d,
const ICFDetector& default_value)
{
if( node.empty() )
d = default_value;
else
d.read(node);
}
} /* namespace xobjdetect */
} /* namespace cv */
/*
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
(3-clause BSD License)
Copyright (C) 2000-2015, Intel Corporation, all rights reserved.
Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
Copyright (C) 2009-2015, NVIDIA Corporation, all rights reserved.
Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved.
Copyright (C) 2015, OpenCV Foundation, all rights reserved.
Copyright (C) 2015, Itseez 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:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions 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.
* Neither the names of the copyright holders nor the names of the contributors
may 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 copyright holders 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.
*/
#include "precomp.hpp"
namespace cv {
namespace xobjdetect {
CvLBPFeatureParams::CvLBPFeatureParams()
{
maxCatCount = 256;
name = LBPF_NAME;
}
void CvLBPEvaluator::init(const CvFeatureParams *_featureParams, int _maxSampleCount, Size _winSize)
{
CV_Assert( _maxSampleCount > 0);
sum.create((int)_maxSampleCount, (_winSize.width + 1) * (_winSize.height + 1), CV_32SC1);
CvFeatureEvaluator::init( _featureParams, _maxSampleCount, _winSize );
}
void CvLBPEvaluator::setImage(const Mat &img, uchar clsLabel, int idx,
const std::vector<int> &feature_ind)
{
CV_DbgAssert( !sum.empty() );
CvFeatureEvaluator::setImage( img, clsLabel, idx, feature_ind );
integral( img, sum );
cur_sum = sum;
offset_ = int(sum.ptr<int>(1) - sum.ptr<int>());
for (size_t i = 0; i < feature_ind.size(); ++i) {
features[feature_ind[i]].calcPoints(offset_);
}
}
void CvLBPEvaluator::writeFeatures( FileStorage &fs, const Mat& featureMap ) const
{
_writeFeatures( features, fs, featureMap );
}
void CvLBPEvaluator::generateFeatures()
{
int offset = winSize.width + 1;
for( int x = 0; x < winSize.width; x++ )
for( int y = 0; y < winSize.height; y++ )
for( int w = 1; w <= winSize.width / 3; w++ )
for( int h = 1; h <= winSize.height / 3; h++ )
if ( (x+3*w <= winSize.width) && (y+3*h <= winSize.height) )
features.push_back( Feature(offset, x, y, w, h ) );
numFeatures = (int)features.size();
}
CvLBPEvaluator::Feature::Feature()
{
rect = cvRect(0, 0, 0, 0);
}
CvLBPEvaluator::Feature::Feature( int offset, int x, int y, int _blockWidth, int _blockHeight )
{
x_ = x;
y_ = y;
block_w_ = _blockWidth;
block_h_ = _blockHeight;
offset_ = offset;
calcPoints(offset);
}
void CvLBPEvaluator::Feature::calcPoints(int offset)
{
Rect tr = rect = cvRect(x_, y_, block_w_, block_h_);
CV_SUM_OFFSETS( p[0], p[1], p[4], p[5], tr, offset )
tr.x += 2*rect.width;
CV_SUM_OFFSETS( p[2], p[3], p[6], p[7], tr, offset )
tr.y +=2*rect.height;
CV_SUM_OFFSETS( p[10], p[11], p[14], p[15], tr, offset )
tr.x -= 2*rect.width;
CV_SUM_OFFSETS( p[8], p[9], p[12], p[13], tr, offset )
offset_ = offset;
}
void CvLBPEvaluator::Feature::write(FileStorage &fs) const
{
fs << CC_RECT << "[:" << rect.x << rect.y << rect.width << rect.height << "]";
}
}
}
/*
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
(3-clause BSD License)
Copyright (C) 2000-2015, Intel Corporation, all rights reserved.
Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
Copyright (C) 2009-2015, NVIDIA Corporation, all rights reserved.
Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved.
Copyright (C) 2015, OpenCV Foundation, all rights reserved.
Copyright (C) 2015, Itseez 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:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions 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.
* Neither the names of the copyright holders nor the names of the contributors
may 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 copyright holders 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.
*/
#ifndef _OPENCV_LBPFEATURES_H_
#define _OPENCV_LBPFEATURES_H_
#include "precomp.hpp"
#define LBPF_NAME "lbpFeatureParams"
namespace cv {
namespace xobjdetect {
struct CvLBPFeatureParams : CvFeatureParams
{
CvLBPFeatureParams();
};
class CvLBPEvaluator : public CvFeatureEvaluator
{
public:
virtual ~CvLBPEvaluator() {}
virtual void init(const CvFeatureParams *_featureParams,
int _maxSampleCount, cv::Size _winSize );
virtual void setImage(const cv::Mat& img, uchar clsLabel, int idx, const std::vector<int> &feature_ind);
virtual void setWindow(const cv::Point& p)
{ cur_sum = sum.rowRange(p.y, p.y + winSize.height).colRange(p.x, p.x + winSize.width); }
virtual float operator()(int featureIdx)
{ return (float)features[featureIdx].calc( cur_sum ); }
virtual void writeFeatures( cv::FileStorage &fs, const cv::Mat& featureMap ) const;
protected:
virtual void generateFeatures();
class Feature
{
public:
Feature();
Feature( int offset, int x, int y, int _block_w, int _block_h );
uchar calc( const cv::Mat& _sum );
void write( cv::FileStorage &fs ) const;
cv::Rect rect;
int p[16];
int x_, y_, block_w_, block_h_, offset_;
void calcPoints(int offset);
};
std::vector<Feature> features;
cv::Mat sum, cur_sum;
int offset_;
};
inline uchar CvLBPEvaluator::Feature::calc(const cv::Mat &_sum)
{
const int* psum = _sum.ptr<int>();
int cval = psum[p[5]] - psum[p[6]] - psum[p[9]] + psum[p[10]];
return (uchar)((psum[p[0]] - psum[p[1]] - psum[p[4]] + psum[p[5]] >= cval ? 128 : 0) | // 0
(psum[p[1]] - psum[p[2]] - psum[p[5]] + psum[p[6]] >= cval ? 64 : 0) | // 1
(psum[p[2]] - psum[p[3]] - psum[p[6]] + psum[p[7]] >= cval ? 32 : 0) | // 2
(psum[p[6]] - psum[p[7]] - psum[p[10]] + psum[p[11]] >= cval ? 16 : 0) | // 5
(psum[p[10]] - psum[p[11]] - psum[p[14]] + psum[p[15]] >= cval ? 8 : 0) | // 8
(psum[p[9]] - psum[p[10]] - psum[p[13]] + psum[p[14]] >= cval ? 4 : 0) | // 7
(psum[p[8]] - psum[p[9]] - psum[p[12]] + psum[p[13]] >= cval ? 2 : 0) | // 6
(psum[p[4]] - psum[p[5]] - psum[p[8]] + psum[p[9]] >= cval ? 1 : 0)); // 3
}
}
}
#endif
/*
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,
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.
......@@ -9,7 +8,12 @@ copy or use the software.
For Open Source Computer Vision Library
(3-clause BSD License)
Copyright (C) 2013, OpenCV Foundation, all rights reserved.
Copyright (C) 2000-2015, Intel Corporation, all rights reserved.
Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
Copyright (C) 2009-2015, NVIDIA Corporation, all rights reserved.
Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved.
Copyright (C) 2015, OpenCV Foundation, all rights reserved.
Copyright (C) 2015, Itseez 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,
......@@ -28,31 +32,50 @@ are permitted provided that the following conditions are met:
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 copyright holders or contributors be liable for
any direct, indirect, incidental, special, exemplary, or consequential damages
warranties of merchantability and fitness for a particular purpose are disclaimed.
In no event shall copyright holders 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.
*/
#ifndef __OPENCV_XOBJDETECT_PRECOMP_HPP__
#define __OPENCV_XOBJDETECT_PRECOMP_HPP__
#include <opencv2/xobjdetect.hpp>
#include <opencv2/xobjdetect/private.hpp>
#include <opencv2/core/utility.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/imgproc/types_c.h>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgcodecs/imgcodecs_c.h>
#include <opencv2/objdetect.hpp>
#include <algorithm>
#include <vector>
#include <string>
#include <cmath>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <sstream>
#include <cassert>
#include <cstdio>
#include "cascadeclassifier.h"
#include "feature_evaluator.hpp"
#include "lbpfeatures.h"
#include "waldboost.hpp"
#include "wbdetector.hpp"
#include <opencv2/xobjdetect.hpp>
#endif /* __OPENCV_XOBJDETECT_PRECOMP_HPP__ */
/*
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
(3-clause BSD License)
Copyright (C) 2013, OpenCV Foundation, 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:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions 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.
* Neither the names of the copyright holders nor the names of the contributors
may 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 copyright holders 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.
*/
#include "precomp.hpp"
namespace cv
{
namespace xobjdetect
{
/* Cumulative sum by rows */
static void cumsum(const Mat_<float>& src, Mat_<float> dst)
{
CV_Assert(src.cols > 0);
for( int row = 0; row < src.rows; ++row )
{
dst(row, 0) = src(row, 0);
for( int col = 1; col < src.cols; ++col )
{
dst(row, col) = dst(row, col - 1) + src(row, col);
}
}
}
//fast log implementation. A bit less accurate but ~5x faster
inline float fast_log2 (float val)
{
int * const exp_ptr = reinterpret_cast <int *> (&val);
int x = *exp_ptr;
const int log_2 = ((x >> 23) & 255) - 128;
x &= ~(255 << 23);
x += 127 << 23;
*exp_ptr = x;
val = ((-1.0f/3) * val + 2) * val - 2.0f/3; // (1)
return (val + log_2);
}
inline float fast_log (const float &val)
{
return (fast_log2 (val) * 0.69314718f);
}
int Stump::train(const Mat& data, const Mat& labels, const Mat& weights, const std::vector<int>& visited_features, bool use_fast_log)
{
CV_Assert(labels.rows == 1 && labels.cols == data.cols);
CV_Assert(weights.rows == 1 && weights.cols == data.cols);
CV_Assert(data.cols > 1);
/* Assert that data and labels have int type */
/* Assert that weights have float type */
Mat_<int> d = Mat_<int>::zeros(1, data.cols);
const Mat_<int>& l = labels;
const Mat_<float>& w = weights;
Mat_<int> indices(1, l.cols);
Mat_<int> sorted_d(1, data.cols);
Mat_<int> sorted_l(1, l.cols);
Mat_<float> sorted_w(1, w.cols);
Mat_<float> pos_c_w = Mat_<float>::zeros(1, w.cols);
Mat_<float> neg_c_w = Mat_<float>::zeros(1, w.cols);
float min_err = FLT_MAX;
int min_row = -1;
int min_thr = -1;
int min_pol = -1;
float min_pos = 1;
float min_neg = -1;
float eps = 1.0f / (4 * l.cols);
/* For every feature */
for( int row = 0; row < data.rows; ++row )
{
if(std::find(visited_features.begin(), visited_features.end(), row) != visited_features.end()) {
//feature discarded
continue;
}
data.row(row).copyTo(d.row(0));
sortIdx(d, indices, cv::SORT_EVERY_ROW | cv::SORT_ASCENDING);
for( int col = 0; col < indices.cols; ++col )
{
int ind = indices(0, col);
sorted_d(0, col) = d(0, ind);
sorted_l(0, col) = l(0, ind);
sorted_w(0, col) = w(0, ind);
}
Mat_<float> pos_w = Mat_<float>::zeros(1, w.cols);
Mat_<float> neg_w = Mat_<float>::zeros(1, w.cols);
for( int col = 0; col < d.cols; ++col )
{
float weight = sorted_w(0, col);
if( sorted_l(0, col) == +1)
pos_w(0, col) = weight;
else
neg_w(0, col) = weight;
}
cumsum(pos_w, pos_c_w);
cumsum(neg_w, neg_c_w);
float pos_total_w = pos_c_w(0, w.cols - 1);
float neg_total_w = neg_c_w(0, w.cols - 1);
for( int col = 0; col < w.cols - 1; ++col )
{
float err, h_pos, h_neg;
float pos_wrong, pos_right;
float neg_wrong, neg_right;
/* Direct polarity */
pos_wrong = pos_c_w(0, col);
pos_right = pos_total_w - pos_wrong;
neg_right = neg_c_w(0, col);
neg_wrong = neg_total_w - neg_right;
err = sqrt(pos_right * neg_wrong) + sqrt(pos_wrong * neg_right);
if(use_fast_log)
{
h_pos = .5f * fast_log((pos_right + eps) / (pos_wrong + eps));
h_neg = .5f * fast_log((neg_wrong + eps) / (neg_right + eps));
}
else
{
h_pos = .5f * log((pos_right + eps) / (pos_wrong + eps));
h_neg = .5f * log((neg_wrong + eps) / (neg_right + eps));
}
if( err < min_err )
{
min_err = err;
min_row = row;
min_thr = (sorted_d(0, col) + sorted_d(0, col + 1)) / 2;
min_pol = +1;
min_pos = h_pos;
min_neg = h_neg;
}
/* Opposite polarity */
swap(pos_right, pos_wrong);
swap(neg_right, neg_wrong);
err = sqrt(pos_right * neg_wrong) + sqrt(pos_wrong * neg_right);
if( err < min_err )
{
min_err = err;
min_row = row;
min_thr = (sorted_d(0, col) + sorted_d(0, col + 1)) / 2;
min_pol = -1;
min_pos = -h_pos;
min_neg = -h_neg;
}
}
}
threshold_ = min_thr;
polarity_ = min_pol;
pos_value_ = min_pos;
neg_value_ = min_neg;
return min_row;
}
float Stump::predict(int value) const
{
return polarity_ * (value - threshold_) > 0 ? pos_value_ : neg_value_;
}
void read(const FileNode& node, Stump& s, const Stump& default_value)
{
if( node.empty() )
s = default_value;
else
s.read(node);
}
void write(FileStorage& fs, String&, const Stump& s)
{
s.write(fs);
}
} /* namespace xobjdetect */
} /* namespace cv */
/*
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,
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.
......@@ -9,7 +8,12 @@ copy or use the software.
For Open Source Computer Vision Library
(3-clause BSD License)
Copyright (C) 2013, OpenCV Foundation, all rights reserved.
Copyright (C) 2000-2015, Intel Corporation, all rights reserved.
Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
Copyright (C) 2009-2015, NVIDIA Corporation, all rights reserved.
Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved.
Copyright (C) 2015, OpenCV Foundation, all rights reserved.
Copyright (C) 2015, Itseez 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,
......@@ -28,360 +32,416 @@ are permitted provided that the following conditions are met:
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 copyright holders or contributors be liable for
any direct, indirect, incidental, special, exemplary, or consequential damages
warranties of merchantability and fitness for a particular purpose are disclaimed.
In no event shall copyright holders 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.
*/
#include "precomp.hpp"
using std::swap;
using std::vector;
#include <iostream>
using std::cout;
using std::endl;
namespace cv {
namespace xobjdetect {
namespace cv
{
namespace xobjdetect
static void compute_cdf(const Mat1b& data,
const Mat1f& weights,
Mat1f& cdf)
{
//sort in-place of columns of the input matrix
void sort_columns_without_copy(Mat& m, Mat indices)
{
if(indices.data == 0)
sortIdx(m, indices, cv::SORT_EVERY_ROW | cv::SORT_ASCENDING);
Mat indices_of_indices;
sortIdx(indices, indices_of_indices, cv::SORT_EVERY_ROW | cv::SORT_ASCENDING);
for (int i = 0; i < cdf.cols; ++i)
cdf(0, i) = 0;
std::vector<bool> visited;
for(int c = 0; c<m.cols; c++)
visited.push_back(false);
int ind_v = 0;
Mat temp_column = Mat();
int next = 0;
Mat column;
while(ind_v < m.cols)
{
if(temp_column.data == 0)
{
(m.col(indices_of_indices.at<int>(0,ind_v))).copyTo(column);
}
else
{
temp_column.copyTo(column);
}
if(indices_of_indices.at<int>(0,next) != next) //value is in the right place
{
//store the next value to change
(m.col(indices_of_indices.at<int>(0,next))).copyTo(temp_column);
//insert the value to change at the right place
column.copyTo(m.col(indices_of_indices.at<int>(0,next)));
//find the index of the next value to change
next = indices_of_indices.at<int>(0,next);
//if the idenx is not visited yet
if(visited[next] == false)
{
//then mark it as visited, it will be computed in the next round
visited[next] = true;
}
else
{
//find first non visited index
int i = 0;
while(i<(int)visited.size() && visited[i] == true)
{
i++;
for (int i = 0; i < weights.cols; ++i) {
cdf(0, data(0, i)) += weights(0, i);
}
ind_v = i;
next = i;
temp_column = Mat();
}
}
else // value is already at the right place
{
visited[next] = true;
int i = 0;
while(i<(int)visited.size() && visited[i] == true)
{
i++;
}
next = i;
temp_column = Mat();
ind_v = i;
}
}
for (int i = 1; i < cdf.cols; ++i) {
cdf(0, i) += cdf(0, i - 1);
}
}
class WaldBoostImpl : public WaldBoost
static void compute_min_step(const Mat &data_pos, const Mat &data_neg, size_t n_bins,
Mat &data_min, Mat &data_step)
{
public:
/* Initialize WaldBoost cascade with default of specified parameters */
WaldBoostImpl(const WaldBoostParams& params):
params_(params)
{}
// Check that quantized data will fit in unsigned char
assert(n_bins <= 256);
virtual std::vector<int> train(Mat& data,
const Mat& labels, bool use_fast_log=false);
assert(data_pos.rows == data_neg.rows);
virtual float predict(
const Ptr<FeatureEvaluator>& feature_evaluator) const;
Mat reduced_pos, reduced_neg;
virtual void write(FileStorage& fs) const;
reduce(data_pos, reduced_pos, 1, CV_REDUCE_MIN);
reduce(data_neg, reduced_neg, 1, CV_REDUCE_MIN);
min(reduced_pos, reduced_neg, data_min);
data_min -= 0.01;
virtual void read(const FileNode& node);
Mat data_max;
reduce(data_pos, reduced_pos, 1, CV_REDUCE_MAX);
reduce(data_neg, reduced_neg, 1, CV_REDUCE_MAX);
max(reduced_pos, reduced_neg, data_max);
data_max += 0.01;
private:
/* Parameters for cascade training */
WaldBoostParams params_;
/* Stumps in cascade */
std::vector<Stump> stumps_;
/* Rejection thresholds for linear combination at every stump evaluation */
std::vector<float> thresholds_;
};
data_step = (data_max - data_min) / (double)(n_bins - 1);
}
static int count(const Mat_<int> &m, int elem)
static void quantize_data(Mat &data, Mat1f &data_min, Mat1f &data_step)
{
int res = 0;
for( int row = 0; row < m.rows; ++row )
for( int col = 0; col < m.cols; ++col )
if( m(row, col) == elem)
res += 1;
return res;
//#pragma omp parallel for
for (int col = 0; col < data.cols; ++col) {
data.col(col) -= data_min;
data.col(col) /= data_step;
}
data.convertTo(data, CV_8U);
}
void WaldBoostImpl::read(const FileNode& node)
WaldBoost::WaldBoost(int weak_count):
weak_count_(weak_count),
thresholds_(),
alphas_(),
feature_indices_(),
polarities_(),
cascade_thresholds_() {}
WaldBoost::WaldBoost():
weak_count_(),
thresholds_(),
alphas_(),
feature_indices_(),
polarities_(),
cascade_thresholds_() {}
std::vector<int> WaldBoost::get_feature_indices()
{
FileNode params = node["waldboost_params"];
params_.weak_count = (int)(params["weak_count"]);
params_.alpha = (float)(params["alpha"]);
return feature_indices_;
}
FileNode stumps = node["waldboost_stumps"];
stumps_.clear();
for( FileNodeIterator n = stumps.begin(); n != stumps.end(); ++n )
{
Stump s;
*n >> s;
stumps_.push_back(s);
void WaldBoost::detect(Ptr<CvFeatureEvaluator> eval,
const Mat& img, const std::vector<float>& scales,
std::vector<Rect>& bboxes, Mat1f& confidences)
{
bboxes.clear();
confidences.release();
Mat resized_img;
int step = 4;
float h;
for (size_t i = 0; i < scales.size(); ++i) {
float scale = scales[i];
resize(img, resized_img, Size(), scale, scale);
eval->setImage(resized_img, 0, 0, feature_indices_);
int n_rows = (int)(24 / scale);
int n_cols = (int)(24 / scale);
for (int r = 0; r + 24 < resized_img.rows; r += step) {
for (int c = 0; c + 24 < resized_img.cols; c += step) {
//eval->setImage(resized_img(Rect(c, r, 24, 24)), 0, 0);
eval->setWindow(Point(c, r));
if (predict(eval, &h) == +1) {
int row = (int)(r / scale);
int col = (int)(c / scale);
bboxes.push_back(Rect(col, row, n_cols, n_rows));
confidences.push_back(h);
}
}
FileNode thresholds = node["waldboost_thresholds"];
thresholds_.clear();
for( FileNodeIterator n = thresholds.begin(); n != thresholds.end(); ++n )
{
float t;
*n >> t;
thresholds_.push_back(t);
}
}
groupRectangles(bboxes, 3, 0.7);
}
void WaldBoostImpl::write(FileStorage& fs) const
void WaldBoost::detect(Ptr<CvFeatureEvaluator> eval,
const Mat& img, const std::vector<float>& scales,
std::vector<Rect>& bboxes, std::vector<double>& confidences)
{
fs << "{";
fs << "waldboost_params" << "{"
<< "weak_count" << params_.weak_count
<< "alpha" << params_.alpha
<< "}";
fs << "waldboost_stumps" << "[";
for( size_t i = 0; i < stumps_.size(); ++i )
fs << stumps_[i];
fs << "]";
fs << "waldboost_thresholds" << "[";
for( size_t i = 0; i < thresholds_.size(); ++i )
fs << thresholds_[i];
fs << "]";
fs << "}";
bboxes.clear();
confidences.clear();
Mat resized_img;
int step = 4;
float h;
for (size_t i = 0; i < scales.size(); ++i) {
float scale = scales[i];
resize(img, resized_img, Size(), scale, scale);
eval->setImage(resized_img, 0, 0, feature_indices_);
int n_rows = (int)(24 / scale);
int n_cols = (int)(24 / scale);
for (int r = 0; r + 24 < resized_img.rows; r += step) {
for (int c = 0; c + 24 < resized_img.cols; c += step) {
eval->setWindow(Point(c, r));
if (predict(eval, &h) == +1) {
int row = (int)(r / scale);
int col = (int)(c / scale);
bboxes.push_back(Rect(col, row, n_cols, n_rows));
confidences.push_back(h);
}
}
}
}
std::vector<int> levels(bboxes.size(), 0);
groupRectangles(bboxes, levels, confidences, 3, 0.7);
}
vector<int> WaldBoostImpl::train(Mat& data, const Mat& labels_, bool use_fast_log)
void WaldBoost::fit(Mat& data_pos, Mat& data_neg)
{
CV_Assert(labels_.rows == 1 && labels_.cols == data.cols);
CV_Assert(data.rows >= params_.weak_count);
// data_pos: F x N_pos
// data_neg: F x N_neg
// every feature corresponds to row
// every sample corresponds to column
assert(data_pos.rows >= weak_count_);
assert(data_pos.rows == data_neg.rows);
std::vector<bool> feature_ignore;
for (int i = 0; i < data_pos.rows; ++i) {
feature_ignore.push_back(false);
}
Mat labels;
labels_.copyTo(labels);
Mat1f pos_weights(1, data_pos.cols, 1.0f / (2 * data_pos.cols));
Mat1f neg_weights(1, data_neg.cols, 1.0f / (2 * data_neg.cols));
Mat1f pos_trace(1, data_pos.cols, 0.0f);
Mat1f neg_trace(1, data_neg.cols, 0.0f);
bool null_data = true;
for( int row = 0; row < data.rows; ++row )
{
for( int col = 0; col < data.cols; ++col )
if( data.at<int>(row, col) )
null_data = false;
bool quantize = false;
if (data_pos.type() != CV_8U) {
std::cerr << "quantize" << std::endl;
quantize = true;
}
CV_Assert(!null_data);
int pos_count = count(labels, +1);
int neg_count = count(labels, -1);
Mat1f data_min, data_step;
int n_bins = 256;
if (quantize) {
compute_min_step(data_pos, data_neg, n_bins, data_min, data_step);
quantize_data(data_pos, data_min, data_step);
quantize_data(data_neg, data_min, data_step);
}
Mat_<float> weights(labels.rows, labels.cols);
float pos_weight = 1.0f / (2 * pos_count);
float neg_weight = 1.0f / (2 * neg_count);
for( int col = 0; col < weights.cols; ++col )
std::cerr << "pos=" << data_pos.cols << " neg=" << data_neg.cols << std::endl;
for (int i = 0; i < weak_count_; ++i) {
// Train weak learner with lowest error using weights
double min_err = DBL_MAX;
int min_feature_ind = -1;
int min_polarity = 0;
int threshold_q = 0;
float min_threshold = 0;
//#pragma omp parallel for
for (int feat_i = 0; feat_i < data_pos.rows; ++feat_i) {
if (feature_ignore[feat_i])
continue;
// Construct cdf
Mat1f pos_cdf(1, n_bins), neg_cdf(1, n_bins);
compute_cdf(data_pos.row(feat_i), pos_weights, pos_cdf);
compute_cdf(data_neg.row(feat_i), neg_weights, neg_cdf);
float neg_total = (float)sum(neg_weights)[0];
Mat1f err_direct = pos_cdf + neg_total - neg_cdf;
Mat1f err_backward = 1.0f - err_direct;
int idx1[2], idx2[2];
double err1, err2;
minMaxIdx(err_direct, &err1, NULL, idx1);
minMaxIdx(err_backward, &err2, NULL, idx2);
//#pragma omp critical
{
if( labels.at<int>(0, col) == +1 )
weights.at<float>(0, col) = pos_weight;
else
weights.at<float>(0, col) = neg_weight;
if (min(err1, err2) < min_err) {
if (err1 < err2) {
min_err = err1;
min_polarity = +1;
threshold_q = idx1[1];
} else {
min_err = err2;
min_polarity = -1;
threshold_q = idx2[1];
}
min_feature_ind = feat_i;
if (quantize) {
min_threshold = data_min(feat_i, 0) + data_step(feat_i, 0) *
(threshold_q + .5f);
} else {
min_threshold = threshold_q + .5f;
}
}
}
}
vector<int> feature_indices_pool;
for( int ind = 0; ind < data.rows; ++ind )
feature_indices_pool.push_back(ind);
vector<int> feature_indices;
vector<int> visited_features;
Mat_<float> trace = Mat_<float>::zeros(labels.rows, labels.cols);
stumps_.clear();
thresholds_.clear();
for( int i = 0; i < params_.weak_count; ++i)
{
Stump s;
int feature_ind = s.train(data, labels, weights, visited_features, use_fast_log);
stumps_.push_back(s);
int ind = feature_indices_pool[feature_ind];
//we don't need to erase the feature index anymore, because we ignore them if already visited
//feature_indices_pool.erase(feature_indices_pool.begin() + feature_ind);
feature_indices.push_back(ind);
// Recompute weights
for( int col = 0; col < weights.cols; ++col )
{
float h = s.predict(data.at<int>(feature_ind, col));
trace(0, col) += h;
int label = labels.at<int>(0, col);
weights.at<float>(0, col) *= exp(-label * h);
float alpha = .5f * (float)log((1 - min_err) / min_err);
alphas_.push_back(alpha);
feature_indices_.push_back(min_feature_ind);
thresholds_.push_back(min_threshold);
polarities_.push_back(min_polarity);
feature_ignore[min_feature_ind] = true;
double loss = 0;
// Update positive weights
for (int j = 0; j < data_pos.cols; ++j) {
int val = data_pos.at<unsigned char>(min_feature_ind, j);
int label = min_polarity * (val - threshold_q) >= 0 ? +1 : -1;
pos_weights(0, j) *= exp(-alpha * label);
pos_trace(0, j) += alpha * label;
loss += exp(-pos_trace(0, j)) / (2.0f * data_pos.cols);
}
// set to zero row for feature in data
for(int jc = 0; jc<data.cols; jc++)
{
data.at<int>(feature_ind, jc) = 0;
// Update negative weights
for (int j = 0; j < data_neg.cols; ++j) {
int val = data_neg.at<unsigned char>(min_feature_ind, j);
int label = min_polarity * (val - threshold_q) >= 0 ? +1 : -1;
neg_weights(0, j) *= exp(alpha * label);
neg_trace(0, j) += alpha * label;
loss += exp(+neg_trace(0, j)) / (2.0f * data_neg.cols);
}
double cascade_threshold = -1;
minMaxIdx(pos_trace, &cascade_threshold);
cascade_thresholds_.push_back((float)cascade_threshold);
std::cerr << "i=" << std::setw(4) << i;
std::cerr << " feat=" << std::setw(5) << min_feature_ind;
std::cerr << " thr=" << std::setw(3) << threshold_q;
std::cerr << " casthr=" << std::fixed << std::setprecision(3)
<< cascade_threshold;
std::cerr << " alpha=" << std::fixed << std::setprecision(3)
<< alpha << " err=" << std::fixed << std::setprecision(3) << min_err
<< " loss=" << std::scientific << loss << std::endl;
//int pos = 0;
//for (int j = 0; j < data_pos.cols; ++j) {
// if (pos_trace(0, j) > cascade_threshold - 0.5) {
// pos_trace(0, pos) = pos_trace(0, j);
// data_pos.col(j).copyTo(data_pos.col(pos));
// pos_weights(0, pos) = pos_weights(0, j);
// pos += 1;
// }
//}
//std::cerr << "pos " << data_pos.cols << "/" << pos << std::endl;
//pos_trace = pos_trace.colRange(0, pos);
//data_pos = data_pos.colRange(0, pos);
//pos_weights = pos_weights.colRange(0, pos);
int pos = 0;
for (int j = 0; j < data_neg.cols; ++j) {
if (neg_trace(0, j) > cascade_threshold - 0.5) {
neg_trace(0, pos) = neg_trace(0, j);
data_neg.col(j).copyTo(data_neg.col(pos));
neg_weights(0, pos) = neg_weights(0, j);
pos += 1;
}
visited_features.push_back(feature_ind);
}
std::cerr << "neg " << data_neg.cols << "/" << pos << std::endl;
neg_trace = neg_trace.colRange(0, pos);
data_neg = data_neg.colRange(0, pos);
neg_weights = neg_weights.colRange(0, pos);
if (loss < 1e-50 || min_err > 0.5) {
std::cerr << "Stopping early" << std::endl;
weak_count_ = i + 1;
break;
}
// Normalize weights
float z = (float)sum(weights)[0];
for( int col = 0; col < weights.cols; ++col)
{
weights.at<float>(0, col) /= z;
double z = (sum(pos_weights) + sum(neg_weights))[0];
pos_weights /= z;
neg_weights /= z;
}
}
// Sort trace
Mat indices;
sortIdx(trace, indices, cv::SORT_EVERY_ROW | cv::SORT_ASCENDING);
Mat new_weights = Mat_<float>::zeros(weights.rows, weights.cols);
Mat new_labels = Mat_<int>::zeros(labels.rows, labels.cols);
Mat new_trace;
for( int col = 0; col < new_weights.cols; ++col )
{
new_weights.at<float>(0, col) =
weights.at<float>(0, indices.at<int>(0, col));
new_labels.at<int>(0, col) =
labels.at<int>(0, indices.at<int>(0, col));
int WaldBoost::predict(Ptr<CvFeatureEvaluator> eval, float *h) const
{
assert(feature_indices_.size() == size_t(weak_count_));
assert(cascade_thresholds_.size() == size_t(weak_count_));
float res = 0;
int count = weak_count_;
for (int i = 0; i < count; ++i) {
float val = (*eval)(feature_indices_[i]);
int label = polarities_[i] * (val - thresholds_[i]) > 0 ? +1: -1;
res += alphas_[i] * label;
if (res < cascade_thresholds_[i]) {
return -1;
}
}
*h = res;
return res > cascade_thresholds_[count - 1] ? +1 : -1;
}
//sort in-place to save memory
sort_columns_without_copy(data, indices);
sort(trace, new_trace, cv::SORT_EVERY_ROW | cv::SORT_ASCENDING);
void WaldBoost::write(FileStorage &fs) const
{
fs << "{";
fs << "waldboost_params"
<< "{" << "weak_count" << weak_count_ << "}";
// Compute threshold for trace
/*
int col = 0;
for( int pos_i = 0;
pos_i < pos_count * params_.alpha && col < new_labels.cols;
++col )
{
if( new_labels.at<int>(0, col) == +1 )
++pos_i;
}
*/
int cur_pos = 0, cur_neg = 0;
int max_col = 0;
for( int col = 0; col < new_labels.cols - 1; ++col ) {
if (new_labels.at<int>(0, col) == +1 )
++cur_pos;
else
++cur_neg;
float p_neg = cur_neg / (float)neg_count;
float p_pos = cur_pos / (float)pos_count;
if( params_.alpha * p_neg > p_pos )
max_col = col;
}
fs << "thresholds" << "[";
for (size_t i = 0; i < thresholds_.size(); ++i)
fs << thresholds_[i];
fs << "]";
thresholds_.push_back(new_trace.at<float>(0, max_col));
fs << "alphas" << "[";
for (size_t i = 0; i < alphas_.size(); ++i)
fs << alphas_[i];
fs << "]";
// Drop samples below threshold
//uses Rois instead of copyTo to save memory
data = data(Rect(max_col, 0, data.cols - max_col, data.rows));
new_trace.colRange(max_col, new_trace.cols).copyTo(trace);
new_weights.colRange(max_col, new_weights.cols).copyTo(weights);
new_labels.colRange(max_col, new_labels.cols).copyTo(labels);
fs << "polarities" << "[";
for (size_t i = 0; i < polarities_.size(); ++i)
fs << polarities_[i];
fs << "]";
pos_count = count(labels, +1);
neg_count = count(labels, -1);
fs << "cascade_thresholds" << "[";
for (size_t i = 0; i < cascade_thresholds_.size(); ++i)
fs << cascade_thresholds_[i];
fs << "]";
if( data.cols < 2 || neg_count == 0)
{
break;
}
}
return feature_indices;
fs << "feature_indices" << "[";
for (size_t i = 0; i < feature_indices_.size(); ++i)
fs << feature_indices_[i];
fs << "]";
fs << "}";
}
float WaldBoostImpl::predict(
const Ptr<FeatureEvaluator>& feature_evaluator) const
void WaldBoost::read(const FileNode &node)
{
float trace = 0;
CV_Assert(stumps_.size() == thresholds_.size());
for( size_t i = 0; i < stumps_.size(); ++i )
{
int value = feature_evaluator->evaluate(i);
trace += stumps_[i].predict(value);
if( trace < thresholds_[i] )
return -1;
}
return trace;
weak_count_ = (int)(node["waldboost_params"]["weak_count"]);
thresholds_.resize(weak_count_);
alphas_.resize(weak_count_);
polarities_.resize(weak_count_);
cascade_thresholds_.resize(weak_count_);
feature_indices_.resize(weak_count_);
FileNodeIterator n;
n = node["thresholds"].begin();
for (int i = 0; i < weak_count_; ++i, ++n)
*n >> thresholds_[i];
n = node["alphas"].begin();
for (int i = 0; i < weak_count_; ++i, ++n)
*n >> alphas_[i];
n = node["polarities"].begin();
for (int i = 0; i < weak_count_; ++i, ++n)
*n >> polarities_[i];
n = node["cascade_thresholds"].begin();
for (int i = 0; i < weak_count_; ++i, ++n)
*n >> cascade_thresholds_[i];
n = node["feature_indices"].begin();
for (int i = 0; i < weak_count_; ++i, ++n)
*n >> feature_indices_[i];
}
Ptr<WaldBoost>
createWaldBoost(const WaldBoostParams& params)
void WaldBoost::reset(int weak_count)
{
return Ptr<WaldBoost>(new WaldBoostImpl(params));
weak_count_ = weak_count;
thresholds_.clear();
alphas_.clear();
feature_indices_.clear();
polarities_.clear();
cascade_thresholds_.clear();
}
WaldBoost::~WaldBoost()
{
}
} /* namespace xobjdetect */
} /* namespace cv */
}
}
/*
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
(3-clause BSD License)
Copyright (C) 2000-2015, Intel Corporation, all rights reserved.
Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
Copyright (C) 2009-2015, NVIDIA Corporation, all rights reserved.
Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved.
Copyright (C) 2015, OpenCV Foundation, all rights reserved.
Copyright (C) 2015, Itseez 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:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions 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.
* Neither the names of the copyright holders nor the names of the contributors
may 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 copyright holders 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.
*/
#ifndef __OPENCV_XOBJDETECT_WALDBOOST_HPP__
#define __OPENCV_XOBJDETECT_WALDBOOST_HPP__
#include "precomp.hpp"
namespace cv {
namespace xobjdetect {
class WaldBoost {
public:
WaldBoost(int weak_count);
WaldBoost();
std::vector<int> get_feature_indices();
void detect(Ptr<CvFeatureEvaluator> eval,
const Mat& img,
const std::vector<float>& scales,
std::vector<Rect>& bboxes,
Mat1f& confidences);
void detect(Ptr<CvFeatureEvaluator> eval,
const Mat& img,
const std::vector<float>& scales,
std::vector<Rect>& bboxes,
std::vector<double>& confidences);
void fit(Mat& data_pos, Mat& data_neg);
int predict(Ptr<CvFeatureEvaluator> eval, float *h) const;
void save(const std::string& filename);
void load(const std::string& filename);
void read(const FileNode &node);
void write(FileStorage &fs) const;
void reset(int weak_count);
~WaldBoost();
private:
int weak_count_;
std::vector<float> thresholds_;
std::vector<float> alphas_;
std::vector<int> feature_indices_;
std::vector<int> polarities_;
std::vector<float> cascade_thresholds_;
};
}
}
#endif
/*
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
(3-clause BSD License)
Copyright (C) 2000-2015, Intel Corporation, all rights reserved.
Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
Copyright (C) 2009-2015, NVIDIA Corporation, all rights reserved.
Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved.
Copyright (C) 2015, OpenCV Foundation, all rights reserved.
Copyright (C) 2015, Itseez 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:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions 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.
* Neither the names of the copyright holders nor the names of the contributors
may 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 copyright holders 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.
*/
#include "precomp.hpp"
using std::cerr;
using std::endl;
using std::vector;
using std::string;
namespace cv {
namespace xobjdetect {
static vector<Mat> sample_patches(
const string& path,
int n_rows,
int n_cols,
size_t n_patches)
{
vector<String> filenames;
glob(path, filenames);
vector<Mat> patches;
size_t patch_count = 0;
for (size_t i = 0; i < filenames.size(); ++i) {
Mat img = imread(filenames[i], CV_LOAD_IMAGE_GRAYSCALE);
for (int row = 0; row + n_rows < img.rows; row += n_rows) {
for (int col = 0; col + n_cols < img.cols; col += n_cols) {
patches.push_back(img(Rect(col, row, n_cols, n_rows)).clone());
patch_count += 1;
if (patch_count == n_patches) {
goto sampling_finished;
}
}
}
}
sampling_finished:
return patches;
}
static vector<Mat> read_imgs(const string& path)
{
vector<String> filenames;
glob(path, filenames);
vector<Mat> imgs;
for (size_t i = 0; i < filenames.size(); ++i) {
imgs.push_back(imread(filenames[i], CV_LOAD_IMAGE_GRAYSCALE));
}
return imgs;
}
void WBDetectorImpl::read(const FileNode& node)
{
boost_.read(node);
}
void WBDetectorImpl::write(FileStorage &fs) const
{
boost_.write(fs);
}
void WBDetectorImpl::train(
const string& pos_samples_path,
const string& neg_imgs_path)
{
vector<Mat> pos_imgs = read_imgs(pos_samples_path);
vector<Mat> neg_imgs = sample_patches(neg_imgs_path, 24, 24, pos_imgs.size() * 10);
assert(pos_imgs.size());
assert(neg_imgs.size());
int n_features;
Mat pos_data, neg_data;
Ptr<CvFeatureEvaluator> eval = CvFeatureEvaluator::create();
eval->init(CvFeatureParams::create(), 1, Size(24, 24));
n_features = eval->getNumFeatures();
const int stages[] = {64, 128, 256, 512, 1024};
const int stage_count = sizeof(stages) / sizeof(*stages);
const int stage_neg = (int)(pos_imgs.size() * 5);
const int max_per_image = 100;
const float scales_arr[] = {.3f, .4f, .5f, .6f, .7f, .8f, .9f, 1.0f};
const vector<float> scales(scales_arr,
scales_arr + sizeof(scales_arr) / sizeof(*scales_arr));
vector<String> neg_filenames;
glob(neg_imgs_path, neg_filenames);
for (int i = 0; i < stage_count; ++i) {
cerr << "compute features" << endl;
pos_data = Mat1b(n_features, (int)pos_imgs.size());
neg_data = Mat1b(n_features, (int)neg_imgs.size());
for (size_t k = 0; k < pos_imgs.size(); ++k) {
eval->setImage(pos_imgs[k], +1, 0, boost_.get_feature_indices());
for (int j = 0; j < n_features; ++j) {
pos_data.at<uchar>(j, (int)k) = (uchar)(*eval)(j);
}
}
for (size_t k = 0; k < neg_imgs.size(); ++k) {
eval->setImage(neg_imgs[k], 0, 0, boost_.get_feature_indices());
for (int j = 0; j < n_features; ++j) {
neg_data.at<uchar>(j, (int)k) = (uchar)(*eval)(j);
}
}
boost_.reset(stages[i]);
boost_.fit(pos_data, neg_data);
if (i + 1 == stage_count) {
break;
}
int bootstrap_count = 0;
size_t img_i = 0;
for (; img_i < neg_filenames.size(); ++img_i) {
cerr << "win " << bootstrap_count << "/" << stage_neg
<< " img " << (img_i + 1) << "/" << neg_filenames.size() << "\r";
Mat img = imread(neg_filenames[img_i], CV_LOAD_IMAGE_GRAYSCALE);
vector<Rect> bboxes;
Mat1f confidences;
boost_.detect(eval, img, scales, bboxes, confidences);
if (confidences.rows > 0) {
Mat1i indices;
sortIdx(confidences, indices,
CV_SORT_EVERY_COLUMN + CV_SORT_DESCENDING);
int win_count = min(max_per_image, confidences.rows);
win_count = min(win_count, stage_neg - bootstrap_count);
Mat window;
for (int k = 0; k < win_count; ++k) {
resize(img(bboxes[indices(k, 0)]), window, Size(24, 24));
neg_imgs.push_back(window.clone());
bootstrap_count += 1;
}
if (bootstrap_count >= stage_neg) {
break;
}
}
}
cerr << "bootstrapped " << bootstrap_count << " windows from "
<< (img_i + 1) << " images" << endl;
}
}
void WBDetectorImpl::detect(
const Mat& img,
vector<Rect> &bboxes,
vector<double> &confidences)
{
Mat test_img = img.clone();
bboxes.clear();
confidences.clear();
vector<float> scales;
for (float scale = 0.2f; scale < 1.2f; scale *= 1.1f) {
scales.push_back(scale);
}
Ptr<CvFeatureParams> params = CvFeatureParams::create();
Ptr<CvFeatureEvaluator> eval = CvFeatureEvaluator::create();
eval->init(params, 1, Size(24, 24));
boost_.detect(eval, img, scales, bboxes, confidences);
assert(confidences.size() == bboxes.size());
}
Ptr<WBDetector>
WBDetector::create()
{
return Ptr<WBDetector>(new WBDetectorImpl());
}
}
}
......@@ -39,6 +39,39 @@ the use of this software, even if advised of the possibility of such damage.
*/
/** @defgroup adas Advanced Driver Assistance
*/
#ifndef __OPENCV_XOBJDETECT_DETECTOR_HPP__
#define __OPENCV_XOBJDETECT_DETECTOR_HPP__
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <vector>
#include <string>
#include "precomp.hpp"
namespace cv
{
namespace xobjdetect
{
class WBDetectorImpl : public WBDetector {
public:
virtual void read(const FileNode &node);
virtual void write(FileStorage &fs) const;
virtual void train(
const std::string& pos_samples,
const std::string& neg_imgs);
virtual void detect(
const Mat& img,
std::vector<Rect> &bboxes,
std::vector<double> &confidences);
private:
WaldBoost boost_;
};
} /* namespace xobjdetect */
} /* namespace cv */
#endif /* __OPENCV_XOBJDETECT_DETECTOR_HPP__ */
add_subdirectory(waldboost_detector)
set(name fcw_train)
set(name waldboost_detector)
set(the_target opencv_${name})
set(OPENCV_${the_target}_DEPS opencv_core opencv_imgcodecs opencv_videoio
......
#include <opencv2/xobjdetect.hpp>
#include <opencv2/imgcodecs/imgcodecs_c.h>
#include <opencv2/imgproc.hpp>
#include <iostream>
#include <cstdio>
using namespace std;
using namespace cv;
using namespace cv::xobjdetect;
int main(int argc, char **argv)
{
if (argc < 5) {
cerr << "Usage: " << argv[0] << " train <model_filename> <pos_path> <neg_path>" << endl;
cerr << " " << argv[0] << " detect <model_filename> <img_filename> <out_filename> <labelling_filename>" << endl;
return 0;
}
string mode = argv[1];
Ptr<WBDetector> detector = WBDetector::create();
if (mode == "train") {
assert(argc == 5);
detector->train(argv[3], argv[4]);
FileStorage fs(argv[2], FileStorage::WRITE);
fs << "waldboost";
detector->write(fs);
} else if (mode == "detect") {
assert(argc == 6);
vector<Rect> bboxes;
vector<double> confidences;
Mat img = imread(argv[3], CV_LOAD_IMAGE_GRAYSCALE);
FileStorage fs(argv[2], FileStorage::READ);
detector->read(fs.getFirstTopLevelNode());
detector->detect(img, bboxes, confidences);
FILE *fhandle = fopen(argv[5], "a");
for (size_t i = 0; i < bboxes.size(); ++i) {
Rect o = bboxes[i];
fprintf(fhandle, "%s;%u;%u;%u;%u;%lf\n",
argv[3], o.x, o.y, o.width, o.height, confidences[i]);
}
for (size_t i = 0; i < bboxes.size(); ++i) {
rectangle(img, bboxes[i], Scalar(255, 0, 0));
}
imwrite(argv[4], img);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment