Merge pull request #21 from shahurik/adas

ADAS: training app, stumps and waldboost
pull/31/head
Vadim Pisarevsky 11 years ago
commit c064042c33
  1. 4
      modules/adas/CMakeLists.txt
  2. 40
      modules/adas/include/opencv2/adas.hpp
  3. 0
      modules/adas/src/adas.cpp
  4. 34
      modules/adas/tools/CMakeLists.txt
  5. 195
      modules/adas/tools/fcw_train.cpp
  6. 2
      modules/xobjdetect/CMakeLists.txt
  7. 179
      modules/xobjdetect/include/opencv2/xobjdetect.hpp
  8. 62
      modules/xobjdetect/include/opencv2/xobjdetect/private.hpp
  9. 203
      modules/xobjdetect/src/acffeature.cpp
  10. 150
      modules/xobjdetect/src/icfdetector.cpp
  11. 56
      modules/xobjdetect/src/precomp.hpp
  12. 203
      modules/xobjdetect/src/stump.cpp
  13. 187
      modules/xobjdetect/src/waldboost.cpp

@ -0,0 +1,4 @@
set(the_description "Automatic driver assistance algorithms")
ocv_define_module(adas opencv_xobjdetect)
add_subdirectory(tools)

@ -0,0 +1,40 @@
/*
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.
*/

