Commit 319b25ee authored by Vlad Shakhuro's avatar Vlad Shakhuro

Bomb commit

parent 9e5b6684
set(name fcw_train)
set(the_target opencv_${name})
set(the_module opencv_adas)
ocv_check_dependencies(${OPENCV_MODULE_${the_module}_DEPS})
if(NOT OCV_DEPENDENCIES_FOUND)
return()
endif()
project(${the_target})
ocv_include_directories("${OpenCV_SOURCE_DIR}/include/opencv")
ocv_include_modules(${OPENCV_MODULE_${the_module}_DEPS})
file(GLOB ${the_target}_SOURCES ${CMAKE_CURRENT_LIST_DIR}/*.cpp)
add_executable(${the_target} ${${the_target}_SOURCES})
ocv_target_link_libraries(${the_target} ${OPENCV_MODULE_${the_module}_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)
add_subdirectory(fcw_train)
add_subdirectory(fcw_detect)
set(name fcw_detect)
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)
#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;
}
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}"
;
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");
float threshold = parser.get<float>("threshold");
if( !parser.check() )
{
parser.printErrors();
return 1;
}
ICFDetector detector;
FileStorage fs(model_filename, FileStorage::READ);
fs["icfdetector"] >> detector;
fs.release();
vector<Rect> objects;
Mat img = imread(image_path);
detector.detect(img, objects, 1.1, Size(40, 40),
Size(300, 300), threshold);
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;
#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;
}
}
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)
#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/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;
}
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}"
"{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}"
;
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");
cerr << pos_path << endl;
cerr << bg_path << endl;
ICFDetectorParams params;
params.feature_count = parser.get<size_t>("feature_count");
params.weak_count = parser.get<size_t>("weak_count");
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( !parser.check() )
{
parser.printErrors();
return 1;
}
ICFDetector detector;
detector.train(pos_path, bg_path, params);
FileStorage fs(model_filename, FileStorage::WRITE);
fs << "icfdetector" << detector;
fs.release();
}
......@@ -58,7 +58,7 @@ namespace xobjdetect
channels — output array for computed channels
*/
void computeChannels(InputArray image, OutputArrayOfArrays channels);
void computeChannels(InputArray image, std::vector<Mat>& channels);
class CV_EXPORTS ACFFeatureEvaluator : public Algorithm
{
......@@ -69,6 +69,8 @@ public:
/* Set window position */
virtual void setPosition(Size position) = 0;
virtual void assertChannels() = 0;
/* Evaluate feature with given index for current channels
and window position */
virtual int evaluate(size_t feature_ind) const = 0;
......@@ -103,7 +105,7 @@ struct CV_EXPORTS WaldBoostParams
int weak_count;
float alpha;
WaldBoostParams(): weak_count(100), alpha(0.01f)
WaldBoostParams(): weak_count(100), alpha(0.02f)
{}
};
......@@ -122,8 +124,8 @@ public:
Returns feature indices chosen for cascade.
Feature enumeration starts from 0
*/
virtual std::vector<int> train(const Mat& data,
const Mat& labels) = 0;
virtual std::vector<int> train(const Mat& /*data*/,
const Mat& /*labels*/) {return std::vector<int>();}
/* Predict object class given object that can compute object features
......@@ -133,10 +135,21 @@ public:
is from class +1
*/
virtual float predict(
const Ptr<ACFFeatureEvaluator>& feature_evaluator) const = 0;
const Ptr<ACFFeatureEvaluator>& /*feature_evaluator*/) const
{return 0.0f;}
/* Write WaldBoost to FileStorage */
virtual void write(FileStorage& /*fs*/) const {}
/* Read WaldBoost */
virtual void read(const FileNode& /*node*/) {}
};
void write(FileStorage& fs, String&, const WaldBoost& waldboost);
void read(const FileNode& node, WaldBoost& w,
const WaldBoost& default_value = WaldBoost());
CV_EXPORTS Ptr<WaldBoost>
createWaldBoost(const WaldBoostParams& params = WaldBoostParams());
......@@ -146,32 +159,63 @@ struct CV_EXPORTS ICFDetectorParams
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)
model_n_rows(40), model_n_cols(40)
{}
};
class CV_EXPORTS ICFDetector
{
public:
ICFDetector(): waldboost_(), features_() {}
/* Train detector
image_filenames — filenames of images for training
pos_path — path to folder with images of objects
labelling — vector of object bounding boxes per every image
bg_path — path to folder with background images
params — parameters for detector training
*/
void train(const std::vector<std::string>& image_filenames,
const std::vector<std::vector<cv::Rect> >& labelling,
void train(const String& pos_path,
const String& bg_path,
ICFDetectorParams params = ICFDetectorParams());
/* Save detector in file, return true on success, false otherwise */
bool save(const std::string& filename);
/* Detect object on image
image — image for detection
object — output array of bounding boxes
scaleFactor — scale between layers in detection pyramid
minSize — min size of objects in pixels
maxSize — max size of objects in pixels
*/
void detect(const Mat& image, std::vector<Rect>& objects,
double scaleFactor, Size minSize, Size maxSize, float threshold);
/* Write detector to FileStorage */
void write(FileStorage &fs) const;
/* Read detector */
void read(const FileNode &node);
private:
Ptr<WaldBoost> waldboost_;
std::vector<Point3i> features_;
int model_n_rows_;
int model_n_cols_;
};
CV_EXPORTS void write(FileStorage& fs, String&, const ICFDetector& detector);
CV_EXPORTS void read(const FileNode& node, ICFDetector& d,
const ICFDetector& default_value = ICFDetector());
} /* namespace xobjdetect */
} /* namespace cv */
......
......@@ -47,6 +47,26 @@ public:
*/
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_;
......@@ -56,6 +76,10 @@ private:
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 */
......
......@@ -64,6 +64,7 @@ public:
}
virtual void setChannels(InputArrayOfArrays channels);
virtual void assertChannels();
virtual void setPosition(Size position);
virtual int evaluate(size_t feature_ind) const;
virtual void evaluateAll(OutputArray feature_values) const;
......@@ -77,16 +78,56 @@ private:
Size position_;
};
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;
}
void ACFFeatureEvaluatorImpl::assertChannels()
{
bool null_data = true;
for( size_t i = 0; i < channels_.size(); ++i )
null_data &= isNull(channels_[i]);
CV_Assert(!null_data);
}
void ACFFeatureEvaluatorImpl::setChannels(cv::InputArrayOfArrays channels)
{
channels_.clear();
vector<Mat> ch;
channels.getMatVector(ch);
CV_Assert(ch.size() == 10);
/*int min_val = 100500, max_val = -1;
for( size_t i = 0; i < ch.size(); ++i )
{
const Mat &channel = ch[i];
for( int row = 0; row < channel.rows; ++row )
for( int col = 0; col < channel.cols; ++col )
{
int val = (int)channel.at<float>(row, col);
if( val < min_val )
min_val = val;
else if( val > max_val )
max_val = val;
}
}
cout << "SET " << min_val << " " << max_val << endl;
*/
for( size_t i = 0; i < ch.size(); ++i )
{
const Mat &channel = ch[i];
Mat_<int> acf_channel(channel.rows / 4, channel.cols / 4);
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 )
......@@ -94,18 +135,23 @@ void ACFFeatureEvaluatorImpl::setChannels(cv::InputArrayOfArrays channels)
int sum = 0;
for( int cell_row = row; cell_row < row + 4; ++cell_row )
for( int cell_col = col; cell_col < col + 4; ++cell_col )
{
//cout << channel.rows << " " << channel.cols << endl;
//cout << cell_row << " " << cell_col << endl;
sum += (int)channel.at<float>(cell_row, cell_col);
}
acf_channel(row / 4, col / 4) = sum;
}
}
channels_.push_back(acf_channel);
channels_.push_back(acf_channel.clone());
}
}
void ACFFeatureEvaluatorImpl::setPosition(Size position)
{
position_ = position;
position_ = Size(position.width / 4, position.height / 4);
}
int ACFFeatureEvaluatorImpl::evaluate(size_t feature_ind) const
......@@ -117,7 +163,7 @@ int ACFFeatureEvaluatorImpl::evaluate(size_t feature_ind) const
int x = feature.x;
int y = feature.y;
int n = feature.z;
return channels_[n].at<int>(y, x);
return channels_[n].at<int>(y + position_.width, x + position_.height);
}
void ACFFeatureEvaluatorImpl::evaluateAll(OutputArray feature_values) const
......@@ -127,7 +173,7 @@ void ACFFeatureEvaluatorImpl::evaluateAll(OutputArray feature_values) const
{
feature_vals(0, i) = evaluate(i);
}
feature_values.setTo(feature_vals);
feature_values.assign(feature_vals);
}
Ptr<ACFFeatureEvaluator>
......@@ -159,14 +205,15 @@ vector<Point3i> generateFeatures(Size window_size, int count)
return features;
}
void computeChannels(cv::InputArray image, cv::OutputArrayOfArrays channels_)
void computeChannels(InputArray image, vector<Mat>& channels)
{
Mat src(image.getMat().rows, image.getMat().cols, CV_32FC3);
image.getMat().convertTo(src, CV_32FC3, 1./255);
Mat_<float> grad;
Mat gray;
Mat luv, gray;
cvtColor(src, gray, CV_RGB2GRAY);
cvtColor(src, luv, CV_RGB2Luv);
Mat_<float> row_der, col_der;
Sobel(gray, row_der, CV_32F, 0, 1);
......@@ -174,7 +221,7 @@ void computeChannels(cv::InputArray image, cv::OutputArrayOfArrays channels_)
magnitude(row_der, col_der, grad);
Mat_<Vec6f> hist(grad.rows, grad.cols);
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) {
......@@ -182,12 +229,22 @@ void computeChannels(cv::InputArray image, cv::OutputArrayOfArrays channels_)
if (angle < 0)
angle += 180;
int ind = (int)(angle / 30);
hist(row, col)[ind] = grad(row, col);
// If angle == 180, prevent index overflow
if (ind == 6)
ind = 5;
hist(row, col)[ind] = grad(row, col) * 255;
}
}
vector<Mat> channels;
channels.push_back(gray);
channels.clear();
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;
......@@ -195,8 +252,6 @@ void computeChannels(cv::InputArray image, cv::OutputArrayOfArrays channels_)
for( size_t i = 0; i < hist_channels.size(); ++i )
channels.push_back(hist_channels[i]);
channels_.setTo(channels);
}
} /* namespace xobjdetect */
......
......@@ -39,6 +39,17 @@ 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;
......@@ -52,64 +63,54 @@ 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,
void ICFDetector::train(const String& pos_path,
const String& bg_path,
ICFDetectorParams params)
{
vector<String> pos_filenames;
glob(pos_path + "/*.png", pos_filenames);
vector<String> bg_filenames;
glob(bg_path + "/*.png", bg_filenames);
model_n_rows_ = params.model_n_rows;
model_n_cols_ = params.model_n_cols;
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);
}
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]);
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 < image_filenames.size(); ++i )
for( size_t i = 0; i < bg_filenames.size(); ++i )
{
Mat img = imread(String(image_filenames[i].c_str()));
for( int j = 0; j < (int)(pos_count / image_filenames.size() + 1); )
cout << setw(6) << (i + 1) << "/" << bg_filenames.size() << "\r";
Mat img = imread(bg_filenames[i]);
for( int j = 0; j < 50;
++j, ++neg_count)
{
Rect r;
r.x = rng.uniform(0, img.cols);
r.width = rng.uniform(r.x + 1, img.cols);
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;
}
sample = img.colRange(r.x, r.width).rowRange(r.y, r.height);
resize(sample, resized_sample, model_size);
samples.push_back(resized_sample.clone());
}
}
cout << "\n";
Mat_<int> labels(1, pos_count + neg_count);
for( int i = 0; i < pos_count; ++i)
......@@ -120,30 +121,131 @@ void ICFDetector::train(const vector<string>& image_filenames,
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;
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);
feature_evaluator->setChannels(channels);
//feature_evaluator->assertChannels();
feature_evaluator->evaluateAll(feature_col);
for( int j = 0; j < feature_col.rows; ++j )
data(i, j) = feature_col(0, j);
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 = 0.001f;
wparams.alpha = 0.02f;
waldboost_ = createWaldBoost(wparams);
vector<int> indices = waldboost_->train(data, labels);
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]]);
}
Ptr<WaldBoost> waldboost = createWaldBoost(wparams);
waldboost->train(data, labels);
void ICFDetector::write(FileStorage& fs) const
{
fs << "{";
fs << "model_n_rows" << model_n_rows_;
fs << "model_n_cols" << model_n_cols_;
fs << "waldboost" << *waldboost_;
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()));
node["model_n_rows"] >> model_n_rows_;
node["model_n_cols"] >> model_n_cols_;
node["waldboost"] >> *waldboost_;
FileNode features = node["features"];
features_.clear();
Point3i 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,
double scaleFactor, Size minSize, Size maxSize, float threshold)
{
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<ACFFeatureEvaluator> evaluator = createACFFeatureEvaluator(features_);
Mat rescaled_image;
int step = 8;
vector<Mat> channels;
for( float scale = scale_from; scale < scale_to + 0.001; scale *= scaleFactor )
{
cout << "scale " << scale << endl;
int new_width = img.cols * scale;
new_width -= new_width % 4;
int new_height = 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 += step)
{
for( int col = 0; col <= rescaled_image.cols - model_n_cols_;
col += step )
{
evaluator->setPosition(Size(row, col));
float value = waldboost_->predict(evaluator);
if( value > threshold )
{
int x = (int)(col / scale);
int y = (int)(row / scale);
int width = (int)(model_n_cols_ / scale);
int height = (int)(model_n_rows_ / scale);
cout << value << " " << x << " " << y << " " << width << " "
<< height << endl;
objects.push_back(Rect(x, y, width, height));
}
}
}
}
}
void write(FileStorage& fs, String&, const ICFDetector& detector)
{
detector.write(fs);
}
bool ICFDetector::save(const string&)
void read(const FileNode& node, ICFDetector& d,
const ICFDetector& default_value)
{
return true;
if( node.empty() )
d = default_value;
else
d.read(node);
}
} /* namespace xobjdetect */
......
......@@ -45,6 +45,8 @@ the use of this software, even if advised of the possibility of such damage.
#include <opencv2/xobjdetect.hpp>
#include <opencv2/xobjdetect/private.hpp>
#include <opencv2/core/utility.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/imgproc/types_c.h>
......
......@@ -65,6 +65,7 @@ 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);
CV_Assert(data.cols > 1);
/* Assert that data and labels have int type */
/* Assert that weights have float type */
......@@ -199,5 +200,19 @@ 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 */
......@@ -45,6 +45,11 @@ using std::swap;
using std::vector;
#include <iostream>
using std::cout;
using std::endl;
namespace cv
{
namespace xobjdetect
......@@ -64,6 +69,10 @@ public:
virtual float predict(
const Ptr<ACFFeatureEvaluator>& feature_evaluator) const;
virtual void write(FileStorage& fs) const;
virtual void read(const FileNode& node);
private:
/* Parameters for cascade training */
WaldBoostParams params_;
......@@ -73,19 +82,97 @@ private:
std::vector<float> thresholds_;
};
vector<int> WaldBoostImpl::train(const Mat& data, const Mat& labels)
static int count(const Mat_<int> &m, int elem)
{
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;
}
void write(FileStorage& fs, String&, const WaldBoost& waldboost)
{
waldboost.write(fs);
}
void read(const FileNode& node, WaldBoost& w,
const WaldBoost& default_value)
{
if( node.empty() )
w = default_value;
else
w.read(node);
}
void WaldBoostImpl::read(const FileNode& node)
{
CV_Assert(labels.rows == 1 && labels.cols == data.cols);
FileNode params = node["waldboost_params"];
params_.weak_count = (int)(params["weak_count"]);
params_.alpha = (float)(params["alpha"]);
int pos_count = 0, neg_count = 0;
for( int col = 0; col < labels.cols; ++col )
FileNode stumps = node["waldboost_stumps"];
stumps_.clear();
for( FileNodeIterator n = stumps.begin(); n != stumps.end(); ++n )
{
if( labels.at<int>(0, col) == +1 )
pos_count += 1;
else
neg_count += 1;
Stump s;
*n >> s;
stumps_.push_back(s);
}
FileNode thresholds = node["waldboost_thresholds"];
thresholds_.clear();
for( FileNodeIterator n = thresholds.begin(); n != thresholds.end(); ++n )
{
float t;
*n >> t;
thresholds_.push_back(t);
}
}
void WaldBoostImpl::write(FileStorage& fs) const
{
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 << "}";
}
vector<int> WaldBoostImpl::train(const Mat& data_, const Mat& labels_)
{
CV_Assert(labels_.rows == 1 && labels_.cols == data_.cols);
CV_Assert(data_.rows >= params_.weak_count);
Mat labels, data;
data_.copyTo(data);
labels_.copyTo(labels);
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;
}
CV_Assert(!null_data);
int pos_count = count(labels, +1);
int neg_count = count(labels, -1);
Mat_<float> weights(labels.rows, labels.cols);
float pos_weight = 1.0f / (2 * pos_count);
float neg_weight = 1.0f / (2 * neg_count);
......@@ -97,6 +184,9 @@ vector<int> WaldBoostImpl::train(const Mat& data, const Mat& labels)
weights.at<float>(0, col) = neg_weight;
}
vector<int> feature_indices_pool;
for( int ind = 0; ind < data.rows; ++ind )
feature_indices_pool.push_back(ind);
vector<int> feature_indices;
Mat_<float> trace = Mat_<float>::zeros(labels.rows, labels.cols);
......@@ -104,10 +194,14 @@ vector<int> WaldBoostImpl::train(const Mat& data, const Mat& labels)
thresholds_.clear();
for( int i = 0; i < params_.weak_count; ++i)
{
cout << "stage " << i << endl;
Stump s;
int feature_ind = s.train(data, labels, weights);
cout << "feature_ind " << feature_ind << endl;
stumps_.push_back(s);
feature_indices.push_back(feature_ind);
int ind = feature_indices_pool[feature_ind];
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 )
......@@ -118,6 +212,14 @@ vector<int> WaldBoostImpl::train(const Mat& data, const Mat& labels)
weights.at<float>(0, col) *= exp(-label * h);
}
// Erase row for feature in data
Mat fixed_data;
fixed_data.push_back(data.rowRange(0, feature_ind));
fixed_data.push_back(data.rowRange(feature_ind + 1, data.rows));
data = fixed_data;
// Normalize weights
float z = (float)sum(weights)[0];
for( int col = 0; col < weights.cols; ++col)
......@@ -125,12 +227,12 @@ vector<int> WaldBoostImpl::train(const Mat& data, const Mat& labels)
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_data = Mat_<int>::zeros(data.rows, data.cols);
Mat new_trace;
for( int col = 0; col < new_weights.cols; ++col )
{
......@@ -138,26 +240,60 @@ vector<int> WaldBoostImpl::train(const Mat& data, const Mat& labels)
weights.at<float>(0, indices.at<int>(0, col));
new_labels.at<int>(0, col) =
labels.at<int>(0, indices.at<int>(0, col));
for( int row = 0; row < new_data.rows; ++row )
{
new_data.at<int>(row, col) =
data.at<int>(row, 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;
pos_i < pos_count * params_.alpha && col < new_labels.cols;
++col )
{
if( labels.at<int>(0, col) == +1 )
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;
}
thresholds_.push_back(new_trace.at<float>(0, col));
thresholds_.push_back(new_trace.at<float>(0, max_col));
cout << "threshold " << *(thresholds_.end() - 1) << endl;
cout << "col " << max_col << " size " << data.cols << endl;
// 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);
new_data.colRange(max_col, new_data.cols).copyTo(data);
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);
pos_count = count(labels, +1);
neg_count = count(labels, -1);
cout << "pos_count " << pos_count << "; neg_count " << neg_count << endl;
if( data.cols < 2 || neg_count == 0)
{
break;
}
}
return feature_indices;
}
......@@ -166,6 +302,7 @@ float WaldBoostImpl::predict(
const Ptr<ACFFeatureEvaluator>& feature_evaluator) const
{
float trace = 0;
CV_Assert(stumps_.size() == thresholds_.size());
for( size_t i = 0; i < stumps_.size(); ++i )
{
int value = feature_evaluator->evaluate(i);
......
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