mirror of
https://github.com/opencv/opencv.git
synced 2026-07-29 15:23:05 +04:00
Merge pull request #25017 from kaingwade:ml_to_contrib
Move ml to opencv_contrib #25017 OpenCV cleanup: #24997 opencv_contrib: opencv/opencv_contrib#3636
This commit is contained in:
@@ -7,7 +7,6 @@ set(OPENCV_CPP_SAMPLES_REQUIRED_DEPS
|
||||
opencv_imgcodecs
|
||||
opencv_videoio
|
||||
opencv_highgui
|
||||
opencv_ml
|
||||
opencv_video
|
||||
opencv_objdetect
|
||||
opencv_photo
|
||||
|
||||
@@ -1,367 +0,0 @@
|
||||
#include "opencv2/core.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include "opencv2/imgcodecs.hpp"
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include "opencv2/ml.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
const int SZ = 20; // size of each digit is SZ x SZ
|
||||
const int CLASS_N = 10;
|
||||
const char* DIGITS_FN = "digits.png";
|
||||
|
||||
static void help(char** argv)
|
||||
{
|
||||
cout <<
|
||||
"\n"
|
||||
"SVM and KNearest digit recognition.\n"
|
||||
"\n"
|
||||
"Sample loads a dataset of handwritten digits from 'digits.png'.\n"
|
||||
"Then it trains a SVM and KNearest classifiers on it and evaluates\n"
|
||||
"their accuracy.\n"
|
||||
"\n"
|
||||
"Following preprocessing is applied to the dataset:\n"
|
||||
" - Moment-based image deskew (see deskew())\n"
|
||||
" - Digit images are split into 4 10x10 cells and 16-bin\n"
|
||||
" histogram of oriented gradients is computed for each\n"
|
||||
" cell\n"
|
||||
" - Transform histograms to space with Hellinger metric (see [1] (RootSIFT))\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"[1] R. Arandjelovic, A. Zisserman\n"
|
||||
" \"Three things everyone should know to improve object retrieval\"\n"
|
||||
" http://www.robots.ox.ac.uk/~vgg/publications/2012/Arandjelovic12/arandjelovic12.pdf\n"
|
||||
"\n"
|
||||
"Usage:\n"
|
||||
<< argv[0] << endl;
|
||||
}
|
||||
|
||||
static void split2d(const Mat& image, const Size cell_size, vector<Mat>& cells)
|
||||
{
|
||||
int height = image.rows;
|
||||
int width = image.cols;
|
||||
|
||||
int sx = cell_size.width;
|
||||
int sy = cell_size.height;
|
||||
|
||||
cells.clear();
|
||||
|
||||
for (int i = 0; i < height; i += sy)
|
||||
{
|
||||
for (int j = 0; j < width; j += sx)
|
||||
{
|
||||
cells.push_back(image(Rect(j, i, sx, sy)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void load_digits(const char* fn, vector<Mat>& digits, vector<int>& labels)
|
||||
{
|
||||
digits.clear();
|
||||
labels.clear();
|
||||
|
||||
String filename = samples::findFile(fn);
|
||||
|
||||
cout << "Loading " << filename << " ..." << endl;
|
||||
|
||||
Mat digits_img = imread(filename, IMREAD_GRAYSCALE);
|
||||
split2d(digits_img, Size(SZ, SZ), digits);
|
||||
|
||||
for (int i = 0; i < CLASS_N; i++)
|
||||
{
|
||||
for (size_t j = 0; j < digits.size() / CLASS_N; j++)
|
||||
{
|
||||
labels.push_back(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void deskew(const Mat& img, Mat& deskewed_img)
|
||||
{
|
||||
Moments m = moments(img);
|
||||
|
||||
if (abs(m.mu02) < 0.01)
|
||||
{
|
||||
deskewed_img = img.clone();
|
||||
return;
|
||||
}
|
||||
|
||||
float skew = (float)(m.mu11 / m.mu02);
|
||||
float M_vals[2][3] = {{1, skew, -0.5f * SZ * skew}, {0, 1, 0}};
|
||||
Mat M(Size(3, 2), CV_32F, &M_vals[0][0]);
|
||||
|
||||
warpAffine(img, deskewed_img, M, Size(SZ, SZ), WARP_INVERSE_MAP | INTER_LINEAR);
|
||||
}
|
||||
|
||||
static void mosaic(const int width, const vector<Mat>& images, Mat& grid)
|
||||
{
|
||||
int mat_width = SZ * width;
|
||||
int mat_height = SZ * (int)ceil((double)images.size() / width);
|
||||
|
||||
if (!images.empty())
|
||||
{
|
||||
grid = Mat(Size(mat_width, mat_height), images[0].type());
|
||||
|
||||
for (size_t i = 0; i < images.size(); i++)
|
||||
{
|
||||
Mat location_on_grid = grid(Rect(SZ * ((int)i % width), SZ * ((int)i / width), SZ, SZ));
|
||||
images[i].copyTo(location_on_grid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void evaluate_model(const vector<float>& predictions, const vector<Mat>& digits, const vector<int>& labels, Mat& mos)
|
||||
{
|
||||
double err = 0;
|
||||
|
||||
for (size_t i = 0; i < predictions.size(); i++)
|
||||
{
|
||||
if ((int)predictions[i] != labels[i])
|
||||
{
|
||||
err++;
|
||||
}
|
||||
}
|
||||
|
||||
err /= predictions.size();
|
||||
|
||||
cout << cv::format("error: %.2f %%", err * 100) << endl;
|
||||
|
||||
int confusion[10][10] = {};
|
||||
|
||||
for (size_t i = 0; i < labels.size(); i++)
|
||||
{
|
||||
confusion[labels[i]][(int)predictions[i]]++;
|
||||
}
|
||||
|
||||
cout << "confusion matrix:" << endl;
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
for (int j = 0; j < 10; j++)
|
||||
{
|
||||
cout << cv::format("%2d ", confusion[i][j]);
|
||||
}
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
cout << endl;
|
||||
|
||||
vector<Mat> vis;
|
||||
|
||||
for (size_t i = 0; i < digits.size(); i++)
|
||||
{
|
||||
Mat img;
|
||||
cvtColor(digits[i], img, COLOR_GRAY2BGR);
|
||||
|
||||
if ((int)predictions[i] != labels[i])
|
||||
{
|
||||
for (int j = 0; j < img.rows; j++)
|
||||
{
|
||||
for (int k = 0; k < img.cols; k++)
|
||||
{
|
||||
img.at<Vec3b>(j, k)[0] = 0;
|
||||
img.at<Vec3b>(j, k)[1] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vis.push_back(img);
|
||||
}
|
||||
|
||||
mosaic(25, vis, mos);
|
||||
}
|
||||
|
||||
static void bincount(const Mat& x, const Mat& weights, const int min_length, vector<double>& bins)
|
||||
{
|
||||
double max_x_val = 0;
|
||||
minMaxLoc(x, NULL, &max_x_val);
|
||||
|
||||
bins = vector<double>(max((int)max_x_val, min_length));
|
||||
|
||||
for (int i = 0; i < x.rows; i++)
|
||||
{
|
||||
for (int j = 0; j < x.cols; j++)
|
||||
{
|
||||
bins[x.at<int>(i, j)] += weights.at<float>(i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void preprocess_hog(const vector<Mat>& digits, Mat& hog)
|
||||
{
|
||||
int bin_n = 16;
|
||||
int half_cell = SZ / 2;
|
||||
double eps = 1e-7;
|
||||
|
||||
hog = Mat(Size(4 * bin_n, (int)digits.size()), CV_32F);
|
||||
|
||||
for (size_t img_index = 0; img_index < digits.size(); img_index++)
|
||||
{
|
||||
Mat gx;
|
||||
Sobel(digits[img_index], gx, CV_32F, 1, 0);
|
||||
|
||||
Mat gy;
|
||||
Sobel(digits[img_index], gy, CV_32F, 0, 1);
|
||||
|
||||
Mat mag;
|
||||
Mat ang;
|
||||
cartToPolar(gx, gy, mag, ang);
|
||||
|
||||
Mat bin(ang.size(), CV_32S);
|
||||
|
||||
for (int i = 0; i < ang.rows; i++)
|
||||
{
|
||||
for (int j = 0; j < ang.cols; j++)
|
||||
{
|
||||
bin.at<int>(i, j) = (int)(bin_n * ang.at<float>(i, j) / (2 * CV_PI));
|
||||
}
|
||||
}
|
||||
|
||||
Mat bin_cells[] = {
|
||||
bin(Rect(0, 0, half_cell, half_cell)),
|
||||
bin(Rect(half_cell, 0, half_cell, half_cell)),
|
||||
bin(Rect(0, half_cell, half_cell, half_cell)),
|
||||
bin(Rect(half_cell, half_cell, half_cell, half_cell))
|
||||
};
|
||||
Mat mag_cells[] = {
|
||||
mag(Rect(0, 0, half_cell, half_cell)),
|
||||
mag(Rect(half_cell, 0, half_cell, half_cell)),
|
||||
mag(Rect(0, half_cell, half_cell, half_cell)),
|
||||
mag(Rect(half_cell, half_cell, half_cell, half_cell))
|
||||
};
|
||||
|
||||
vector<double> hist;
|
||||
hist.reserve(4 * bin_n);
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
vector<double> partial_hist;
|
||||
bincount(bin_cells[i], mag_cells[i], bin_n, partial_hist);
|
||||
hist.insert(hist.end(), partial_hist.begin(), partial_hist.end());
|
||||
}
|
||||
|
||||
// transform to Hellinger kernel
|
||||
double sum = 0;
|
||||
|
||||
for (size_t i = 0; i < hist.size(); i++)
|
||||
{
|
||||
sum += hist[i];
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < hist.size(); i++)
|
||||
{
|
||||
hist[i] /= sum + eps;
|
||||
hist[i] = sqrt(hist[i]);
|
||||
}
|
||||
|
||||
double hist_norm = norm(hist);
|
||||
|
||||
for (size_t i = 0; i < hist.size(); i++)
|
||||
{
|
||||
hog.at<float>((int)img_index, (int)i) = (float)(hist[i] / (hist_norm + eps));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void shuffle(vector<Mat>& digits, vector<int>& labels)
|
||||
{
|
||||
vector<int> shuffled_indexes(digits.size());
|
||||
|
||||
for (size_t i = 0; i < digits.size(); i++)
|
||||
{
|
||||
shuffled_indexes[i] = (int)i;
|
||||
}
|
||||
|
||||
randShuffle(shuffled_indexes);
|
||||
|
||||
vector<Mat> shuffled_digits(digits.size());
|
||||
vector<int> shuffled_labels(labels.size());
|
||||
|
||||
for (size_t i = 0; i < shuffled_indexes.size(); i++)
|
||||
{
|
||||
shuffled_digits[shuffled_indexes[i]] = digits[i];
|
||||
shuffled_labels[shuffled_indexes[i]] = labels[i];
|
||||
}
|
||||
|
||||
digits = shuffled_digits;
|
||||
labels = shuffled_labels;
|
||||
}
|
||||
|
||||
int main(int /* argc */, char* argv[])
|
||||
{
|
||||
help(argv);
|
||||
|
||||
vector<Mat> digits;
|
||||
vector<int> labels;
|
||||
|
||||
load_digits(DIGITS_FN, digits, labels);
|
||||
|
||||
cout << "preprocessing..." << endl;
|
||||
|
||||
// shuffle digits
|
||||
shuffle(digits, labels);
|
||||
|
||||
vector<Mat> digits2;
|
||||
|
||||
for (size_t i = 0; i < digits.size(); i++)
|
||||
{
|
||||
Mat deskewed_digit;
|
||||
deskew(digits[i], deskewed_digit);
|
||||
digits2.push_back(deskewed_digit);
|
||||
}
|
||||
|
||||
Mat samples;
|
||||
|
||||
preprocess_hog(digits2, samples);
|
||||
|
||||
int train_n = (int)(0.9 * samples.rows);
|
||||
Mat test_set;
|
||||
|
||||
vector<Mat> digits_test(digits2.begin() + train_n, digits2.end());
|
||||
mosaic(25, digits_test, test_set);
|
||||
imshow("test set", test_set);
|
||||
|
||||
Mat samples_train = samples(Rect(0, 0, samples.cols, train_n));
|
||||
Mat samples_test = samples(Rect(0, train_n, samples.cols, samples.rows - train_n));
|
||||
vector<int> labels_train(labels.begin(), labels.begin() + train_n);
|
||||
vector<int> labels_test(labels.begin() + train_n, labels.end());
|
||||
|
||||
Ptr<ml::KNearest> k_nearest;
|
||||
Ptr<ml::SVM> svm;
|
||||
vector<float> predictions;
|
||||
Mat vis;
|
||||
|
||||
cout << "training KNearest..." << endl;
|
||||
k_nearest = ml::KNearest::create();
|
||||
k_nearest->train(samples_train, ml::ROW_SAMPLE, labels_train);
|
||||
|
||||
// predict digits with KNearest
|
||||
k_nearest->findNearest(samples_test, 4, predictions);
|
||||
evaluate_model(predictions, digits_test, labels_test, vis);
|
||||
imshow("KNearest test", vis);
|
||||
k_nearest.release();
|
||||
|
||||
cout << "training SVM..." << endl;
|
||||
svm = ml::SVM::create();
|
||||
svm->setGamma(5.383);
|
||||
svm->setC(2.67);
|
||||
svm->setKernel(ml::SVM::RBF);
|
||||
svm->setType(ml::SVM::C_SVC);
|
||||
svm->train(samples_train, ml::ROW_SAMPLE, labels_train);
|
||||
|
||||
// predict digits with SVM
|
||||
svm->predict(samples_test, predictions);
|
||||
evaluate_model(predictions, digits_test, labels_test, vis);
|
||||
imshow("SVM test", vis);
|
||||
cout << "Saving SVM as \"digits_svm.yml\"..." << endl;
|
||||
svm->save("digits_svm.yml");
|
||||
svm.release();
|
||||
|
||||
waitKey();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include "opencv2/ml.hpp"
|
||||
|
||||
using namespace cv;
|
||||
using namespace cv::ml;
|
||||
|
||||
int main( int /*argc*/, char** /*argv*/ )
|
||||
{
|
||||
const int N = 4;
|
||||
const int N1 = (int)sqrt((double)N);
|
||||
const Scalar colors[] =
|
||||
{
|
||||
Scalar(0,0,255), Scalar(0,255,0),
|
||||
Scalar(0,255,255),Scalar(255,255,0)
|
||||
};
|
||||
|
||||
int i, j;
|
||||
int nsamples = 100;
|
||||
Mat samples( nsamples, 2, CV_32FC1 );
|
||||
Mat labels;
|
||||
Mat img = Mat::zeros( Size( 500, 500 ), CV_8UC3 );
|
||||
Mat sample( 1, 2, CV_32FC1 );
|
||||
|
||||
samples = samples.reshape(2, 0);
|
||||
for( i = 0; i < N; i++ )
|
||||
{
|
||||
// form the training samples
|
||||
Mat samples_part = samples.rowRange(i*nsamples/N, (i+1)*nsamples/N );
|
||||
|
||||
Scalar mean(((i%N1)+1)*img.rows/(N1+1),
|
||||
((i/N1)+1)*img.rows/(N1+1));
|
||||
Scalar sigma(30,30);
|
||||
randn( samples_part, mean, sigma );
|
||||
}
|
||||
samples = samples.reshape(1, 0);
|
||||
|
||||
// cluster the data
|
||||
Ptr<EM> em_model = EM::create();
|
||||
em_model->setClustersNumber(N);
|
||||
em_model->setCovarianceMatrixType(EM::COV_MAT_SPHERICAL);
|
||||
em_model->setTermCriteria(TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 300, 0.1));
|
||||
em_model->trainEM( samples, noArray(), labels, noArray() );
|
||||
|
||||
// classify every image pixel
|
||||
for( i = 0; i < img.rows; i++ )
|
||||
{
|
||||
for( j = 0; j < img.cols; j++ )
|
||||
{
|
||||
sample.at<float>(0) = (float)j;
|
||||
sample.at<float>(1) = (float)i;
|
||||
int response = cvRound(em_model->predict2( sample, noArray() )[1]);
|
||||
Scalar c = colors[response];
|
||||
|
||||
circle( img, Point(j, i), 1, c*0.75, FILLED );
|
||||
}
|
||||
}
|
||||
|
||||
//draw the clustered samples
|
||||
for( i = 0; i < nsamples; i++ )
|
||||
{
|
||||
Point pt(cvRound(samples.at<float>(i, 0)), cvRound(samples.at<float>(i, 1)));
|
||||
circle( img, pt, 1, colors[labels.at<int>(i)], FILLED );
|
||||
}
|
||||
|
||||
imshow( "EM-clustering result", img );
|
||||
waitKey(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,558 +0,0 @@
|
||||
#include "opencv2/core.hpp"
|
||||
#include "opencv2/ml.hpp"
|
||||
|
||||
#include <cstdio>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
using namespace cv::ml;
|
||||
|
||||
static void help(char** argv)
|
||||
{
|
||||
printf("\nThe sample demonstrates how to train Random Trees classifier\n"
|
||||
"(or Boosting classifier, or MLP, or Knearest, or Nbayes, or Support Vector Machines - see main()) using the provided dataset.\n"
|
||||
"\n"
|
||||
"We use the sample database letter-recognition.data\n"
|
||||
"from UCI Repository, here is the link:\n"
|
||||
"\n"
|
||||
"Newman, D.J. & Hettich, S. & Blake, C.L. & Merz, C.J. (1998).\n"
|
||||
"UCI Repository of machine learning databases\n"
|
||||
"[http://www.ics.uci.edu/~mlearn/MLRepository.html].\n"
|
||||
"Irvine, CA: University of California, Department of Information and Computer Science.\n"
|
||||
"\n"
|
||||
"The dataset consists of 20000 feature vectors along with the\n"
|
||||
"responses - capital latin letters A..Z.\n"
|
||||
"The first 16000 (10000 for boosting)) samples are used for training\n"
|
||||
"and the remaining 4000 (10000 for boosting) - to test the classifier.\n"
|
||||
"======================================================\n");
|
||||
printf("\nThis is letter recognition sample.\n"
|
||||
"The usage: %s [-data=<path to letter-recognition.data>] \\\n"
|
||||
" [-save=<output XML file for the classifier>] \\\n"
|
||||
" [-load=<XML file with the pre-trained classifier>] \\\n"
|
||||
" [-boost|-mlp|-knearest|-nbayes|-svm] # to use boost/mlp/knearest/SVM classifier instead of default Random Trees\n", argv[0] );
|
||||
}
|
||||
|
||||
// This function reads data and responses from the file <filename>
|
||||
static bool
|
||||
read_num_class_data( const string& filename, int var_count,
|
||||
Mat* _data, Mat* _responses )
|
||||
{
|
||||
const int M = 1024;
|
||||
char buf[M+2];
|
||||
|
||||
Mat el_ptr(1, var_count, CV_32F);
|
||||
int i;
|
||||
vector<int> responses;
|
||||
|
||||
_data->release();
|
||||
_responses->release();
|
||||
|
||||
FILE* f = fopen( filename.c_str(), "rt" );
|
||||
if( !f )
|
||||
{
|
||||
cout << "Could not read the database " << filename << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
for(;;)
|
||||
{
|
||||
char* ptr;
|
||||
if( !fgets( buf, M, f ) || !strchr( buf, ',' ) )
|
||||
break;
|
||||
responses.push_back((int)buf[0]);
|
||||
ptr = buf+2;
|
||||
for( i = 0; i < var_count; i++ )
|
||||
{
|
||||
int n = 0;
|
||||
sscanf( ptr, "%f%n", &el_ptr.at<float>(i), &n );
|
||||
ptr += n + 1;
|
||||
}
|
||||
if( i < var_count )
|
||||
break;
|
||||
_data->push_back(el_ptr);
|
||||
}
|
||||
fclose(f);
|
||||
Mat(responses).copyTo(*_responses);
|
||||
|
||||
cout << "The database " << filename << " is loaded.\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static Ptr<T> load_classifier(const string& filename_to_load)
|
||||
{
|
||||
// load classifier from the specified file
|
||||
Ptr<T> model = StatModel::load<T>( filename_to_load );
|
||||
if( model.empty() )
|
||||
cout << "Could not read the classifier " << filename_to_load << endl;
|
||||
else
|
||||
cout << "The classifier " << filename_to_load << " is loaded.\n";
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
static Ptr<TrainData>
|
||||
prepare_train_data(const Mat& data, const Mat& responses, int ntrain_samples)
|
||||
{
|
||||
Mat sample_idx = Mat::zeros( 1, data.rows, CV_8U );
|
||||
Mat train_samples = sample_idx.colRange(0, ntrain_samples);
|
||||
train_samples.setTo(Scalar::all(1));
|
||||
|
||||
int nvars = data.cols;
|
||||
Mat var_type( nvars + 1, 1, CV_8U );
|
||||
var_type.setTo(Scalar::all(VAR_ORDERED));
|
||||
var_type.at<uchar>(nvars) = VAR_CATEGORICAL;
|
||||
|
||||
return TrainData::create(data, ROW_SAMPLE, responses,
|
||||
noArray(), sample_idx, noArray(), var_type);
|
||||
}
|
||||
|
||||
inline TermCriteria TC(int iters, double eps)
|
||||
{
|
||||
return TermCriteria(TermCriteria::MAX_ITER + (eps > 0 ? TermCriteria::EPS : 0), iters, eps);
|
||||
}
|
||||
|
||||
static void test_and_save_classifier(const Ptr<StatModel>& model,
|
||||
const Mat& data, const Mat& responses,
|
||||
int ntrain_samples, int rdelta,
|
||||
const string& filename_to_save)
|
||||
{
|
||||
int i, nsamples_all = data.rows;
|
||||
double train_hr = 0, test_hr = 0;
|
||||
|
||||
// compute prediction error on train and test data
|
||||
for( i = 0; i < nsamples_all; i++ )
|
||||
{
|
||||
Mat sample = data.row(i);
|
||||
|
||||
float r = model->predict( sample );
|
||||
r = std::abs(r + rdelta - responses.at<int>(i)) <= FLT_EPSILON ? 1.f : 0.f;
|
||||
|
||||
if( i < ntrain_samples )
|
||||
train_hr += r;
|
||||
else
|
||||
test_hr += r;
|
||||
}
|
||||
|
||||
test_hr /= nsamples_all - ntrain_samples;
|
||||
train_hr = ntrain_samples > 0 ? train_hr/ntrain_samples : 1.;
|
||||
|
||||
printf( "Recognition rate: train = %.1f%%, test = %.1f%%\n",
|
||||
train_hr*100., test_hr*100. );
|
||||
|
||||
if( !filename_to_save.empty() )
|
||||
{
|
||||
model->save( filename_to_save );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
build_rtrees_classifier( const string& data_filename,
|
||||
const string& filename_to_save,
|
||||
const string& filename_to_load )
|
||||
{
|
||||
Mat data;
|
||||
Mat responses;
|
||||
bool ok = read_num_class_data( data_filename, 16, &data, &responses );
|
||||
if( !ok )
|
||||
return ok;
|
||||
|
||||
Ptr<RTrees> model;
|
||||
|
||||
int nsamples_all = data.rows;
|
||||
int ntrain_samples = (int)(nsamples_all*0.8);
|
||||
|
||||
// Create or load Random Trees classifier
|
||||
if( !filename_to_load.empty() )
|
||||
{
|
||||
model = load_classifier<RTrees>(filename_to_load);
|
||||
if( model.empty() )
|
||||
return false;
|
||||
ntrain_samples = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// create classifier by using <data> and <responses>
|
||||
cout << "Training the classifier ...\n";
|
||||
// Params( int maxDepth, int minSampleCount,
|
||||
// double regressionAccuracy, bool useSurrogates,
|
||||
// int maxCategories, const Mat& priors,
|
||||
// bool calcVarImportance, int nactiveVars,
|
||||
// TermCriteria termCrit );
|
||||
Ptr<TrainData> tdata = prepare_train_data(data, responses, ntrain_samples);
|
||||
model = RTrees::create();
|
||||
model->setMaxDepth(10);
|
||||
model->setMinSampleCount(10);
|
||||
model->setRegressionAccuracy(0);
|
||||
model->setUseSurrogates(false);
|
||||
model->setMaxCategories(15);
|
||||
model->setPriors(Mat());
|
||||
model->setCalculateVarImportance(true);
|
||||
model->setActiveVarCount(4);
|
||||
model->setTermCriteria(TC(100,0.01f));
|
||||
model->train(tdata);
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
test_and_save_classifier(model, data, responses, ntrain_samples, 0, filename_to_save);
|
||||
cout << "Number of trees: " << model->getRoots().size() << endl;
|
||||
|
||||
// Print variable importance
|
||||
Mat var_importance = model->getVarImportance();
|
||||
if( !var_importance.empty() )
|
||||
{
|
||||
double rt_imp_sum = sum( var_importance )[0];
|
||||
printf("var#\timportance (in %%):\n");
|
||||
int i, n = (int)var_importance.total();
|
||||
for( i = 0; i < n; i++ )
|
||||
printf( "%-2d\t%-4.1f\n", i, 100.f*var_importance.at<float>(i)/rt_imp_sum);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
build_boost_classifier( const string& data_filename,
|
||||
const string& filename_to_save,
|
||||
const string& filename_to_load )
|
||||
{
|
||||
const int class_count = 26;
|
||||
Mat data;
|
||||
Mat responses;
|
||||
Mat weak_responses;
|
||||
|
||||
bool ok = read_num_class_data( data_filename, 16, &data, &responses );
|
||||
if( !ok )
|
||||
return ok;
|
||||
|
||||
int i, j, k;
|
||||
Ptr<Boost> model;
|
||||
|
||||
int nsamples_all = data.rows;
|
||||
int ntrain_samples = (int)(nsamples_all*0.5);
|
||||
int var_count = data.cols;
|
||||
|
||||
// Create or load Boosted Tree classifier
|
||||
if( !filename_to_load.empty() )
|
||||
{
|
||||
model = load_classifier<Boost>(filename_to_load);
|
||||
if( model.empty() )
|
||||
return false;
|
||||
ntrain_samples = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
//
|
||||
// As currently boosted tree classifier in MLL can only be trained
|
||||
// for 2-class problems, we transform the training database by
|
||||
// "unrolling" each training sample as many times as the number of
|
||||
// classes (26) that we have.
|
||||
//
|
||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
Mat new_data( ntrain_samples*class_count, var_count + 1, CV_32F );
|
||||
Mat new_responses( ntrain_samples*class_count, 1, CV_32S );
|
||||
|
||||
// 1. unroll the database type mask
|
||||
printf( "Unrolling the database...\n");
|
||||
for( i = 0; i < ntrain_samples; i++ )
|
||||
{
|
||||
const float* data_row = data.ptr<float>(i);
|
||||
for( j = 0; j < class_count; j++ )
|
||||
{
|
||||
float* new_data_row = (float*)new_data.ptr<float>(i*class_count+j);
|
||||
memcpy(new_data_row, data_row, var_count*sizeof(data_row[0]));
|
||||
new_data_row[var_count] = (float)j;
|
||||
new_responses.at<int>(i*class_count + j) = responses.at<int>(i) == j+'A';
|
||||
}
|
||||
}
|
||||
|
||||
Mat var_type( 1, var_count + 2, CV_8U );
|
||||
var_type.setTo(Scalar::all(VAR_ORDERED));
|
||||
var_type.at<uchar>(var_count) = var_type.at<uchar>(var_count+1) = VAR_CATEGORICAL;
|
||||
|
||||
Ptr<TrainData> tdata = TrainData::create(new_data, ROW_SAMPLE, new_responses,
|
||||
noArray(), noArray(), noArray(), var_type);
|
||||
vector<double> priors(2);
|
||||
priors[0] = 1;
|
||||
priors[1] = 26;
|
||||
|
||||
cout << "Training the classifier (may take a few minutes)...\n";
|
||||
model = Boost::create();
|
||||
model->setBoostType(Boost::GENTLE);
|
||||
model->setWeakCount(100);
|
||||
model->setWeightTrimRate(0.95);
|
||||
model->setMaxDepth(5);
|
||||
model->setUseSurrogates(false);
|
||||
model->setPriors(Mat(priors));
|
||||
model->train(tdata);
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
Mat temp_sample( 1, var_count + 1, CV_32F );
|
||||
float* tptr = temp_sample.ptr<float>();
|
||||
|
||||
// compute prediction error on train and test data
|
||||
double train_hr = 0, test_hr = 0;
|
||||
for( i = 0; i < nsamples_all; i++ )
|
||||
{
|
||||
int best_class = 0;
|
||||
double max_sum = -DBL_MAX;
|
||||
const float* ptr = data.ptr<float>(i);
|
||||
for( k = 0; k < var_count; k++ )
|
||||
tptr[k] = ptr[k];
|
||||
|
||||
for( j = 0; j < class_count; j++ )
|
||||
{
|
||||
tptr[var_count] = (float)j;
|
||||
float s = model->predict( temp_sample, noArray(), StatModel::RAW_OUTPUT );
|
||||
if( max_sum < s )
|
||||
{
|
||||
max_sum = s;
|
||||
best_class = j + 'A';
|
||||
}
|
||||
}
|
||||
|
||||
double r = std::abs(best_class - responses.at<int>(i)) < FLT_EPSILON ? 1 : 0;
|
||||
if( i < ntrain_samples )
|
||||
train_hr += r;
|
||||
else
|
||||
test_hr += r;
|
||||
}
|
||||
|
||||
test_hr /= nsamples_all-ntrain_samples;
|
||||
train_hr = ntrain_samples > 0 ? train_hr/ntrain_samples : 1.;
|
||||
printf( "Recognition rate: train = %.1f%%, test = %.1f%%\n",
|
||||
train_hr*100., test_hr*100. );
|
||||
|
||||
cout << "Number of trees: " << model->getRoots().size() << endl;
|
||||
|
||||
// Save classifier to file if needed
|
||||
if( !filename_to_save.empty() )
|
||||
model->save( filename_to_save );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
build_mlp_classifier( const string& data_filename,
|
||||
const string& filename_to_save,
|
||||
const string& filename_to_load )
|
||||
{
|
||||
const int class_count = 26;
|
||||
Mat data;
|
||||
Mat responses;
|
||||
|
||||
bool ok = read_num_class_data( data_filename, 16, &data, &responses );
|
||||
if( !ok )
|
||||
return ok;
|
||||
|
||||
Ptr<ANN_MLP> model;
|
||||
|
||||
int nsamples_all = data.rows;
|
||||
int ntrain_samples = (int)(nsamples_all*0.8);
|
||||
|
||||
// Create or load MLP classifier
|
||||
if( !filename_to_load.empty() )
|
||||
{
|
||||
model = load_classifier<ANN_MLP>(filename_to_load);
|
||||
if( model.empty() )
|
||||
return false;
|
||||
ntrain_samples = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
//
|
||||
// MLP does not support categorical variables by explicitly.
|
||||
// So, instead of the output class label, we will use
|
||||
// a binary vector of <class_count> components for training and,
|
||||
// therefore, MLP will give us a vector of "probabilities" at the
|
||||
// prediction stage
|
||||
//
|
||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
Mat train_data = data.rowRange(0, ntrain_samples);
|
||||
Mat train_responses = Mat::zeros( ntrain_samples, class_count, CV_32F );
|
||||
|
||||
// 1. unroll the responses
|
||||
cout << "Unrolling the responses...\n";
|
||||
for( int i = 0; i < ntrain_samples; i++ )
|
||||
{
|
||||
int cls_label = responses.at<int>(i) - 'A';
|
||||
train_responses.at<float>(i, cls_label) = 1.f;
|
||||
}
|
||||
|
||||
// 2. train classifier
|
||||
int layer_sz[] = { data.cols, 100, 100, class_count };
|
||||
int nlayers = (int)(sizeof(layer_sz)/sizeof(layer_sz[0]));
|
||||
Mat layer_sizes( 1, nlayers, CV_32S, layer_sz );
|
||||
|
||||
#if 1
|
||||
int method = ANN_MLP::BACKPROP;
|
||||
double method_param = 0.001;
|
||||
int max_iter = 300;
|
||||
#else
|
||||
int method = ANN_MLP::RPROP;
|
||||
double method_param = 0.1;
|
||||
int max_iter = 1000;
|
||||
#endif
|
||||
|
||||
Ptr<TrainData> tdata = TrainData::create(train_data, ROW_SAMPLE, train_responses);
|
||||
|
||||
cout << "Training the classifier (may take a few minutes)...\n";
|
||||
model = ANN_MLP::create();
|
||||
model->setLayerSizes(layer_sizes);
|
||||
model->setActivationFunction(ANN_MLP::SIGMOID_SYM, 0, 0);
|
||||
model->setTermCriteria(TC(max_iter,0));
|
||||
model->setTrainMethod(method, method_param);
|
||||
model->train(tdata);
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
test_and_save_classifier(model, data, responses, ntrain_samples, 'A', filename_to_save);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
build_knearest_classifier( const string& data_filename, int K )
|
||||
{
|
||||
Mat data;
|
||||
Mat responses;
|
||||
bool ok = read_num_class_data( data_filename, 16, &data, &responses );
|
||||
if( !ok )
|
||||
return ok;
|
||||
|
||||
|
||||
int nsamples_all = data.rows;
|
||||
int ntrain_samples = (int)(nsamples_all*0.8);
|
||||
|
||||
// create classifier by using <data> and <responses>
|
||||
cout << "Training the classifier ...\n";
|
||||
Ptr<TrainData> tdata = prepare_train_data(data, responses, ntrain_samples);
|
||||
Ptr<KNearest> model = KNearest::create();
|
||||
model->setDefaultK(K);
|
||||
model->setIsClassifier(true);
|
||||
model->train(tdata);
|
||||
cout << endl;
|
||||
|
||||
test_and_save_classifier(model, data, responses, ntrain_samples, 0, string());
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
build_nbayes_classifier( const string& data_filename )
|
||||
{
|
||||
Mat data;
|
||||
Mat responses;
|
||||
bool ok = read_num_class_data( data_filename, 16, &data, &responses );
|
||||
if( !ok )
|
||||
return ok;
|
||||
|
||||
Ptr<NormalBayesClassifier> model;
|
||||
|
||||
int nsamples_all = data.rows;
|
||||
int ntrain_samples = (int)(nsamples_all*0.8);
|
||||
|
||||
// create classifier by using <data> and <responses>
|
||||
cout << "Training the classifier ...\n";
|
||||
Ptr<TrainData> tdata = prepare_train_data(data, responses, ntrain_samples);
|
||||
model = NormalBayesClassifier::create();
|
||||
model->train(tdata);
|
||||
cout << endl;
|
||||
|
||||
test_and_save_classifier(model, data, responses, ntrain_samples, 0, string());
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
build_svm_classifier( const string& data_filename,
|
||||
const string& filename_to_save,
|
||||
const string& filename_to_load )
|
||||
{
|
||||
Mat data;
|
||||
Mat responses;
|
||||
bool ok = read_num_class_data( data_filename, 16, &data, &responses );
|
||||
if( !ok )
|
||||
return ok;
|
||||
|
||||
Ptr<SVM> model;
|
||||
|
||||
int nsamples_all = data.rows;
|
||||
int ntrain_samples = (int)(nsamples_all*0.8);
|
||||
|
||||
// Create or load Random Trees classifier
|
||||
if( !filename_to_load.empty() )
|
||||
{
|
||||
model = load_classifier<SVM>(filename_to_load);
|
||||
if( model.empty() )
|
||||
return false;
|
||||
ntrain_samples = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// create classifier by using <data> and <responses>
|
||||
cout << "Training the classifier ...\n";
|
||||
Ptr<TrainData> tdata = prepare_train_data(data, responses, ntrain_samples);
|
||||
model = SVM::create();
|
||||
model->setType(SVM::C_SVC);
|
||||
model->setKernel(SVM::LINEAR);
|
||||
model->setC(1);
|
||||
model->train(tdata);
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
test_and_save_classifier(model, data, responses, ntrain_samples, 0, filename_to_save);
|
||||
return true;
|
||||
}
|
||||
|
||||
int main( int argc, char *argv[] )
|
||||
{
|
||||
string filename_to_save = "";
|
||||
string filename_to_load = "";
|
||||
string data_filename;
|
||||
int method = 0;
|
||||
|
||||
cv::CommandLineParser parser(argc, argv, "{data|letter-recognition.data|}{save||}{load||}{boost||}"
|
||||
"{mlp||}{knn knearest||}{nbayes||}{svm||}");
|
||||
data_filename = samples::findFile(parser.get<string>("data"));
|
||||
if (parser.has("save"))
|
||||
filename_to_save = parser.get<string>("save");
|
||||
if (parser.has("load"))
|
||||
filename_to_load = samples::findFile(parser.get<string>("load"));
|
||||
if (parser.has("boost"))
|
||||
method = 1;
|
||||
else if (parser.has("mlp"))
|
||||
method = 2;
|
||||
else if (parser.has("knearest"))
|
||||
method = 3;
|
||||
else if (parser.has("nbayes"))
|
||||
method = 4;
|
||||
else if (parser.has("svm"))
|
||||
method = 5;
|
||||
|
||||
help(argv);
|
||||
|
||||
if( (method == 0 ?
|
||||
build_rtrees_classifier( data_filename, filename_to_save, filename_to_load ) :
|
||||
method == 1 ?
|
||||
build_boost_classifier( data_filename, filename_to_save, filename_to_load ) :
|
||||
method == 2 ?
|
||||
build_mlp_classifier( data_filename, filename_to_save, filename_to_load ) :
|
||||
method == 3 ?
|
||||
build_knearest_classifier( data_filename, 10 ) :
|
||||
method == 4 ?
|
||||
build_nbayes_classifier( data_filename) :
|
||||
method == 5 ?
|
||||
build_svm_classifier( data_filename, filename_to_save, filename_to_load ):
|
||||
-1) < 0)
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
// Logistic Regression sample
|
||||
// AUTHOR: Rahul Kavi rahulkavi[at]live[at]com
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <opencv2/core.hpp>
|
||||
#include <opencv2/ml.hpp>
|
||||
#include <opencv2/highgui.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
using namespace cv::ml;
|
||||
|
||||
static void showImage(const Mat &data, int columns, const String &name)
|
||||
{
|
||||
Mat bigImage;
|
||||
for(int i = 0; i < data.rows; ++i)
|
||||
{
|
||||
bigImage.push_back(data.row(i).reshape(0, columns));
|
||||
}
|
||||
imshow(name, bigImage.t());
|
||||
}
|
||||
|
||||
static float calculateAccuracyPercent(const Mat &original, const Mat &predicted)
|
||||
{
|
||||
return 100 * (float)countNonZero(original == predicted) / predicted.rows;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
const String filename = samples::findFile("data01.xml");
|
||||
cout << "**********************************************************************" << endl;
|
||||
cout << filename
|
||||
<< " contains digits 0 and 1 of 20 samples each, collected on an Android device" << endl;
|
||||
cout << "Each of the collected images are of size 28 x 28 re-arranged to 1 x 784 matrix"
|
||||
<< endl;
|
||||
cout << "**********************************************************************" << endl;
|
||||
|
||||
Mat data, labels;
|
||||
{
|
||||
cout << "loading the dataset...";
|
||||
FileStorage f;
|
||||
if(f.open(filename, FileStorage::READ))
|
||||
{
|
||||
f["datamat"] >> data;
|
||||
f["labelsmat"] >> labels;
|
||||
f.release();
|
||||
}
|
||||
else
|
||||
{
|
||||
cerr << "file can not be opened: " << filename << endl;
|
||||
return 1;
|
||||
}
|
||||
data.convertTo(data, CV_32F);
|
||||
labels.convertTo(labels, CV_32F);
|
||||
cout << "read " << data.rows << " rows of data" << endl;
|
||||
}
|
||||
|
||||
Mat data_train, data_test;
|
||||
Mat labels_train, labels_test;
|
||||
for(int i = 0; i < data.rows; i++)
|
||||
{
|
||||
if(i % 2 == 0)
|
||||
{
|
||||
data_train.push_back(data.row(i));
|
||||
labels_train.push_back(labels.row(i));
|
||||
}
|
||||
else
|
||||
{
|
||||
data_test.push_back(data.row(i));
|
||||
labels_test.push_back(labels.row(i));
|
||||
}
|
||||
}
|
||||
cout << "training/testing samples count: " << data_train.rows << "/" << data_test.rows << endl;
|
||||
|
||||
// display sample image
|
||||
showImage(data_train, 28, "train data");
|
||||
showImage(data_test, 28, "test data");
|
||||
|
||||
// simple case with batch gradient
|
||||
cout << "training...";
|
||||
//! [init]
|
||||
Ptr<LogisticRegression> lr1 = LogisticRegression::create();
|
||||
lr1->setLearningRate(0.001);
|
||||
lr1->setIterations(10);
|
||||
lr1->setRegularization(LogisticRegression::REG_L2);
|
||||
lr1->setTrainMethod(LogisticRegression::BATCH);
|
||||
lr1->setMiniBatchSize(1);
|
||||
//! [init]
|
||||
lr1->train(data_train, ROW_SAMPLE, labels_train);
|
||||
cout << "done!" << endl;
|
||||
|
||||
cout << "predicting...";
|
||||
Mat responses;
|
||||
lr1->predict(data_test, responses);
|
||||
cout << "done!" << endl;
|
||||
|
||||
// show prediction report
|
||||
cout << "original vs predicted:" << endl;
|
||||
labels_test.convertTo(labels_test, CV_32S);
|
||||
cout << labels_test.t() << endl;
|
||||
cout << responses.t() << endl;
|
||||
cout << "accuracy: " << calculateAccuracyPercent(labels_test, responses) << "%" << endl;
|
||||
|
||||
// save the classifier
|
||||
const String saveFilename = "NewLR_Trained.xml";
|
||||
cout << "saving the classifier to " << saveFilename << endl;
|
||||
lr1->save(saveFilename);
|
||||
|
||||
// load the classifier onto new object
|
||||
cout << "loading a new classifier from " << saveFilename << endl;
|
||||
Ptr<LogisticRegression> lr2 = StatModel::load<LogisticRegression>(saveFilename);
|
||||
|
||||
// predict using loaded classifier
|
||||
cout << "predicting the dataset using the loaded classifier...";
|
||||
Mat responses2;
|
||||
lr2->predict(data_test, responses2);
|
||||
cout << "done!" << endl;
|
||||
|
||||
// calculate accuracy
|
||||
cout << labels_test.t() << endl;
|
||||
cout << responses2.t() << endl;
|
||||
cout << "accuracy: " << calculateAccuracyPercent(labels_test, responses2) << "%" << endl;
|
||||
|
||||
waitKey(0);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
#include <opencv2/ml/ml.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
using namespace cv::ml;
|
||||
|
||||
int main()
|
||||
{
|
||||
//create random training data
|
||||
Mat_<float> data(100, 100);
|
||||
randn(data, Mat::zeros(1, 1, data.type()), Mat::ones(1, 1, data.type()));
|
||||
|
||||
//half of the samples for each class
|
||||
Mat_<float> responses(data.rows, 2);
|
||||
for (int i = 0; i<data.rows; ++i)
|
||||
{
|
||||
if (i < data.rows/2)
|
||||
{
|
||||
responses(i, 0) = 1;
|
||||
responses(i, 1) = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
responses(i, 0) = 0;
|
||||
responses(i, 1) = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
//example code for just a single response (regression)
|
||||
Mat_<float> responses(data.rows, 1);
|
||||
for (int i=0; i<responses.rows; ++i)
|
||||
responses(i, 0) = i < responses.rows / 2 ? 0 : 1;
|
||||
*/
|
||||
|
||||
//create the neural network
|
||||
Mat_<int> layerSizes(1, 3);
|
||||
layerSizes(0, 0) = data.cols;
|
||||
layerSizes(0, 1) = 20;
|
||||
layerSizes(0, 2) = responses.cols;
|
||||
|
||||
Ptr<ANN_MLP> network = ANN_MLP::create();
|
||||
network->setLayerSizes(layerSizes);
|
||||
network->setActivationFunction(ANN_MLP::SIGMOID_SYM, 0.1, 0.1);
|
||||
network->setTrainMethod(ANN_MLP::BACKPROP, 0.1, 0.1);
|
||||
Ptr<TrainData> trainData = TrainData::create(data, ROW_SAMPLE, responses);
|
||||
|
||||
network->train(trainData);
|
||||
if (network->isTrained())
|
||||
{
|
||||
printf("Predict one-vector:\n");
|
||||
Mat result;
|
||||
network->predict(Mat::ones(1, data.cols, data.type()), result);
|
||||
cout << result << endl;
|
||||
|
||||
printf("Predict training data:\n");
|
||||
for (int i=0; i<data.rows; ++i)
|
||||
{
|
||||
network->predict(data.row(i), result);
|
||||
cout << result << endl;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,399 +0,0 @@
|
||||
#include "opencv2/core.hpp"
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include "opencv2/ml.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
using namespace cv::ml;
|
||||
|
||||
const Scalar WHITE_COLOR = Scalar(255,255,255);
|
||||
const string winName = "points";
|
||||
const int testStep = 5;
|
||||
|
||||
Mat img, imgDst;
|
||||
RNG rng;
|
||||
|
||||
vector<Point> trainedPoints;
|
||||
vector<int> trainedPointsMarkers;
|
||||
const int MAX_CLASSES = 2;
|
||||
vector<Vec3b> classColors(MAX_CLASSES);
|
||||
int currentClass = 0;
|
||||
vector<int> classCounters(MAX_CLASSES);
|
||||
|
||||
#define _NBC_ 1 // normal Bayessian classifier
|
||||
#define _KNN_ 1 // k nearest neighbors classifier
|
||||
#define _SVM_ 1 // support vectors machine
|
||||
#define _DT_ 1 // decision tree
|
||||
#define _BT_ 1 // ADA Boost
|
||||
#define _GBT_ 0 // gradient boosted trees
|
||||
#define _RF_ 1 // random forest
|
||||
#define _ANN_ 1 // artificial neural networks
|
||||
#define _EM_ 1 // expectation-maximization
|
||||
|
||||
static void on_mouse( int event, int x, int y, int /*flags*/, void* )
|
||||
{
|
||||
if( img.empty() )
|
||||
return;
|
||||
|
||||
int updateFlag = 0;
|
||||
|
||||
if( event == EVENT_LBUTTONUP )
|
||||
{
|
||||
trainedPoints.push_back( Point(x,y) );
|
||||
trainedPointsMarkers.push_back( currentClass );
|
||||
classCounters[currentClass]++;
|
||||
updateFlag = true;
|
||||
}
|
||||
|
||||
//draw
|
||||
if( updateFlag )
|
||||
{
|
||||
img = Scalar::all(0);
|
||||
|
||||
// draw points
|
||||
for( size_t i = 0; i < trainedPoints.size(); i++ )
|
||||
{
|
||||
Vec3b c = classColors[trainedPointsMarkers[i]];
|
||||
circle( img, trainedPoints[i], 5, Scalar(c), -1 );
|
||||
}
|
||||
|
||||
imshow( winName, img );
|
||||
}
|
||||
}
|
||||
|
||||
static Mat prepare_train_samples(const vector<Point>& pts)
|
||||
{
|
||||
Mat samples;
|
||||
Mat(pts).reshape(1, (int)pts.size()).convertTo(samples, CV_32F);
|
||||
return samples;
|
||||
}
|
||||
|
||||
static Ptr<TrainData> prepare_train_data()
|
||||
{
|
||||
Mat samples = prepare_train_samples(trainedPoints);
|
||||
return TrainData::create(samples, ROW_SAMPLE, Mat(trainedPointsMarkers));
|
||||
}
|
||||
|
||||
static void predict_and_paint(const Ptr<StatModel>& model, Mat& dst)
|
||||
{
|
||||
Mat testSample( 1, 2, CV_32FC1 );
|
||||
for( int y = 0; y < img.rows; y += testStep )
|
||||
{
|
||||
for( int x = 0; x < img.cols; x += testStep )
|
||||
{
|
||||
testSample.at<float>(0) = (float)x;
|
||||
testSample.at<float>(1) = (float)y;
|
||||
|
||||
int response = (int)model->predict( testSample );
|
||||
dst.at<Vec3b>(y, x) = classColors[response];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if _NBC_
|
||||
static void find_decision_boundary_NBC()
|
||||
{
|
||||
// learn classifier
|
||||
Ptr<NormalBayesClassifier> normalBayesClassifier = StatModel::train<NormalBayesClassifier>(prepare_train_data());
|
||||
|
||||
predict_and_paint(normalBayesClassifier, imgDst);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if _KNN_
|
||||
static void find_decision_boundary_KNN( int K )
|
||||
{
|
||||
|
||||
Ptr<KNearest> knn = KNearest::create();
|
||||
knn->setDefaultK(K);
|
||||
knn->setIsClassifier(true);
|
||||
knn->train(prepare_train_data());
|
||||
predict_and_paint(knn, imgDst);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if _SVM_
|
||||
static void find_decision_boundary_SVM( double C )
|
||||
{
|
||||
Ptr<SVM> svm = SVM::create();
|
||||
svm->setType(SVM::C_SVC);
|
||||
svm->setKernel(SVM::POLY); //SVM::LINEAR;
|
||||
svm->setDegree(0.5);
|
||||
svm->setGamma(1);
|
||||
svm->setCoef0(1);
|
||||
svm->setNu(0.5);
|
||||
svm->setP(0);
|
||||
svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS, 1000, 0.01));
|
||||
svm->setC(C);
|
||||
svm->train(prepare_train_data());
|
||||
predict_and_paint(svm, imgDst);
|
||||
|
||||
Mat sv = svm->getSupportVectors();
|
||||
for( int i = 0; i < sv.rows; i++ )
|
||||
{
|
||||
const float* supportVector = sv.ptr<float>(i);
|
||||
circle( imgDst, Point(saturate_cast<int>(supportVector[0]),saturate_cast<int>(supportVector[1])), 5, Scalar(255,255,255), -1 );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if _DT_
|
||||
static void find_decision_boundary_DT()
|
||||
{
|
||||
Ptr<DTrees> dtree = DTrees::create();
|
||||
dtree->setMaxDepth(8);
|
||||
dtree->setMinSampleCount(2);
|
||||
dtree->setUseSurrogates(false);
|
||||
dtree->setCVFolds(0); // the number of cross-validation folds
|
||||
dtree->setUse1SERule(false);
|
||||
dtree->setTruncatePrunedTree(false);
|
||||
dtree->train(prepare_train_data());
|
||||
predict_and_paint(dtree, imgDst);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if _BT_
|
||||
static void find_decision_boundary_BT()
|
||||
{
|
||||
Ptr<Boost> boost = Boost::create();
|
||||
boost->setBoostType(Boost::DISCRETE);
|
||||
boost->setWeakCount(100);
|
||||
boost->setWeightTrimRate(0.95);
|
||||
boost->setMaxDepth(2);
|
||||
boost->setUseSurrogates(false);
|
||||
boost->setPriors(Mat());
|
||||
boost->train(prepare_train_data());
|
||||
predict_and_paint(boost, imgDst);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if _GBT_
|
||||
static void find_decision_boundary_GBT()
|
||||
{
|
||||
GBTrees::Params params( GBTrees::DEVIANCE_LOSS, // loss_function_type
|
||||
100, // weak_count
|
||||
0.1f, // shrinkage
|
||||
1.0f, // subsample_portion
|
||||
2, // max_depth
|
||||
false // use_surrogates )
|
||||
);
|
||||
|
||||
Ptr<GBTrees> gbtrees = StatModel::train<GBTrees>(prepare_train_data(), params);
|
||||
predict_and_paint(gbtrees, imgDst);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if _RF_
|
||||
static void find_decision_boundary_RF()
|
||||
{
|
||||
Ptr<RTrees> rtrees = RTrees::create();
|
||||
rtrees->setMaxDepth(4);
|
||||
rtrees->setMinSampleCount(2);
|
||||
rtrees->setRegressionAccuracy(0.f);
|
||||
rtrees->setUseSurrogates(false);
|
||||
rtrees->setMaxCategories(16);
|
||||
rtrees->setPriors(Mat());
|
||||
rtrees->setCalculateVarImportance(false);
|
||||
rtrees->setActiveVarCount(1);
|
||||
rtrees->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 5, 0));
|
||||
rtrees->train(prepare_train_data());
|
||||
predict_and_paint(rtrees, imgDst);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if _ANN_
|
||||
static void find_decision_boundary_ANN( const Mat& layer_sizes )
|
||||
{
|
||||
Mat trainClasses = Mat::zeros( (int)trainedPoints.size(), (int)classColors.size(), CV_32FC1 );
|
||||
for( int i = 0; i < trainClasses.rows; i++ )
|
||||
{
|
||||
trainClasses.at<float>(i, trainedPointsMarkers[i]) = 1.f;
|
||||
}
|
||||
|
||||
Mat samples = prepare_train_samples(trainedPoints);
|
||||
Ptr<TrainData> tdata = TrainData::create(samples, ROW_SAMPLE, trainClasses);
|
||||
|
||||
Ptr<ANN_MLP> ann = ANN_MLP::create();
|
||||
ann->setLayerSizes(layer_sizes);
|
||||
ann->setActivationFunction(ANN_MLP::SIGMOID_SYM, 1, 1);
|
||||
ann->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS, 300, FLT_EPSILON));
|
||||
ann->setTrainMethod(ANN_MLP::BACKPROP, 0.001);
|
||||
ann->train(tdata);
|
||||
predict_and_paint(ann, imgDst);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if _EM_
|
||||
static void find_decision_boundary_EM()
|
||||
{
|
||||
img.copyTo( imgDst );
|
||||
|
||||
Mat samples = prepare_train_samples(trainedPoints);
|
||||
|
||||
int i, j, nmodels = (int)classColors.size();
|
||||
vector<Ptr<EM> > em_models(nmodels);
|
||||
Mat modelSamples;
|
||||
|
||||
for( i = 0; i < nmodels; i++ )
|
||||
{
|
||||
const int componentCount = 3;
|
||||
|
||||
modelSamples.release();
|
||||
for( j = 0; j < samples.rows; j++ )
|
||||
{
|
||||
if( trainedPointsMarkers[j] == i )
|
||||
modelSamples.push_back(samples.row(j));
|
||||
}
|
||||
|
||||
// learn models
|
||||
if( !modelSamples.empty() )
|
||||
{
|
||||
Ptr<EM> em = EM::create();
|
||||
em->setClustersNumber(componentCount);
|
||||
em->setCovarianceMatrixType(EM::COV_MAT_DIAGONAL);
|
||||
em->trainEM(modelSamples, noArray(), noArray(), noArray());
|
||||
em_models[i] = em;
|
||||
}
|
||||
}
|
||||
|
||||
// classify coordinate plane points using the bayes classifier, i.e.
|
||||
// y(x) = arg max_i=1_modelsCount likelihoods_i(x)
|
||||
Mat testSample(1, 2, CV_32FC1 );
|
||||
Mat logLikelihoods(1, nmodels, CV_64FC1, Scalar(-DBL_MAX));
|
||||
|
||||
for( int y = 0; y < img.rows; y += testStep )
|
||||
{
|
||||
for( int x = 0; x < img.cols; x += testStep )
|
||||
{
|
||||
testSample.at<float>(0) = (float)x;
|
||||
testSample.at<float>(1) = (float)y;
|
||||
|
||||
for( i = 0; i < nmodels; i++ )
|
||||
{
|
||||
if( !em_models[i].empty() )
|
||||
logLikelihoods.at<double>(i) = em_models[i]->predict2(testSample, noArray())[0];
|
||||
}
|
||||
Point maxLoc;
|
||||
minMaxLoc(logLikelihoods, 0, 0, 0, &maxLoc);
|
||||
imgDst.at<Vec3b>(y, x) = classColors[maxLoc.x];
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
cout << "Use:" << endl
|
||||
<< " key '0' .. '1' - switch to class #n" << endl
|
||||
<< " left mouse button - to add new point;" << endl
|
||||
<< " key 'r' - to run the ML model;" << endl
|
||||
<< " key 'i' - to init (clear) the data." << endl << endl;
|
||||
|
||||
cv::namedWindow( "points", 1 );
|
||||
img.create( 480, 640, CV_8UC3 );
|
||||
imgDst.create( 480, 640, CV_8UC3 );
|
||||
|
||||
imshow( "points", img );
|
||||
setMouseCallback( "points", on_mouse );
|
||||
|
||||
classColors[0] = Vec3b(0, 255, 0);
|
||||
classColors[1] = Vec3b(0, 0, 255);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
char key = (char)waitKey();
|
||||
|
||||
if( key == 27 ) break;
|
||||
|
||||
if( key == 'i' ) // init
|
||||
{
|
||||
img = Scalar::all(0);
|
||||
|
||||
trainedPoints.clear();
|
||||
trainedPointsMarkers.clear();
|
||||
classCounters.assign(MAX_CLASSES, 0);
|
||||
|
||||
imshow( winName, img );
|
||||
}
|
||||
|
||||
if( key == '0' || key == '1' )
|
||||
{
|
||||
currentClass = key - '0';
|
||||
}
|
||||
|
||||
if( key == 'r' ) // run
|
||||
{
|
||||
double minVal = 0;
|
||||
minMaxLoc(classCounters, &minVal, 0, 0, 0);
|
||||
if( minVal == 0 )
|
||||
{
|
||||
printf("each class should have at least 1 point\n");
|
||||
continue;
|
||||
}
|
||||
img.copyTo( imgDst );
|
||||
#if _NBC_
|
||||
find_decision_boundary_NBC();
|
||||
imshow( "NormalBayesClassifier", imgDst );
|
||||
#endif
|
||||
#if _KNN_
|
||||
find_decision_boundary_KNN( 3 );
|
||||
imshow( "kNN", imgDst );
|
||||
|
||||
find_decision_boundary_KNN( 15 );
|
||||
imshow( "kNN2", imgDst );
|
||||
#endif
|
||||
|
||||
#if _SVM_
|
||||
//(1)-(2)separable and not sets
|
||||
|
||||
find_decision_boundary_SVM( 1 );
|
||||
imshow( "classificationSVM1", imgDst );
|
||||
|
||||
find_decision_boundary_SVM( 10 );
|
||||
imshow( "classificationSVM2", imgDst );
|
||||
#endif
|
||||
|
||||
#if _DT_
|
||||
find_decision_boundary_DT();
|
||||
imshow( "DT", imgDst );
|
||||
#endif
|
||||
|
||||
#if _BT_
|
||||
find_decision_boundary_BT();
|
||||
imshow( "BT", imgDst);
|
||||
#endif
|
||||
|
||||
#if _GBT_
|
||||
find_decision_boundary_GBT();
|
||||
imshow( "GBT", imgDst);
|
||||
#endif
|
||||
|
||||
#if _RF_
|
||||
find_decision_boundary_RF();
|
||||
imshow( "RF", imgDst);
|
||||
#endif
|
||||
|
||||
#if _ANN_
|
||||
Mat layer_sizes1( 1, 3, CV_32SC1 );
|
||||
layer_sizes1.at<int>(0) = 2;
|
||||
layer_sizes1.at<int>(1) = 5;
|
||||
layer_sizes1.at<int>(2) = (int)classColors.size();
|
||||
find_decision_boundary_ANN( layer_sizes1 );
|
||||
imshow( "ANN", imgDst );
|
||||
#endif
|
||||
|
||||
#if _EM_
|
||||
find_decision_boundary_EM();
|
||||
imshow( "EM", imgDst );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,392 +0,0 @@
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include "opencv2/ml.hpp"
|
||||
#include "opencv2/objdetect.hpp"
|
||||
#include "opencv2/videoio.hpp"
|
||||
#include <iostream>
|
||||
#include <time.h>
|
||||
|
||||
using namespace cv;
|
||||
using namespace cv::ml;
|
||||
using namespace std;
|
||||
|
||||
vector< float > get_svm_detector( const Ptr< SVM >& svm );
|
||||
void convert_to_ml( const std::vector< Mat > & train_samples, Mat& trainData );
|
||||
void load_images( const String & dirname, vector< Mat > & img_lst, bool showImages );
|
||||
void sample_neg( const vector< Mat > & full_neg_lst, vector< Mat > & neg_lst, const Size & size );
|
||||
void computeHOGs( const Size wsize, const vector< Mat > & img_lst, vector< Mat > & gradient_lst, bool use_flip );
|
||||
void test_trained_detector( String obj_det_filename, String test_dir, String videofilename );
|
||||
|
||||
vector< float > get_svm_detector( const Ptr< SVM >& svm )
|
||||
{
|
||||
// get the support vectors
|
||||
Mat sv = svm->getSupportVectors();
|
||||
const int sv_total = sv.rows;
|
||||
// get the decision function
|
||||
Mat alpha, svidx;
|
||||
double rho = svm->getDecisionFunction( 0, alpha, svidx );
|
||||
|
||||
CV_Assert( alpha.total() == 1 && svidx.total() == 1 && sv_total == 1 );
|
||||
CV_Assert( (alpha.type() == CV_64F && alpha.at<double>(0) == 1.) ||
|
||||
(alpha.type() == CV_32F && alpha.at<float>(0) == 1.f) );
|
||||
CV_Assert( sv.type() == CV_32F );
|
||||
|
||||
vector< float > hog_detector( sv.cols + 1 );
|
||||
memcpy( &hog_detector[0], sv.ptr(), sv.cols*sizeof( hog_detector[0] ) );
|
||||
hog_detector[sv.cols] = (float)-rho;
|
||||
return hog_detector;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert training/testing set to be used by OpenCV Machine Learning algorithms.
|
||||
* TrainData is a matrix of size (#samples x max(#cols,#rows) per samples), in 32FC1.
|
||||
* Transposition of samples are made if needed.
|
||||
*/
|
||||
void convert_to_ml( const vector< Mat > & train_samples, Mat& trainData )
|
||||
{
|
||||
//--Convert data
|
||||
const int rows = (int)train_samples.size();
|
||||
const int cols = (int)std::max( train_samples[0].cols, train_samples[0].rows );
|
||||
Mat tmp( 1, cols, CV_32FC1 ); ///< used for transposition if needed
|
||||
trainData = Mat( rows, cols, CV_32FC1 );
|
||||
|
||||
for( size_t i = 0 ; i < train_samples.size(); ++i )
|
||||
{
|
||||
CV_Assert( train_samples[i].cols == 1 || train_samples[i].rows == 1 );
|
||||
|
||||
if( train_samples[i].cols == 1 )
|
||||
{
|
||||
transpose( train_samples[i], tmp );
|
||||
tmp.copyTo( trainData.row( (int)i ) );
|
||||
}
|
||||
else if( train_samples[i].rows == 1 )
|
||||
{
|
||||
train_samples[i].copyTo( trainData.row( (int)i ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void load_images( const String & dirname, vector< Mat > & img_lst, bool showImages = false )
|
||||
{
|
||||
vector< String > files;
|
||||
glob( dirname, files );
|
||||
|
||||
for ( size_t i = 0; i < files.size(); ++i )
|
||||
{
|
||||
Mat img = imread( files[i] ); // load the image
|
||||
if ( img.empty() )
|
||||
{
|
||||
cout << files[i] << " is invalid!" << endl; // invalid image, skip it.
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( showImages )
|
||||
{
|
||||
imshow( "image", img );
|
||||
waitKey( 1 );
|
||||
}
|
||||
img_lst.push_back( img );
|
||||
}
|
||||
}
|
||||
|
||||
void sample_neg( const vector< Mat > & full_neg_lst, vector< Mat > & neg_lst, const Size & size )
|
||||
{
|
||||
Rect box;
|
||||
box.width = size.width;
|
||||
box.height = size.height;
|
||||
|
||||
srand( (unsigned int)time( NULL ) );
|
||||
|
||||
for ( size_t i = 0; i < full_neg_lst.size(); i++ )
|
||||
if ( full_neg_lst[i].cols > box.width && full_neg_lst[i].rows > box.height )
|
||||
{
|
||||
box.x = rand() % ( full_neg_lst[i].cols - box.width );
|
||||
box.y = rand() % ( full_neg_lst[i].rows - box.height );
|
||||
Mat roi = full_neg_lst[i]( box );
|
||||
neg_lst.push_back( roi.clone() );
|
||||
}
|
||||
}
|
||||
|
||||
void computeHOGs( const Size wsize, const vector< Mat > & img_lst, vector< Mat > & gradient_lst, bool use_flip )
|
||||
{
|
||||
HOGDescriptor hog;
|
||||
hog.winSize = wsize;
|
||||
Mat gray;
|
||||
vector< float > descriptors;
|
||||
|
||||
for( size_t i = 0 ; i < img_lst.size(); i++ )
|
||||
{
|
||||
if ( img_lst[i].cols >= wsize.width && img_lst[i].rows >= wsize.height )
|
||||
{
|
||||
Rect r = Rect(( img_lst[i].cols - wsize.width ) / 2,
|
||||
( img_lst[i].rows - wsize.height ) / 2,
|
||||
wsize.width,
|
||||
wsize.height);
|
||||
cvtColor( img_lst[i](r), gray, COLOR_BGR2GRAY );
|
||||
hog.compute( gray, descriptors, Size( 8, 8 ), Size( 0, 0 ) );
|
||||
gradient_lst.push_back( Mat( descriptors ).clone() );
|
||||
if ( use_flip )
|
||||
{
|
||||
flip( gray, gray, 1 );
|
||||
hog.compute( gray, descriptors, Size( 8, 8 ), Size( 0, 0 ) );
|
||||
gradient_lst.push_back( Mat( descriptors ).clone() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test_trained_detector( String obj_det_filename, String test_dir, String videofilename )
|
||||
{
|
||||
cout << "Testing trained detector..." << endl;
|
||||
HOGDescriptor hog;
|
||||
hog.load( obj_det_filename );
|
||||
|
||||
vector< String > files;
|
||||
glob( test_dir, files );
|
||||
|
||||
int delay = 0;
|
||||
VideoCapture cap;
|
||||
|
||||
if ( videofilename != "" )
|
||||
{
|
||||
if ( videofilename.size() == 1 && isdigit( videofilename[0] ) )
|
||||
cap.open( videofilename[0] - '0' );
|
||||
else
|
||||
cap.open( videofilename );
|
||||
}
|
||||
|
||||
obj_det_filename = "testing " + obj_det_filename;
|
||||
namedWindow( obj_det_filename, WINDOW_NORMAL );
|
||||
|
||||
for( size_t i=0;; i++ )
|
||||
{
|
||||
Mat img;
|
||||
|
||||
if ( cap.isOpened() )
|
||||
{
|
||||
cap >> img;
|
||||
delay = 1;
|
||||
}
|
||||
else if( i < files.size() )
|
||||
{
|
||||
img = imread( files[i] );
|
||||
}
|
||||
|
||||
if ( img.empty() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
vector< Rect > detections;
|
||||
vector< double > foundWeights;
|
||||
|
||||
hog.detectMultiScale( img, detections, foundWeights );
|
||||
for ( size_t j = 0; j < detections.size(); j++ )
|
||||
{
|
||||
Scalar color = Scalar( 0, foundWeights[j] * foundWeights[j] * 200, 0 );
|
||||
rectangle( img, detections[j], color, img.cols / 400 + 1 );
|
||||
}
|
||||
|
||||
imshow( obj_det_filename, img );
|
||||
|
||||
if( waitKey( delay ) == 27 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
const char* keys =
|
||||
{
|
||||
"{help h| | show help message}"
|
||||
"{pd | | path of directory contains positive images}"
|
||||
"{nd | | path of directory contains negative images}"
|
||||
"{td | | path of directory contains test images}"
|
||||
"{tv | | test video file name}"
|
||||
"{dw | | width of the detector}"
|
||||
"{dh | | height of the detector}"
|
||||
"{f |false| indicates if the program will generate and use mirrored samples or not}"
|
||||
"{d |false| train twice}"
|
||||
"{t |false| test a trained detector}"
|
||||
"{v |false| visualize training steps}"
|
||||
"{fn |my_detector.yml| file name of trained SVM}"
|
||||
};
|
||||
|
||||
CommandLineParser parser( argc, argv, keys );
|
||||
|
||||
if ( parser.has( "help" ) )
|
||||
{
|
||||
parser.printMessage();
|
||||
exit( 0 );
|
||||
}
|
||||
|
||||
String pos_dir = parser.get< String >( "pd" );
|
||||
String neg_dir = parser.get< String >( "nd" );
|
||||
String test_dir = parser.get< String >( "td" );
|
||||
String obj_det_filename = parser.get< String >( "fn" );
|
||||
String videofilename = parser.get< String >( "tv" );
|
||||
int detector_width = parser.get< int >( "dw" );
|
||||
int detector_height = parser.get< int >( "dh" );
|
||||
bool test_detector = parser.get< bool >( "t" );
|
||||
bool train_twice = parser.get< bool >( "d" );
|
||||
bool visualization = parser.get< bool >( "v" );
|
||||
bool flip_samples = parser.get< bool >( "f" );
|
||||
|
||||
if ( test_detector )
|
||||
{
|
||||
test_trained_detector( obj_det_filename, test_dir, videofilename );
|
||||
exit( 0 );
|
||||
}
|
||||
|
||||
if( pos_dir.empty() || neg_dir.empty() )
|
||||
{
|
||||
parser.printMessage();
|
||||
cout << "Wrong number of parameters.\n\n"
|
||||
<< "Example command line:\n" << argv[0] << " -dw=64 -dh=128 -pd=/INRIAPerson/96X160H96/Train/pos -nd=/INRIAPerson/neg -td=/INRIAPerson/Test/pos -fn=HOGpedestrian64x128.xml -d\n"
|
||||
<< "\nExample command line for testing trained detector:\n" << argv[0] << " -t -fn=HOGpedestrian64x128.xml -td=/INRIAPerson/Test/pos";
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
vector< Mat > pos_lst, full_neg_lst, neg_lst, gradient_lst;
|
||||
vector< int > labels;
|
||||
|
||||
clog << "Positive images are being loaded..." ;
|
||||
load_images( pos_dir, pos_lst, visualization );
|
||||
if ( pos_lst.size() > 0 )
|
||||
{
|
||||
clog << "...[done] " << pos_lst.size() << " files." << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
clog << "no image in " << pos_dir <<endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
Size pos_image_size = pos_lst[0].size();
|
||||
|
||||
if ( detector_width && detector_height )
|
||||
{
|
||||
pos_image_size = Size( detector_width, detector_height );
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( size_t i = 0; i < pos_lst.size(); ++i )
|
||||
{
|
||||
if( pos_lst[i].size() != pos_image_size )
|
||||
{
|
||||
cout << "All positive images should be same size!" << endl;
|
||||
exit( 1 );
|
||||
}
|
||||
}
|
||||
pos_image_size = pos_image_size / 8 * 8;
|
||||
}
|
||||
|
||||
clog << "Negative images are being loaded...";
|
||||
load_images( neg_dir, full_neg_lst, visualization );
|
||||
clog << "...[done] " << full_neg_lst.size() << " files." << endl;
|
||||
|
||||
clog << "Negative images are being processed...";
|
||||
sample_neg( full_neg_lst, neg_lst, pos_image_size );
|
||||
clog << "...[done] " << neg_lst.size() << " files." << endl;
|
||||
|
||||
clog << "Histogram of Gradients are being calculated for positive images...";
|
||||
computeHOGs( pos_image_size, pos_lst, gradient_lst, flip_samples );
|
||||
size_t positive_count = gradient_lst.size();
|
||||
labels.assign( positive_count, +1 );
|
||||
clog << "...[done] ( positive images count : " << positive_count << " )" << endl;
|
||||
|
||||
clog << "Histogram of Gradients are being calculated for negative images...";
|
||||
computeHOGs( pos_image_size, neg_lst, gradient_lst, flip_samples );
|
||||
size_t negative_count = gradient_lst.size() - positive_count;
|
||||
labels.insert( labels.end(), negative_count, -1 );
|
||||
CV_Assert( positive_count < labels.size() );
|
||||
clog << "...[done] ( negative images count : " << negative_count << " )" << endl;
|
||||
|
||||
Mat train_data;
|
||||
convert_to_ml( gradient_lst, train_data );
|
||||
|
||||
clog << "Training SVM...";
|
||||
Ptr< SVM > svm = SVM::create();
|
||||
/* Default values to train SVM */
|
||||
svm->setCoef0( 0.0 );
|
||||
svm->setDegree( 3 );
|
||||
svm->setTermCriteria( TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 1000, 1e-3 ) );
|
||||
svm->setGamma( 0 );
|
||||
svm->setKernel( SVM::LINEAR );
|
||||
svm->setNu( 0.5 );
|
||||
svm->setP( 0.1 ); // for EPSILON_SVR, epsilon in loss function?
|
||||
svm->setC( 0.01 ); // From paper, soft classifier
|
||||
svm->setType( SVM::EPS_SVR ); // C_SVC; // EPSILON_SVR; // may be also NU_SVR; // do regression task
|
||||
svm->train( train_data, ROW_SAMPLE, labels );
|
||||
clog << "...[done]" << endl;
|
||||
|
||||
if ( train_twice )
|
||||
{
|
||||
clog << "Testing trained detector on negative images. This might take a few minutes...";
|
||||
HOGDescriptor my_hog;
|
||||
my_hog.winSize = pos_image_size;
|
||||
|
||||
// Set the trained svm to my_hog
|
||||
my_hog.setSVMDetector( get_svm_detector( svm ) );
|
||||
|
||||
vector< Rect > detections;
|
||||
vector< double > foundWeights;
|
||||
|
||||
for ( size_t i = 0; i < full_neg_lst.size(); i++ )
|
||||
{
|
||||
if ( full_neg_lst[i].cols >= pos_image_size.width && full_neg_lst[i].rows >= pos_image_size.height )
|
||||
my_hog.detectMultiScale( full_neg_lst[i], detections, foundWeights );
|
||||
else
|
||||
detections.clear();
|
||||
|
||||
for ( size_t j = 0; j < detections.size(); j++ )
|
||||
{
|
||||
Mat detection = full_neg_lst[i]( detections[j] ).clone();
|
||||
resize( detection, detection, pos_image_size, 0, 0, INTER_LINEAR_EXACT);
|
||||
neg_lst.push_back( detection );
|
||||
}
|
||||
|
||||
if ( visualization )
|
||||
{
|
||||
for ( size_t j = 0; j < detections.size(); j++ )
|
||||
{
|
||||
rectangle( full_neg_lst[i], detections[j], Scalar( 0, 255, 0 ), 2 );
|
||||
}
|
||||
imshow( "testing trained detector on negative images", full_neg_lst[i] );
|
||||
waitKey( 5 );
|
||||
}
|
||||
}
|
||||
clog << "...[done]" << endl;
|
||||
|
||||
gradient_lst.clear();
|
||||
clog << "Histogram of Gradients are being calculated for positive images...";
|
||||
computeHOGs( pos_image_size, pos_lst, gradient_lst, flip_samples );
|
||||
positive_count = gradient_lst.size();
|
||||
clog << "...[done] ( positive count : " << positive_count << " )" << endl;
|
||||
|
||||
clog << "Histogram of Gradients are being calculated for negative images...";
|
||||
computeHOGs( pos_image_size, neg_lst, gradient_lst, flip_samples );
|
||||
negative_count = gradient_lst.size() - positive_count;
|
||||
clog << "...[done] ( negative count : " << negative_count << " )" << endl;
|
||||
|
||||
labels.clear();
|
||||
labels.assign(positive_count, +1);
|
||||
labels.insert(labels.end(), negative_count, -1);
|
||||
|
||||
clog << "Training SVM again...";
|
||||
convert_to_ml( gradient_lst, train_data );
|
||||
svm->train( train_data, ROW_SAMPLE, labels );
|
||||
clog << "...[done]" << endl;
|
||||
}
|
||||
|
||||
HOGDescriptor hog;
|
||||
hog.winSize = pos_image_size;
|
||||
hog.setSVMDetector( get_svm_detector( svm ) );
|
||||
hog.save( obj_det_filename );
|
||||
|
||||
test_trained_detector( obj_det_filename, test_dir, videofilename );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,211 +0,0 @@
|
||||
#include "opencv2/core.hpp"
|
||||
#include "opencv2/video/tracking.hpp"
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include "opencv2/ml.hpp"
|
||||
|
||||
using namespace cv;
|
||||
using namespace cv::ml;
|
||||
|
||||
|
||||
struct Data
|
||||
{
|
||||
Mat img;
|
||||
Mat samples; //Set of train samples. Contains points on image
|
||||
Mat responses; //Set of responses for train samples
|
||||
|
||||
Data()
|
||||
{
|
||||
const int WIDTH = 841;
|
||||
const int HEIGHT = 594;
|
||||
img = Mat::zeros(HEIGHT, WIDTH, CV_8UC3);
|
||||
imshow("Train svmsgd", img);
|
||||
}
|
||||
};
|
||||
|
||||
//Train with SVMSGD algorithm
|
||||
//(samples, responses) is a train set
|
||||
//weights is a required vector for decision function of SVMSGD algorithm
|
||||
bool doTrain(const Mat samples, const Mat responses, Mat &weights, float &shift);
|
||||
|
||||
//function finds two points for drawing line (wx = 0)
|
||||
bool findPointsForLine(const Mat &weights, float shift, Point points[2], int width, int height);
|
||||
|
||||
// function finds cross point of line (wx = 0) and segment ( (y = HEIGHT, 0 <= x <= WIDTH) or (x = WIDTH, 0 <= y <= HEIGHT) )
|
||||
bool findCrossPointWithBorders(const Mat &weights, float shift, const std::pair<Point,Point> &segment, Point &crossPoint);
|
||||
|
||||
//segments' initialization ( (y = HEIGHT, 0 <= x <= WIDTH) and (x = WIDTH, 0 <= y <= HEIGHT) )
|
||||
void fillSegments(std::vector<std::pair<Point,Point> > &segments, int width, int height);
|
||||
|
||||
//redraw points' set and line (wx = 0)
|
||||
void redraw(Data data, const Point points[2]);
|
||||
|
||||
//add point in train set, train SVMSGD algorithm and draw results on image
|
||||
void addPointRetrainAndRedraw(Data &data, int x, int y, int response);
|
||||
|
||||
|
||||
bool doTrain( const Mat samples, const Mat responses, Mat &weights, float &shift)
|
||||
{
|
||||
cv::Ptr<SVMSGD> svmsgd = SVMSGD::create();
|
||||
|
||||
cv::Ptr<TrainData> trainData = TrainData::create(samples, cv::ml::ROW_SAMPLE, responses);
|
||||
svmsgd->train( trainData );
|
||||
|
||||
if (svmsgd->isTrained())
|
||||
{
|
||||
weights = svmsgd->getWeights();
|
||||
shift = svmsgd->getShift();
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void fillSegments(std::vector<std::pair<Point,Point> > &segments, int width, int height)
|
||||
{
|
||||
std::pair<Point,Point> currentSegment;
|
||||
|
||||
currentSegment.first = Point(width, 0);
|
||||
currentSegment.second = Point(width, height);
|
||||
segments.push_back(currentSegment);
|
||||
|
||||
currentSegment.first = Point(0, height);
|
||||
currentSegment.second = Point(width, height);
|
||||
segments.push_back(currentSegment);
|
||||
|
||||
currentSegment.first = Point(0, 0);
|
||||
currentSegment.second = Point(width, 0);
|
||||
segments.push_back(currentSegment);
|
||||
|
||||
currentSegment.first = Point(0, 0);
|
||||
currentSegment.second = Point(0, height);
|
||||
segments.push_back(currentSegment);
|
||||
}
|
||||
|
||||
|
||||
bool findCrossPointWithBorders(const Mat &weights, float shift, const std::pair<Point,Point> &segment, Point &crossPoint)
|
||||
{
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int xMin = std::min(segment.first.x, segment.second.x);
|
||||
int xMax = std::max(segment.first.x, segment.second.x);
|
||||
int yMin = std::min(segment.first.y, segment.second.y);
|
||||
int yMax = std::max(segment.first.y, segment.second.y);
|
||||
|
||||
CV_Assert(weights.type() == CV_32FC1);
|
||||
CV_Assert(xMin == xMax || yMin == yMax);
|
||||
|
||||
if (xMin == xMax && weights.at<float>(1) != 0)
|
||||
{
|
||||
x = xMin;
|
||||
y = static_cast<int>(std::floor( - (weights.at<float>(0) * x + shift) / weights.at<float>(1)));
|
||||
if (y >= yMin && y <= yMax)
|
||||
{
|
||||
crossPoint.x = x;
|
||||
crossPoint.y = y;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (yMin == yMax && weights.at<float>(0) != 0)
|
||||
{
|
||||
y = yMin;
|
||||
x = static_cast<int>(std::floor( - (weights.at<float>(1) * y + shift) / weights.at<float>(0)));
|
||||
if (x >= xMin && x <= xMax)
|
||||
{
|
||||
crossPoint.x = x;
|
||||
crossPoint.y = y;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool findPointsForLine(const Mat &weights, float shift, Point points[2], int width, int height)
|
||||
{
|
||||
if (weights.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int foundPointsCount = 0;
|
||||
std::vector<std::pair<Point,Point> > segments;
|
||||
fillSegments(segments, width, height);
|
||||
|
||||
for (uint i = 0; i < segments.size(); i++)
|
||||
{
|
||||
if (findCrossPointWithBorders(weights, shift, segments[i], points[foundPointsCount]))
|
||||
foundPointsCount++;
|
||||
if (foundPointsCount >= 2)
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void redraw(Data data, const Point points[2])
|
||||
{
|
||||
data.img.setTo(0);
|
||||
Point center;
|
||||
int radius = 3;
|
||||
Scalar color;
|
||||
CV_Assert((data.samples.type() == CV_32FC1) && (data.responses.type() == CV_32FC1));
|
||||
for (int i = 0; i < data.samples.rows; i++)
|
||||
{
|
||||
center.x = static_cast<int>(data.samples.at<float>(i,0));
|
||||
center.y = static_cast<int>(data.samples.at<float>(i,1));
|
||||
color = (data.responses.at<float>(i) > 0) ? Scalar(128,128,0) : Scalar(0,128,128);
|
||||
circle(data.img, center, radius, color, 5);
|
||||
}
|
||||
line(data.img, points[0], points[1],cv::Scalar(1,255,1));
|
||||
|
||||
imshow("Train svmsgd", data.img);
|
||||
}
|
||||
|
||||
void addPointRetrainAndRedraw(Data &data, int x, int y, int response)
|
||||
{
|
||||
Mat currentSample(1, 2, CV_32FC1);
|
||||
|
||||
currentSample.at<float>(0,0) = (float)x;
|
||||
currentSample.at<float>(0,1) = (float)y;
|
||||
data.samples.push_back(currentSample);
|
||||
data.responses.push_back(static_cast<float>(response));
|
||||
|
||||
Mat weights(1, 2, CV_32FC1);
|
||||
float shift = 0;
|
||||
|
||||
if (doTrain(data.samples, data.responses, weights, shift))
|
||||
{
|
||||
Point points[2];
|
||||
findPointsForLine(weights, shift, points, data.img.cols, data.img.rows);
|
||||
|
||||
redraw(data, points);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void onMouse( int event, int x, int y, int, void* pData)
|
||||
{
|
||||
Data &data = *(Data*)pData;
|
||||
|
||||
switch( event )
|
||||
{
|
||||
case EVENT_LBUTTONUP:
|
||||
addPointRetrainAndRedraw(data, x, y, 1);
|
||||
break;
|
||||
|
||||
case EVENT_RBUTTONDOWN:
|
||||
addPointRetrainAndRedraw(data, x, y, -1);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
Data data;
|
||||
|
||||
setMouseCallback( "Train svmsgd", onMouse, &data );
|
||||
waitKey();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
#include <opencv2/core.hpp>
|
||||
#include <opencv2/imgproc.hpp>
|
||||
#include <opencv2/highgui.hpp>
|
||||
#include <opencv2/ml.hpp>
|
||||
|
||||
using namespace cv;
|
||||
|
||||
class TravelSalesman
|
||||
{
|
||||
private :
|
||||
const std::vector<Point>& posCity;
|
||||
std::vector<int>& next;
|
||||
RNG rng;
|
||||
int d0,d1,d2,d3;
|
||||
|
||||
public:
|
||||
TravelSalesman(std::vector<Point> &p, std::vector<int> &n) :
|
||||
posCity(p), next(n)
|
||||
{
|
||||
rng = theRNG();
|
||||
}
|
||||
/** Give energy value for a state of system.*/
|
||||
double energy() const;
|
||||
/** Function which change the state of system (random perturbation).*/
|
||||
void changeState();
|
||||
/** Function to reverse to the previous state.*/
|
||||
void reverseState();
|
||||
|
||||
};
|
||||
|
||||
void TravelSalesman::changeState()
|
||||
{
|
||||
d0 = rng.uniform(0,static_cast<int>(posCity.size()));
|
||||
d1 = next[d0];
|
||||
d2 = next[d1];
|
||||
d3 = next[d2];
|
||||
|
||||
next[d0] = d2;
|
||||
next[d2] = d1;
|
||||
next[d1] = d3;
|
||||
}
|
||||
|
||||
|
||||
void TravelSalesman::reverseState()
|
||||
{
|
||||
next[d0] = d1;
|
||||
next[d1] = d2;
|
||||
next[d2] = d3;
|
||||
}
|
||||
|
||||
double TravelSalesman::energy() const
|
||||
{
|
||||
double e = 0;
|
||||
for (size_t i = 0; i < next.size(); i++)
|
||||
{
|
||||
e += norm(posCity[i]-posCity[next[i]]);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
static void DrawTravelMap(Mat &img, std::vector<Point> &p, std::vector<int> &n)
|
||||
{
|
||||
for (size_t i = 0; i < n.size(); i++)
|
||||
{
|
||||
circle(img,p[i],5,Scalar(0,0,255),2);
|
||||
line(img,p[i],p[n[i]],Scalar(0,255,0),2);
|
||||
}
|
||||
}
|
||||
int main(void)
|
||||
{
|
||||
int nbCity=40;
|
||||
Mat img(500,500,CV_8UC3,Scalar::all(0));
|
||||
RNG rng(123456);
|
||||
int radius=static_cast<int>(img.cols*0.45);
|
||||
Point center(img.cols/2,img.rows/2);
|
||||
|
||||
std::vector<Point> posCity(nbCity);
|
||||
std::vector<int> next(nbCity);
|
||||
for (size_t i = 0; i < posCity.size(); i++)
|
||||
{
|
||||
double theta = rng.uniform(0., 2 * CV_PI);
|
||||
posCity[i].x = static_cast<int>(radius*cos(theta)) + center.x;
|
||||
posCity[i].y = static_cast<int>(radius*sin(theta)) + center.y;
|
||||
next[i]=(i+1)%nbCity;
|
||||
}
|
||||
TravelSalesman ts_system(posCity, next);
|
||||
|
||||
DrawTravelMap(img,posCity,next);
|
||||
imshow("Map",img);
|
||||
waitKey(10);
|
||||
double currentTemperature = 100.0;
|
||||
for (int i = 0, zeroChanges = 0; zeroChanges < 10; i++)
|
||||
{
|
||||
int changesApplied = ml::simulatedAnnealingSolver(ts_system, currentTemperature, currentTemperature*0.97, 0.99, 10000*nbCity, ¤tTemperature, rng);
|
||||
img.setTo(Scalar::all(0));
|
||||
DrawTravelMap(img, posCity, next);
|
||||
imshow("Map", img);
|
||||
int k = waitKey(10);
|
||||
std::cout << "i=" << i << " changesApplied=" << changesApplied << " temp=" << currentTemperature << " result=" << ts_system.energy() << std::endl;
|
||||
if (k == 27 || k == 'q' || k == 'Q')
|
||||
return 0;
|
||||
if (changesApplied == 0)
|
||||
zeroChanges++;
|
||||
}
|
||||
std::cout << "Done" << std::endl;
|
||||
waitKey(0);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
#include "opencv2/ml.hpp"
|
||||
#include "opencv2/core.hpp"
|
||||
#include "opencv2/core/utility.hpp"
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
using namespace cv;
|
||||
using namespace cv::ml;
|
||||
|
||||
static void help(char** argv)
|
||||
{
|
||||
printf(
|
||||
"\nThis sample demonstrates how to use different decision trees and forests including boosting and random trees.\n"
|
||||
"Usage:\n\t%s [-r=<response_column>] [-ts=type_spec] <csv filename>\n"
|
||||
"where -r=<response_column> specified the 0-based index of the response (0 by default)\n"
|
||||
"-ts= specifies the var type spec in the form ord[n1,n2-n3,n4-n5,...]cat[m1-m2,m3,m4-m5,...]\n"
|
||||
"<csv filename> is the name of training data file in comma-separated value format\n\n", argv[0]);
|
||||
}
|
||||
|
||||
static void train_and_print_errs(Ptr<StatModel> model, const Ptr<TrainData>& data)
|
||||
{
|
||||
bool ok = model->train(data);
|
||||
if( !ok )
|
||||
{
|
||||
printf("Training failed\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf( "train error: %f\n", model->calcError(data, false, noArray()) );
|
||||
printf( "test error: %f\n\n", model->calcError(data, true, noArray()) );
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
cv::CommandLineParser parser(argc, argv, "{ help h | | }{r | 0 | }{ts | | }{@input | | }");
|
||||
if (parser.has("help"))
|
||||
{
|
||||
help(argv);
|
||||
return 0;
|
||||
}
|
||||
std::string filename = parser.get<std::string>("@input");
|
||||
int response_idx;
|
||||
std::string typespec;
|
||||
response_idx = parser.get<int>("r");
|
||||
typespec = parser.get<std::string>("ts");
|
||||
if( filename.empty() || !parser.check() )
|
||||
{
|
||||
parser.printErrors();
|
||||
help(argv);
|
||||
return 0;
|
||||
}
|
||||
printf("\nReading in %s...\n\n",filename.c_str());
|
||||
const double train_test_split_ratio = 0.5;
|
||||
|
||||
Ptr<TrainData> data = TrainData::loadFromCSV(filename, 0, response_idx, response_idx+1, typespec);
|
||||
if( data.empty() )
|
||||
{
|
||||
printf("ERROR: File %s can not be read\n", filename.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
data->setTrainTestSplitRatio(train_test_split_ratio);
|
||||
std::cout << "Test/Train: " << data->getNTestSamples() << "/" << data->getNTrainSamples();
|
||||
|
||||
printf("======DTREE=====\n");
|
||||
Ptr<DTrees> dtree = DTrees::create();
|
||||
dtree->setMaxDepth(10);
|
||||
dtree->setMinSampleCount(2);
|
||||
dtree->setRegressionAccuracy(0);
|
||||
dtree->setUseSurrogates(false);
|
||||
dtree->setMaxCategories(16);
|
||||
dtree->setCVFolds(0);
|
||||
dtree->setUse1SERule(false);
|
||||
dtree->setTruncatePrunedTree(false);
|
||||
dtree->setPriors(Mat());
|
||||
train_and_print_errs(dtree, data);
|
||||
|
||||
if( (int)data->getClassLabels().total() <= 2 ) // regression or 2-class classification problem
|
||||
{
|
||||
printf("======BOOST=====\n");
|
||||
Ptr<Boost> boost = Boost::create();
|
||||
boost->setBoostType(Boost::GENTLE);
|
||||
boost->setWeakCount(100);
|
||||
boost->setWeightTrimRate(0.95);
|
||||
boost->setMaxDepth(2);
|
||||
boost->setUseSurrogates(false);
|
||||
boost->setPriors(Mat());
|
||||
train_and_print_errs(boost, data);
|
||||
}
|
||||
|
||||
printf("======RTREES=====\n");
|
||||
Ptr<RTrees> rtrees = RTrees::create();
|
||||
rtrees->setMaxDepth(10);
|
||||
rtrees->setMinSampleCount(2);
|
||||
rtrees->setRegressionAccuracy(0);
|
||||
rtrees->setUseSurrogates(false);
|
||||
rtrees->setMaxCategories(16);
|
||||
rtrees->setPriors(Mat());
|
||||
rtrees->setCalculateVarImportance(true);
|
||||
rtrees->setActiveVarCount(0);
|
||||
rtrees->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 100, 0));
|
||||
train_and_print_errs(rtrees, data);
|
||||
cv::Mat ref_labels = data->getClassLabels();
|
||||
cv::Mat test_data = data->getTestSampleIdx();
|
||||
cv::Mat predict_labels;
|
||||
rtrees->predict(data->getSamples(), predict_labels);
|
||||
|
||||
cv::Mat variable_importance = rtrees->getVarImportance();
|
||||
std::cout << "Estimated variable importance" << std::endl;
|
||||
for (int i = 0; i < variable_importance.rows; i++) {
|
||||
std::cout << "Variable " << i << ": " << variable_importance.at<float>(i, 0) << std::endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
#include <opencv2/core.hpp>
|
||||
#include <opencv2/imgproc.hpp>
|
||||
#include <opencv2/imgcodecs.hpp>
|
||||
#include <opencv2/highgui.hpp>
|
||||
#include <opencv2/ml.hpp>
|
||||
|
||||
using namespace cv;
|
||||
using namespace cv::ml;
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
// Set up training data
|
||||
//! [setup1]
|
||||
int labels[4] = {1, -1, -1, -1};
|
||||
float trainingData[4][2] = { {501, 10}, {255, 10}, {501, 255}, {10, 501} };
|
||||
//! [setup1]
|
||||
//! [setup2]
|
||||
Mat trainingDataMat(4, 2, CV_32F, trainingData);
|
||||
Mat labelsMat(4, 1, CV_32SC1, labels);
|
||||
//! [setup2]
|
||||
|
||||
// Train the SVM
|
||||
//! [init]
|
||||
Ptr<SVM> svm = SVM::create();
|
||||
svm->setType(SVM::C_SVC);
|
||||
svm->setKernel(SVM::LINEAR);
|
||||
svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 100, 1e-6));
|
||||
//! [init]
|
||||
//! [train]
|
||||
svm->train(trainingDataMat, ROW_SAMPLE, labelsMat);
|
||||
//! [train]
|
||||
|
||||
// Data for visual representation
|
||||
int width = 512, height = 512;
|
||||
Mat image = Mat::zeros(height, width, CV_8UC3);
|
||||
|
||||
// Show the decision regions given by the SVM
|
||||
//! [show]
|
||||
Vec3b green(0,255,0), blue(255,0,0);
|
||||
for (int i = 0; i < image.rows; i++)
|
||||
{
|
||||
for (int j = 0; j < image.cols; j++)
|
||||
{
|
||||
Mat sampleMat = (Mat_<float>(1,2) << j,i);
|
||||
float response = svm->predict(sampleMat);
|
||||
|
||||
if (response == 1)
|
||||
image.at<Vec3b>(i,j) = green;
|
||||
else if (response == -1)
|
||||
image.at<Vec3b>(i,j) = blue;
|
||||
}
|
||||
}
|
||||
//! [show]
|
||||
|
||||
// Show the training data
|
||||
//! [show_data]
|
||||
int thickness = -1;
|
||||
circle( image, Point(501, 10), 5, Scalar( 0, 0, 0), thickness );
|
||||
circle( image, Point(255, 10), 5, Scalar(255, 255, 255), thickness );
|
||||
circle( image, Point(501, 255), 5, Scalar(255, 255, 255), thickness );
|
||||
circle( image, Point( 10, 501), 5, Scalar(255, 255, 255), thickness );
|
||||
//! [show_data]
|
||||
|
||||
// Show support vectors
|
||||
//! [show_vectors]
|
||||
thickness = 2;
|
||||
Mat sv = svm->getUncompressedSupportVectors();
|
||||
|
||||
for (int i = 0; i < sv.rows; i++)
|
||||
{
|
||||
const float* v = sv.ptr<float>(i);
|
||||
circle(image, Point( (int) v[0], (int) v[1]), 6, Scalar(128, 128, 128), thickness);
|
||||
}
|
||||
//! [show_vectors]
|
||||
|
||||
imwrite("result.png", image); // save the image
|
||||
|
||||
imshow("SVM Simple Example", image); // show it to the user
|
||||
waitKey();
|
||||
return 0;
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
#include <iostream>
|
||||
#include <opencv2/core.hpp>
|
||||
#include <opencv2/imgproc.hpp>
|
||||
#include "opencv2/imgcodecs.hpp"
|
||||
#include <opencv2/highgui.hpp>
|
||||
#include <opencv2/ml.hpp>
|
||||
|
||||
using namespace cv;
|
||||
using namespace cv::ml;
|
||||
using namespace std;
|
||||
|
||||
static void help()
|
||||
{
|
||||
cout<< "\n--------------------------------------------------------------------------" << endl
|
||||
<< "This program shows Support Vector Machines for Non-Linearly Separable Data. " << endl
|
||||
<< "--------------------------------------------------------------------------" << endl
|
||||
<< endl;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
help();
|
||||
|
||||
const int NTRAINING_SAMPLES = 100; // Number of training samples per class
|
||||
const float FRAC_LINEAR_SEP = 0.9f; // Fraction of samples which compose the linear separable part
|
||||
|
||||
// Data for visual representation
|
||||
const int WIDTH = 512, HEIGHT = 512;
|
||||
Mat I = Mat::zeros(HEIGHT, WIDTH, CV_8UC3);
|
||||
|
||||
//--------------------- 1. Set up training data randomly ---------------------------------------
|
||||
Mat trainData(2*NTRAINING_SAMPLES, 2, CV_32F);
|
||||
Mat labels (2*NTRAINING_SAMPLES, 1, CV_32S);
|
||||
|
||||
RNG rng(100); // Random value generation class
|
||||
|
||||
// Set up the linearly separable part of the training data
|
||||
int nLinearSamples = (int) (FRAC_LINEAR_SEP * NTRAINING_SAMPLES);
|
||||
|
||||
//! [setup1]
|
||||
// Generate random points for the class 1
|
||||
Mat trainClass = trainData.rowRange(0, nLinearSamples);
|
||||
// The x coordinate of the points is in [0, 0.4)
|
||||
Mat c = trainClass.colRange(0, 1);
|
||||
rng.fill(c, RNG::UNIFORM, Scalar(0), Scalar(0.4 * WIDTH));
|
||||
// The y coordinate of the points is in [0, 1)
|
||||
c = trainClass.colRange(1,2);
|
||||
rng.fill(c, RNG::UNIFORM, Scalar(0), Scalar(HEIGHT));
|
||||
|
||||
// Generate random points for the class 2
|
||||
trainClass = trainData.rowRange(2*NTRAINING_SAMPLES-nLinearSamples, 2*NTRAINING_SAMPLES);
|
||||
// The x coordinate of the points is in [0.6, 1]
|
||||
c = trainClass.colRange(0 , 1);
|
||||
rng.fill(c, RNG::UNIFORM, Scalar(0.6*WIDTH), Scalar(WIDTH));
|
||||
// The y coordinate of the points is in [0, 1)
|
||||
c = trainClass.colRange(1,2);
|
||||
rng.fill(c, RNG::UNIFORM, Scalar(0), Scalar(HEIGHT));
|
||||
//! [setup1]
|
||||
|
||||
//------------------ Set up the non-linearly separable part of the training data ---------------
|
||||
//! [setup2]
|
||||
// Generate random points for the classes 1 and 2
|
||||
trainClass = trainData.rowRange(nLinearSamples, 2*NTRAINING_SAMPLES-nLinearSamples);
|
||||
// The x coordinate of the points is in [0.4, 0.6)
|
||||
c = trainClass.colRange(0,1);
|
||||
rng.fill(c, RNG::UNIFORM, Scalar(0.4*WIDTH), Scalar(0.6*WIDTH));
|
||||
// The y coordinate of the points is in [0, 1)
|
||||
c = trainClass.colRange(1,2);
|
||||
rng.fill(c, RNG::UNIFORM, Scalar(0), Scalar(HEIGHT));
|
||||
//! [setup2]
|
||||
|
||||
//------------------------- Set up the labels for the classes ---------------------------------
|
||||
labels.rowRange( 0, NTRAINING_SAMPLES).setTo(1); // Class 1
|
||||
labels.rowRange(NTRAINING_SAMPLES, 2*NTRAINING_SAMPLES).setTo(2); // Class 2
|
||||
|
||||
//------------------------ 2. Set up the support vector machines parameters --------------------
|
||||
cout << "Starting training process" << endl;
|
||||
//! [init]
|
||||
Ptr<SVM> svm = SVM::create();
|
||||
svm->setType(SVM::C_SVC);
|
||||
svm->setC(0.1);
|
||||
svm->setKernel(SVM::LINEAR);
|
||||
svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, (int)1e7, 1e-6));
|
||||
//! [init]
|
||||
|
||||
//------------------------ 3. Train the svm ----------------------------------------------------
|
||||
//! [train]
|
||||
svm->train(trainData, ROW_SAMPLE, labels);
|
||||
//! [train]
|
||||
cout << "Finished training process" << endl;
|
||||
|
||||
//------------------------ 4. Show the decision regions ----------------------------------------
|
||||
//! [show]
|
||||
Vec3b green(0,100,0), blue(100,0,0);
|
||||
for (int i = 0; i < I.rows; i++)
|
||||
{
|
||||
for (int j = 0; j < I.cols; j++)
|
||||
{
|
||||
Mat sampleMat = (Mat_<float>(1,2) << j, i);
|
||||
float response = svm->predict(sampleMat);
|
||||
|
||||
if (response == 1) I.at<Vec3b>(i,j) = green;
|
||||
else if (response == 2) I.at<Vec3b>(i,j) = blue;
|
||||
}
|
||||
}
|
||||
//! [show]
|
||||
|
||||
//----------------------- 5. Show the training data --------------------------------------------
|
||||
//! [show_data]
|
||||
int thick = -1;
|
||||
float px, py;
|
||||
// Class 1
|
||||
for (int i = 0; i < NTRAINING_SAMPLES; i++)
|
||||
{
|
||||
px = trainData.at<float>(i,0);
|
||||
py = trainData.at<float>(i,1);
|
||||
circle(I, Point( (int) px, (int) py ), 3, Scalar(0, 255, 0), thick);
|
||||
}
|
||||
// Class 2
|
||||
for (int i = NTRAINING_SAMPLES; i <2*NTRAINING_SAMPLES; i++)
|
||||
{
|
||||
px = trainData.at<float>(i,0);
|
||||
py = trainData.at<float>(i,1);
|
||||
circle(I, Point( (int) px, (int) py ), 3, Scalar(255, 0, 0), thick);
|
||||
}
|
||||
//! [show_data]
|
||||
|
||||
//------------------------- 6. Show support vectors --------------------------------------------
|
||||
//! [show_vectors]
|
||||
thick = 2;
|
||||
Mat sv = svm->getUncompressedSupportVectors();
|
||||
|
||||
for (int i = 0; i < sv.rows; i++)
|
||||
{
|
||||
const float* v = sv.ptr<float>(i);
|
||||
circle(I, Point( (int) v[0], (int) v[1]), 6, Scalar(128, 128, 128), thick);
|
||||
}
|
||||
//! [show_vectors]
|
||||
|
||||
imwrite("result.png", I); // save the Image
|
||||
imshow("SVM for Non-Linear Training Data", I); // show it to the user
|
||||
waitKey();
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user