@ -0,0 +1,34 @@
set(name fcw_train)
set(the_target opencv_${name})
set(OPENCV_${the_target}_DEPS 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(${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} RUNTIME DESTINATION bin COMPONENT main)

@ -0,0 +1,195 @@
#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;
#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_pos_int(const char *str, int *n)
{
int pos = 0;
if( sscanf(str, "%d%n", n, &pos) != 1 || str[pos] != '\0' || *n <= 0 )
{
return false;
}
return true;
}
static bool read_model_size(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 bool read_overlap(const char *str, double *overlap)
{
int pos = 0;
if( sscanf(str, "%lf%n", overlap, &pos) != 1 || str[pos] != '\0' ||
*overlap < 0 || *overlap > 1)
{
return false;
}
return true;
}
static bool read_labels(const string& path,
vector<string>& filenames, vector< vector<Rect> >& labels)
{
string labels_path = path + "/gt.txt";
string filename, line;
int x1, y1, x2, y2;
char delim;
ifstream ifs(labels_path.c_str());
if( !ifs.good() )
return false;
while( getline(ifs, line) )
{
stringstream stream(line);
stream >> filename;
filenames.push_back(path + "/" + filename);
vector<Rect> filename_labels;
while( stream >> x1 >> y1 >> x2 >> y2 >> delim )
{
filename_labels.push_back(Rect(x1, y1, x2, y2));
}
labels.push_back(filename_labels);
filename_labels.clear();
}
return true;
}
int main(int argc, char *argv[])
{
if( argc == 1 )
{
printf("Usage: %s OPTIONS, where OPTIONS are:\n"
"\n"
"--path <path> - path to dir with data and labels\n"
" (labels should have name gt.txt)\n"
"\n"
"--feature_count <count> - number of features to generate\n"
"\n"
"--weak_count <count> - number of weak classifiers in cascade\n"
"\n"
"--model_size <rowsxcols> - model size in pixels\n"
"\n"
"--overlap <measure> - number from [0, 1], means maximum\n"
" overlap with objects while sampling background\n"
"\n"
"--model_filename <path> - filename for saving model\n",
argv[0]);
return 0;
}
string path, model_path;
ICFDetectorParams params;
for( int i = 1; i < argc; ++i )
{
if( !strcmp("--path", argv[i]) )
{
i += 1;
path = argv[i];
}
else if( !strcmp("--feature_count", argv[i]) )
{
i += 1;
if( !read_pos_int(argv[i], &params.feature_count) )
{
fprintf(stderr, "Error reading feature count from `%s`\n",
argv[i]);
return 1;
}
}
else if( !strcmp("--weak_count", argv[i]) )
{
i += 1;
if( !read_pos_int(argv[i], &params.weak_count) )
{
fprintf(stderr, "Error reading weak count from `%s`\n",
argv[i]);
return 1;
}
}
else if( !strcmp("--model_size", argv[i]) )
{
i += 1;
if( !read_model_size(argv[i], &params.model_n_rows,
&params.model_n_cols) )
{
fprintf(stderr, "Error reading model size from `%s`\n",
argv[i]);
return 1;
}
}
else if( !strcmp("--overlap", argv[i]) )
{
i += 1;
if( !read_overlap(argv[i], &params.overlap) )
{
fprintf(stderr, "Error reading overlap from `%s`\n",
argv[i]);
return 1;
}
}
else if( !strcmp("--model_filename", argv[i]) )
{
i += 1;
model_path = argv[i];
}
else
{
fprintf(stderr, "Error: unknown argument `%s`\n", argv[i]);
return 1;
}
}
try
{
ICFDetector detector;
vector<string> filenames;
vector< vector<Rect> > labels;
read_labels(path, filenames, labels);
detector.train(filenames, labels, params);
}
catch( const char *err )
{
cerr << err << endl;
}
catch( ... )
{
cerr << "Unknown error\n" << endl;
}
}

@ -0,0 +1,2 @@
set(the_description "Object detection algorithms")
ocv_define_module(xobjdetect opencv_core opencv_imgproc opencv_highgui)

@ -0,0 +1,179 @@
/*
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.
*/
#ifndef __OPENCV_XOBJDETECT_XOBJDETECT_HPP__
#define __OPENCV_XOBJDETECT_XOBJDETECT_HPP__
#include <opencv2/core.hpp>
#include <vector>
#include <string>
namespace cv
{
namespace xobjdetect
{
/* Compute channel pyramid for acf features
image image, for which channels should be computed
channels output array for computed channels
*/
void computeChannels(InputArray image, OutputArrayOfArrays channels);
class CV_EXPORTS ACFFeatureEvaluator : public Algorithm
{
public:
/* Set channels for feature evaluation */
virtual void setChannels(InputArrayOfArrays channels) = 0;
/* Set window position */
virtual void setPosition(Size position) = 0;
/* Evaluate feature with given index for current channels
and window position */
virtual int evaluate(size_t feature_ind) const = 0;
/* Evaluate all features for current channels and window position
Returns matrix-column of features
*/
virtual void evaluateAll(OutputArray feature_values) const = 0;
};
/* Construct evaluator, set features to evaluate */
CV_EXPORTS Ptr<ACFFeatureEvaluator>
createACFFeatureEvaluator(const std::vector<Point3i>& features);
/* Generate acf features
window_size size of window in which features should be evaluated
count number of features to generate.
Max number of features is min(count, # possible distinct features)
Returns vector of distinct acf features
*/
std::vector<Point3i>
generateFeatures(Size window_size, int count = INT_MAX);
struct CV_EXPORTS WaldBoostParams
{
int weak_count;
float alpha;
WaldBoostParams(): weak_count(100), alpha(0.01f)
{}
};
class CV_EXPORTS WaldBoost : public Algorithm
{
public:
/* Train WaldBoost cascade 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}
Returns feature indices chosen for cascade.
Feature enumeration starts from 0
*/
virtual std::vector<int> train(const Mat& data,
const Mat& labels) = 0;
/* Predict object class given object that can compute object features
feature_evaluator object that can compute features by demand
Returns confidence_value measure of confidense that object
is from class +1
*/
virtual float predict(
const Ptr<ACFFeatureEvaluator>& feature_evaluator) const = 0;
};
CV_EXPORTS Ptr<WaldBoost>
createWaldBoost(const WaldBoostParams& params = WaldBoostParams());
struct CV_EXPORTS ICFDetectorParams
{
int feature_count;
int weak_count;
int model_n_rows;
int model_n_cols;
double overlap;
ICFDetectorParams(): feature_count(UINT_MAX), weak_count(100),
model_n_rows(40), model_n_cols(40), overlap(0.0)
{}
};
class CV_EXPORTS ICFDetector
{
public:
/* Train detector
image_filenames filenames of images for training
labelling vector of object bounding boxes per every image
params parameters for detector training
*/
void train(const std::vector<std::string>& image_filenames,
const std::vector<std::vector<cv::Rect> >& labelling,
ICFDetectorParams params = ICFDetectorParams());
/* Save detector in file, return true on success, false otherwise */
bool save(const std::string& filename);
};
} /* namespace xobjdetect */
} /* namespace cv */
#endif /* __OPENCV_XOBJDETECT_XOBJDETECT_HPP__ */

@ -0,0 +1,62 @@
#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
Returns chosen feature index. Feature enumeration starts from 0
*/
int train(const Mat& data, const Mat& labels, const Mat& weights);
/* 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;
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_;
};
} /* namespace xobjdetect */
} /* namespace cv */
#endif // __OPENCV_XOBJDETECT_PRIVATE_HPP__

@ -0,0 +1,203 @@
/*
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
{
class ACFFeatureEvaluatorImpl : public ACFFeatureEvaluator
{
public:
ACFFeatureEvaluatorImpl(const vector<Point3i>& features):
features_(features), channels_(), position_()
{
CV_Assert(features.size() > 0);
}
virtual void setChannels(InputArrayOfArrays channels);
virtual void setPosition(Size position);
virtual int evaluate(size_t feature_ind) const;
virtual void evaluateAll(OutputArray feature_values) const;
private:
/* Features to evaluate */
std::vector<Point3i> features_;
/* Channels for feature evaluation */
std::vector<Mat> channels_;
/* Channels window position */
Size position_;
};
void ACFFeatureEvaluatorImpl::setChannels(cv::InputArrayOfArrays channels)
{
channels_.clear();
vector<Mat> ch;
channels.getMatVector(ch);
CV_Assert(ch.size() == 10);
for( size_t i = 0; i < ch.size(); ++i )
{
const Mat &channel = ch[i];
Mat_<int> acf_channel(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);
}
}
void ACFFeatureEvaluatorImpl::setPosition(Size position)
{
position_ = position;
}
int ACFFeatureEvaluatorImpl::evaluate(size_t feature_ind) const
{
CV_Assert(channels_.size() == 10);
CV_Assert(feature_ind < features_.size());
Point3i feature = features_.at(feature_ind);
int x = feature.x;
int y = feature.y;
int n = feature.z;
return channels_[n].at<int>(y, x);
}
void ACFFeatureEvaluatorImpl::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.setTo(feature_vals);
}
Ptr<ACFFeatureEvaluator>
createACFFeatureEvaluator(const vector<Point3i>& features)
{
return Ptr<ACFFeatureEvaluator>(new ACFFeatureEvaluatorImpl(features));
}
vector<Point3i> generateFeatures(Size window_size, int count)
{
CV_Assert(count > 0);
int cur_count = 0;
int max_count = window_size.width * window_size.height / 16;
count = min(count, max_count);
vector<Point3i> features;
for( int x = 0; x < window_size.width / 4; ++x )
{
for( int y = 0; y < window_size.height / 4; ++y )
{
/* Assume there are 10 channel types */
for( int n = 0; n < 10; ++n )
{
features.push_back(Point3i(x, y, n));
if( (cur_count += 1) == count )
break;
}
}
}
return features;
}
void computeChannels(cv::InputArray image, cv::OutputArrayOfArrays channels_)
{
Mat src(image.getMat().rows, image.getMat().cols, CV_32FC3);
image.getMat().convertTo(src, CV_32FC3, 1./255);
Mat_<float> grad;
Mat gray;
cvtColor(src, gray, CV_RGB2GRAY);
Mat_<float> row_der, col_der;
Sobel(gray, row_der, CV_32F, 0, 1);
Sobel(gray, col_der, CV_32F, 1, 0);
magnitude(row_der, col_der, grad);
Mat_<Vec6f> hist(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;
if (angle < 0)
angle += 180;
int ind = (int)(angle / 30);
hist(row, col)[ind] = grad(row, col);
}
}
vector<Mat> channels;
channels.push_back(gray);
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]);
channels_.setTo(channels);
}
} /* namespace xobjdetect */
} /* namespace cv */

@ -0,0 +1,150 @@
/*
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::string;
using std::min;
using std::max;
namespace cv
{
namespace xobjdetect
{
static bool overlap(const Rect& r, const vector<Rect>& gt)
{
for( size_t i = 0; i < gt.size(); ++i )
if( (r & gt[i]).area() )
return true;
return false;
}
void ICFDetector::train(const vector<string>& image_filenames,
const vector< vector<Rect> >& labelling,
ICFDetectorParams params)
{
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 < image_filenames.size(); ++i, ++pos_count )
{
Mat img = imread(String(image_filenames[i].c_str()));
for( size_t j = 0; j < labelling[i].size(); ++j )
{
Rect r = labelling[i][j];
if( r.x > img.cols || r.y > img.rows )
continue;
sample = img.colRange(max(r.x, 0), min(r.width, img.cols))
.rowRange(max(r.y, 0), min(r.height, img.rows));
resize(sample, resized_sample, model_size);
samples.push_back(resized_sample);
}
}
int neg_count = 0;
RNG rng;
for( size_t i = 0; i < image_filenames.size(); ++i )
{
Mat img = imread(String(image_filenames[i].c_str()));
for( int j = 0; j < (int)(pos_count / image_filenames.size() + 1); )
{
Rect r;
r.x = rng.uniform(0, img.cols);
r.width = rng.uniform(r.x + 1, img.cols);
r.y = rng.uniform(0, img.rows);
r.height = rng.uniform(r.y + 1, img.rows);
if( !overlap(r, labelling[i]) )
{
sample = img.colRange(r.x, r.width).rowRange(r.y, r.height);
//resize(sample, resized_sample);
samples.push_back(resized_sample);
++neg_count;
++j;
}
}
}
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<Point3i> features = generateFeatures(model_size);
Ptr<ACFFeatureEvaluator> feature_evaluator = createACFFeatureEvaluator(features);
Mat_<int> data((int)features.size(), (int)samples.size());
Mat_<int> feature_col;
vector<Mat> channels;
for( int i = 0; i < (int)samples.size(); ++i )
{
computeChannels(samples[i], channels);
feature_evaluator->setChannels(channels);
feature_evaluator->evaluateAll(feature_col);
for( int j = 0; j < feature_col.rows; ++j )
data(i, j) = feature_col(0, j);
}
WaldBoostParams wparams;
wparams.weak_count = params.weak_count;
wparams.alpha = 0.001f;
Ptr<WaldBoost> waldboost = createWaldBoost(wparams);
waldboost->train(data, labels);
}
bool ICFDetector::save(const string&)
{
return true;
}
} /* namespace xobjdetect */
} /* namespace cv */

@ -0,0 +1,56 @@
/*
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.
*/
#ifndef __OPENCV_XOBJDETECT_PRECOMP_HPP__
#define __OPENCV_XOBJDETECT_PRECOMP_HPP__
#include <opencv2/xobjdetect.hpp>
#include <opencv2/xobjdetect/private.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/imgproc/types_c.h>
#include <opencv2/highgui.hpp>
#include <algorithm>
#include <cmath>
#endif /* __OPENCV_XOBJDETECT_PRECOMP_HPP__ */

@ -0,0 +1,203 @@
/*
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);
}
}
}
int Stump::train(const Mat& data, const Mat& labels, const Mat& weights)
{
CV_Assert(labels.rows == 1 && labels.cols == data.cols);
CV_Assert(weights.rows == 1 && weights.cols == data.cols);
/* Assert that data and labels have int type */
/* Assert that weights have float type */
/* Prepare labels for each feature rearranged according to sorted order */
Mat sorted_labels(data.rows, data.cols, labels.type());
Mat sorted_weights(data.rows, data.cols, weights.type());
Mat indices;
sortIdx(data, indices, cv::SORT_EVERY_ROW | cv::SORT_ASCENDING);
for( int row = 0; row < indices.rows; ++row )
{
for( int col = 0; col < indices.cols; ++col )
{
sorted_labels.at<int>(row, col) =
labels.at<int>(0, indices.at<int>(row, col));
sorted_weights.at<float>(row, col) =
weights.at<float>(0, indices.at<int>(row, col));
}
}
/* Sort feature values */
Mat sorted_data(data.rows, data.cols, data.type());
sort(data, sorted_data, cv::SORT_EVERY_ROW | cv::SORT_ASCENDING);
/* Split positive and negative weights */
Mat pos_weights = Mat::zeros(sorted_weights.rows, sorted_weights.cols,
sorted_weights.type());
Mat neg_weights = Mat::zeros(sorted_weights.rows, sorted_weights.cols,
sorted_weights.type());
for( int row = 0; row < data.rows; ++row )
{
for( int col = 0; col < data.cols; ++col )
{
if( sorted_labels.at<int>(row, col) == +1 )
{
pos_weights.at<float>(row, col) =
sorted_weights.at<float>(row, col);
}
else
{
neg_weights.at<float>(row, col) =
sorted_weights.at<float>(row, col);
}
}
}
/* Compute cumulative sums for fast stump error computation */
Mat pos_cum_weights = Mat::zeros(sorted_weights.rows, sorted_weights.cols,
sorted_weights.type());
Mat neg_cum_weights = Mat::zeros(sorted_weights.rows, sorted_weights.cols,
sorted_weights.type());
cumsum(pos_weights, pos_cum_weights);
cumsum(neg_weights, neg_cum_weights);
/* Compute total weights of positive and negative samples */
float pos_total_weight = pos_cum_weights.at<float>(0, weights.cols - 1);
float neg_total_weight = neg_cum_weights.at<float>(0, weights.cols - 1);
float eps = 1.0f / (4 * labels.cols);
/* Compute minimal error */
float min_err = FLT_MAX;
int min_row = -1;
int min_col = -1;
int min_polarity = 0;
float min_pos_value = 1, min_neg_value = -1;
for( int row = 0; row < sorted_weights.rows; ++row )
{
for( int col = 0; col < sorted_weights.cols - 1; ++col )
{
float err, h_pos, h_neg;
// Direct polarity
float pos_wrong = pos_cum_weights.at<float>(row, col);
float pos_right = pos_total_weight - pos_wrong;
float neg_right = neg_cum_weights.at<float>(row, col);
float neg_wrong = neg_total_weight - neg_right;
h_pos = (float)(.5 * log((pos_right + eps) / (pos_wrong + eps)));
h_neg = (float)(.5 * log((neg_wrong + eps) / (neg_right + eps)));
err = sqrt(pos_right * neg_wrong) + sqrt(pos_wrong * neg_right);
if( err < min_err )
{
min_err = err;
min_row = row;
min_col = col;
min_polarity = +1;
min_pos_value = h_pos;
min_neg_value = h_neg;
}
// Opposite polarity
swap(pos_right, pos_wrong);
swap(neg_right, neg_wrong);
h_pos = -h_pos;
h_neg = -h_neg;
err = sqrt(pos_right * neg_wrong) + sqrt(pos_wrong * neg_right);
if( err < min_err )
{
min_err = err;
min_row = row;
min_col = col;
min_polarity = -1;
min_pos_value = h_pos;
min_neg_value = h_neg;
}
}
}
/* Compute threshold, store found values in fields */
threshold_ = ( sorted_data.at<int>(min_row, min_col) +
sorted_data.at<int>(min_row, min_col + 1) ) / 2;
polarity_ = min_polarity;
pos_value_ = min_pos_value;
neg_value_ = min_neg_value;
return min_row;
}
float Stump::predict(int value) const
{
return polarity_ * (value - threshold_) > 0 ? pos_value_ : neg_value_;
}
} /* namespace xobjdetect */
} /* namespace cv */

@ -0,0 +1,187 @@
/*
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::swap;
using std::vector;
namespace cv
{
namespace xobjdetect
{
class WaldBoostImpl : public WaldBoost
{
public:
/* Initialize WaldBoost cascade with default of specified parameters */
WaldBoostImpl(const WaldBoostParams& params):
params_(params)
{}
virtual std::vector<int> train(const Mat& data,
const Mat& labels);
virtual float predict(
const Ptr<ACFFeatureEvaluator>& feature_evaluator) const;
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_;
};
vector<int> WaldBoostImpl::train(const Mat& data, const Mat& labels)
{
CV_Assert(labels.rows == 1 && labels.cols == data.cols);
int pos_count = 0, neg_count = 0;
for( int col = 0; col < labels.cols; ++col )
{
if( labels.at<int>(0, col) == +1 )
pos_count += 1;
else
neg_count += 1;
}
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 )
{
if( labels.at<int>(0, col) == +1 )
weights.at<float>(0, col) = pos_weight;
else
weights.at<float>(0, col) = neg_weight;
}
vector<int> feature_indices;
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);
stumps_.push_back(s);
feature_indices.push_back(feature_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);
}
// Normalize weights
float z = (float)sum(weights)[0];
for( int col = 0; col < weights.cols; ++col)
{
weights.at<float>(0, col) /= 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));
}
sort(trace, new_trace, cv::SORT_EVERY_ROW | cv::SORT_ASCENDING);
// Compute threshold for trace
int col = 0;
for( int pos_i = 0;
pos_i < pos_count * params_.alpha && col < weights.cols;
++col )
{
if( labels.at<int>(0, col) == +1 )
++pos_i;
}
thresholds_.push_back(new_trace.at<float>(0, col));
// Drop samples below threshold
new_trace.colRange(col, new_trace.cols).copyTo(trace);
new_weights.colRange(col, new_weights.cols).copyTo(weights);
new_labels.colRange(col, new_labels.cols).copyTo(labels);
}
return feature_indices;
}
float WaldBoostImpl::predict(
const Ptr<ACFFeatureEvaluator>& feature_evaluator) const
{
float trace = 0;
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;
}
Ptr<WaldBoost>
createWaldBoost(const WaldBoostParams& params)
{
return Ptr<WaldBoost>(new WaldBoostImpl(params));
}
} /* namespace xobjdetect */
} /* namespace cv */
Loading…
Cancel
Save