vendor: OpenCV 5.0.0 snapshot at 755e50675d97db9b7d449d8bd6b09888646f6c6e
This commit is contained in:
@@ -0,0 +1,368 @@
|
||||
#include "opencv2/core.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include "opencv2/imgcodecs.hpp"
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include "opencv2/geometry.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;
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
#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;
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
#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;
|
||||
}
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
import org.opencv.core.Core;
|
||||
import org.opencv.core.CvType;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.core.Point;
|
||||
import org.opencv.core.Scalar;
|
||||
import org.opencv.core.TermCriteria;
|
||||
import org.opencv.highgui.HighGui;
|
||||
import org.opencv.imgcodecs.Imgcodecs;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
import org.opencv.ml.Ml;
|
||||
import org.opencv.ml.SVM;
|
||||
|
||||
public class IntroductionToSVMDemo {
|
||||
public static void main(String[] args) {
|
||||
// Load the native OpenCV library
|
||||
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
|
||||
|
||||
// Set up training data
|
||||
//! [setup1]
|
||||
int[] labels = { 1, -1, -1, -1 };
|
||||
float[] trainingData = { 501, 10, 255, 10, 501, 255, 10, 501 };
|
||||
//! [setup1]
|
||||
//! [setup2]
|
||||
Mat trainingDataMat = new Mat(4, 2, CvType.CV_32FC1);
|
||||
trainingDataMat.put(0, 0, trainingData);
|
||||
Mat labelsMat = new Mat(4, 1, CvType.CV_32SC1);
|
||||
labelsMat.put(0, 0, labels);
|
||||
//! [setup2]
|
||||
|
||||
// Train the SVM
|
||||
//! [init]
|
||||
SVM svm = SVM.create();
|
||||
svm.setType(SVM.C_SVC);
|
||||
svm.setKernel(SVM.LINEAR);
|
||||
svm.setTermCriteria(new TermCriteria(TermCriteria.MAX_ITER, 100, 1e-6));
|
||||
//! [init]
|
||||
//! [train]
|
||||
svm.train(trainingDataMat, Ml.ROW_SAMPLE, labelsMat);
|
||||
//! [train]
|
||||
|
||||
// Data for visual representation
|
||||
int width = 512, height = 512;
|
||||
Mat image = Mat.zeros(height, width, CvType.CV_8UC3);
|
||||
|
||||
// Show the decision regions given by the SVM
|
||||
//! [show]
|
||||
byte[] imageData = new byte[(int) (image.total() * image.channels())];
|
||||
Mat sampleMat = new Mat(1, 2, CvType.CV_32F);
|
||||
float[] sampleMatData = new float[(int) (sampleMat.total() * sampleMat.channels())];
|
||||
for (int i = 0; i < image.rows(); i++) {
|
||||
for (int j = 0; j < image.cols(); j++) {
|
||||
sampleMatData[0] = j;
|
||||
sampleMatData[1] = i;
|
||||
sampleMat.put(0, 0, sampleMatData);
|
||||
float response = svm.predict(sampleMat);
|
||||
|
||||
if (response == 1) {
|
||||
imageData[(i * image.cols() + j) * image.channels()] = 0;
|
||||
imageData[(i * image.cols() + j) * image.channels() + 1] = (byte) 255;
|
||||
imageData[(i * image.cols() + j) * image.channels() + 2] = 0;
|
||||
} else if (response == -1) {
|
||||
imageData[(i * image.cols() + j) * image.channels()] = (byte) 255;
|
||||
imageData[(i * image.cols() + j) * image.channels() + 1] = 0;
|
||||
imageData[(i * image.cols() + j) * image.channels() + 2] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
image.put(0, 0, imageData);
|
||||
//! [show]
|
||||
|
||||
// Show the training data
|
||||
//! [show_data]
|
||||
int thickness = -1;
|
||||
int lineType = Imgproc.LINE_8;
|
||||
Imgproc.circle(image, new Point(501, 10), 5, new Scalar(0, 0, 0), thickness, lineType, 0);
|
||||
Imgproc.circle(image, new Point(255, 10), 5, new Scalar(255, 255, 255), thickness, lineType, 0);
|
||||
Imgproc.circle(image, new Point(501, 255), 5, new Scalar(255, 255, 255), thickness, lineType, 0);
|
||||
Imgproc.circle(image, new Point(10, 501), 5, new Scalar(255, 255, 255), thickness, lineType, 0);
|
||||
//! [show_data]
|
||||
|
||||
// Show support vectors
|
||||
//! [show_vectors]
|
||||
thickness = 2;
|
||||
Mat sv = svm.getUncompressedSupportVectors();
|
||||
float[] svData = new float[(int) (sv.total() * sv.channels())];
|
||||
sv.get(0, 0, svData);
|
||||
for (int i = 0; i < sv.rows(); ++i) {
|
||||
Imgproc.circle(image, new Point(svData[i * sv.cols()], svData[i * sv.cols() + 1]), 6,
|
||||
new Scalar(128, 128, 128), thickness, lineType, 0);
|
||||
}
|
||||
//! [show_vectors]
|
||||
|
||||
Imgcodecs.imwrite("result.png", image); // save the image
|
||||
|
||||
HighGui.imshow("SVM Simple Example", image); // show it to the user
|
||||
HighGui.waitKey();
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
import java.util.Random;
|
||||
|
||||
import org.opencv.core.Core;
|
||||
import org.opencv.core.CvType;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.core.Point;
|
||||
import org.opencv.core.Scalar;
|
||||
import org.opencv.core.TermCriteria;
|
||||
import org.opencv.highgui.HighGui;
|
||||
import org.opencv.imgcodecs.Imgcodecs;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
import org.opencv.ml.Ml;
|
||||
import org.opencv.ml.SVM;
|
||||
|
||||
public class NonLinearSVMsDemo {
|
||||
public static final int NTRAINING_SAMPLES = 100;
|
||||
public static final float FRAC_LINEAR_SEP = 0.9f;
|
||||
|
||||
public static void main(String[] args) {
|
||||
// Load the native OpenCV library
|
||||
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
|
||||
|
||||
System.out.println("\n--------------------------------------------------------------------------");
|
||||
System.out.println("This program shows Support Vector Machines for Non-Linearly Separable Data. ");
|
||||
System.out.println("--------------------------------------------------------------------------\n");
|
||||
|
||||
// Data for visual representation
|
||||
int width = 512, height = 512;
|
||||
Mat I = Mat.zeros(height, width, CvType.CV_8UC3);
|
||||
|
||||
// --------------------- 1. Set up training data randomly---------------------------------------
|
||||
Mat trainData = new Mat(2 * NTRAINING_SAMPLES, 2, CvType.CV_32F);
|
||||
Mat labels = new Mat(2 * NTRAINING_SAMPLES, 1, CvType.CV_32S);
|
||||
|
||||
Random rng = new Random(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);
|
||||
float[] cData = new float[(int) (c.total() * c.channels())];
|
||||
double[] cDataDbl = rng.doubles(cData.length, 0, 0.4f * width).toArray();
|
||||
for (int i = 0; i < cData.length; i++) {
|
||||
cData[i] = (float) cDataDbl[i];
|
||||
}
|
||||
c.put(0, 0, cData);
|
||||
// The y coordinate of the points is in [0, 1)
|
||||
c = trainClass.colRange(1, 2);
|
||||
cData = new float[(int) (c.total() * c.channels())];
|
||||
cDataDbl = rng.doubles(cData.length, 0, height).toArray();
|
||||
for (int i = 0; i < cData.length; i++) {
|
||||
cData[i] = (float) cDataDbl[i];
|
||||
}
|
||||
c.put(0, 0, cData);
|
||||
|
||||
// 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);
|
||||
cData = new float[(int) (c.total() * c.channels())];
|
||||
cDataDbl = rng.doubles(cData.length, 0.6 * width, width).toArray();
|
||||
for (int i = 0; i < cData.length; i++) {
|
||||
cData[i] = (float) cDataDbl[i];
|
||||
}
|
||||
c.put(0, 0, cData);
|
||||
// The y coordinate of the points is in [0, 1)
|
||||
c = trainClass.colRange(1, 2);
|
||||
cData = new float[(int) (c.total() * c.channels())];
|
||||
cDataDbl = rng.doubles(cData.length, 0, height).toArray();
|
||||
for (int i = 0; i < cData.length; i++) {
|
||||
cData[i] = (float) cDataDbl[i];
|
||||
}
|
||||
c.put(0, 0, cData);
|
||||
//! [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);
|
||||
cData = new float[(int) (c.total() * c.channels())];
|
||||
cDataDbl = rng.doubles(cData.length, 0.4 * width, 0.6 * width).toArray();
|
||||
for (int i = 0; i < cData.length; i++) {
|
||||
cData[i] = (float) cDataDbl[i];
|
||||
}
|
||||
c.put(0, 0, cData);
|
||||
// The y coordinate of the points is in [0, 1)
|
||||
c = trainClass.colRange(1, 2);
|
||||
cData = new float[(int) (c.total() * c.channels())];
|
||||
cDataDbl = rng.doubles(cData.length, 0, height).toArray();
|
||||
for (int i = 0; i < cData.length; i++) {
|
||||
cData[i] = (float) cDataDbl[i];
|
||||
}
|
||||
c.put(0, 0, cData);
|
||||
//! [setup2]
|
||||
|
||||
// ------------------------- Set up the labels for the classes---------------------------------
|
||||
labels.rowRange(0, NTRAINING_SAMPLES).setTo(new Scalar(1)); // Class 1
|
||||
labels.rowRange(NTRAINING_SAMPLES, 2 * NTRAINING_SAMPLES).setTo(new Scalar(2)); // Class 2
|
||||
|
||||
// ------------------------ 2. Set up the support vector machines parameters--------------------
|
||||
System.out.println("Starting training process");
|
||||
//! [init]
|
||||
SVM svm = SVM.create();
|
||||
svm.setType(SVM.C_SVC);
|
||||
svm.setC(0.1);
|
||||
svm.setKernel(SVM.LINEAR);
|
||||
svm.setTermCriteria(new TermCriteria(TermCriteria.MAX_ITER, (int) 1e7, 1e-6));
|
||||
//! [init]
|
||||
|
||||
// ------------------------ 3. Train the svm----------------------------------------------------
|
||||
//! [train]
|
||||
svm.train(trainData, Ml.ROW_SAMPLE, labels);
|
||||
//! [train]
|
||||
System.out.println("Finished training process");
|
||||
|
||||
// ------------------------ 4. Show the decision regions----------------------------------------
|
||||
//! [show]
|
||||
byte[] IData = new byte[(int) (I.total() * I.channels())];
|
||||
Mat sampleMat = new Mat(1, 2, CvType.CV_32F);
|
||||
float[] sampleMatData = new float[(int) (sampleMat.total() * sampleMat.channels())];
|
||||
for (int i = 0; i < I.rows(); i++) {
|
||||
for (int j = 0; j < I.cols(); j++) {
|
||||
sampleMatData[0] = j;
|
||||
sampleMatData[1] = i;
|
||||
sampleMat.put(0, 0, sampleMatData);
|
||||
float response = svm.predict(sampleMat);
|
||||
|
||||
if (response == 1) {
|
||||
IData[(i * I.cols() + j) * I.channels()] = 0;
|
||||
IData[(i * I.cols() + j) * I.channels() + 1] = 100;
|
||||
IData[(i * I.cols() + j) * I.channels() + 2] = 0;
|
||||
} else if (response == 2) {
|
||||
IData[(i * I.cols() + j) * I.channels()] = 100;
|
||||
IData[(i * I.cols() + j) * I.channels() + 1] = 0;
|
||||
IData[(i * I.cols() + j) * I.channels() + 2] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
I.put(0, 0, IData);
|
||||
//! [show]
|
||||
|
||||
// ----------------------- 5. Show the training data--------------------------------------------
|
||||
//! [show_data]
|
||||
int thick = -1;
|
||||
int lineType = Imgproc.LINE_8;
|
||||
float px, py;
|
||||
// Class 1
|
||||
float[] trainDataData = new float[(int) (trainData.total() * trainData.channels())];
|
||||
trainData.get(0, 0, trainDataData);
|
||||
for (int i = 0; i < NTRAINING_SAMPLES; i++) {
|
||||
px = trainDataData[i * trainData.cols()];
|
||||
py = trainDataData[i * trainData.cols() + 1];
|
||||
Imgproc.circle(I, new Point(px, py), 3, new Scalar(0, 255, 0), thick, lineType, 0);
|
||||
}
|
||||
// Class 2
|
||||
for (int i = NTRAINING_SAMPLES; i < 2 * NTRAINING_SAMPLES; ++i) {
|
||||
px = trainDataData[i * trainData.cols()];
|
||||
py = trainDataData[i * trainData.cols() + 1];
|
||||
Imgproc.circle(I, new Point(px, py), 3, new Scalar(255, 0, 0), thick, lineType, 0);
|
||||
}
|
||||
//! [show_data]
|
||||
|
||||
// ------------------------- 6. Show support vectors--------------------------------------------
|
||||
//! [show_vectors]
|
||||
thick = 2;
|
||||
Mat sv = svm.getUncompressedSupportVectors();
|
||||
float[] svData = new float[(int) (sv.total() * sv.channels())];
|
||||
sv.get(0, 0, svData);
|
||||
for (int i = 0; i < sv.rows(); i++) {
|
||||
Imgproc.circle(I, new Point(svData[i * sv.cols()], svData[i * sv.cols() + 1]), 6, new Scalar(128, 128, 128),
|
||||
thick, lineType, 0);
|
||||
}
|
||||
//! [show_vectors]
|
||||
|
||||
Imgcodecs.imwrite("result.png", I); // save the Image
|
||||
HighGui.imshow("SVM for Non-Linear Training Data", I); // show it to the user
|
||||
HighGui.waitKey();
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,558 @@
|
||||
#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;
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
// 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;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
//#include <opencv2/ml/ml.hpp>
|
||||
#include <opencv2/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;
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
#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;
|
||||
}
|
||||
@@ -0,0 +1,399 @@
|
||||
#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;
|
||||
}
|
||||
Executable
+224
@@ -0,0 +1,224 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
'''
|
||||
This module contains some common routines used by other samples.
|
||||
'''
|
||||
|
||||
from functools import reduce
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
|
||||
# built-in modules
|
||||
import os
|
||||
import itertools as it
|
||||
from contextlib import contextmanager
|
||||
|
||||
image_extensions = ['.bmp', '.jpg', '.jpeg', '.png', '.tif', '.tiff', '.pbm', '.pgm', '.ppm']
|
||||
|
||||
class Bunch(object):
|
||||
def __init__(self, **kw):
|
||||
self.__dict__.update(kw)
|
||||
def __str__(self):
|
||||
return str(self.__dict__)
|
||||
|
||||
def splitfn(fn):
|
||||
path, fn = os.path.split(fn)
|
||||
name, ext = os.path.splitext(fn)
|
||||
return path, name, ext
|
||||
|
||||
def anorm2(a):
|
||||
return (a*a).sum(-1)
|
||||
def anorm(a):
|
||||
return np.sqrt( anorm2(a) )
|
||||
|
||||
def homotrans(H, x, y):
|
||||
xs = H[0, 0]*x + H[0, 1]*y + H[0, 2]
|
||||
ys = H[1, 0]*x + H[1, 1]*y + H[1, 2]
|
||||
s = H[2, 0]*x + H[2, 1]*y + H[2, 2]
|
||||
return xs/s, ys/s
|
||||
|
||||
def to_rect(a):
|
||||
a = np.ravel(a)
|
||||
if len(a) == 2:
|
||||
a = (0, 0, a[0], a[1])
|
||||
return np.array(a, np.float64).reshape(2, 2)
|
||||
|
||||
def rect2rect_mtx(src, dst):
|
||||
src, dst = to_rect(src), to_rect(dst)
|
||||
cx, cy = (dst[1] - dst[0]) / (src[1] - src[0])
|
||||
tx, ty = dst[0] - src[0] * (cx, cy)
|
||||
M = np.float64([[ cx, 0, tx],
|
||||
[ 0, cy, ty],
|
||||
[ 0, 0, 1]])
|
||||
return M
|
||||
|
||||
|
||||
def lookat(eye, target, up = (0, 0, 1)):
|
||||
fwd = np.asarray(target, np.float64) - eye
|
||||
fwd /= anorm(fwd)
|
||||
right = np.cross(fwd, up)
|
||||
right /= anorm(right)
|
||||
down = np.cross(fwd, right)
|
||||
R = np.float64([right, down, fwd])
|
||||
tvec = -np.dot(R, eye)
|
||||
return R, tvec
|
||||
|
||||
def mtx2rvec(R):
|
||||
w, u, vt = cv.SVDecomp(R - np.eye(3))
|
||||
p = vt[0] + u[:,0]*w[0] # same as np.dot(R, vt[0])
|
||||
c = np.dot(vt[0], p)
|
||||
s = np.dot(vt[1], p)
|
||||
axis = np.cross(vt[0], vt[1])
|
||||
return axis * np.arctan2(s, c)
|
||||
|
||||
def draw_str(dst, target, s):
|
||||
x, y = target
|
||||
cv.putText(dst, s, (x+1, y+1), cv.FONT_HERSHEY_PLAIN, 1.0, (0, 0, 0), thickness = 2, lineType=cv.LINE_AA)
|
||||
cv.putText(dst, s, (x, y), cv.FONT_HERSHEY_PLAIN, 1.0, (255, 255, 255), lineType=cv.LINE_AA)
|
||||
|
||||
class Sketcher:
|
||||
def __init__(self, windowname, dests, colors_func):
|
||||
self.prev_pt = None
|
||||
self.windowname = windowname
|
||||
self.dests = dests
|
||||
self.colors_func = colors_func
|
||||
self.dirty = False
|
||||
self.show()
|
||||
cv.setMouseCallback(self.windowname, self.on_mouse)
|
||||
|
||||
def show(self):
|
||||
cv.imshow(self.windowname, self.dests[0])
|
||||
|
||||
def on_mouse(self, event, x, y, flags, param):
|
||||
pt = (x, y)
|
||||
if event == cv.EVENT_LBUTTONDOWN:
|
||||
self.prev_pt = pt
|
||||
elif event == cv.EVENT_LBUTTONUP:
|
||||
self.prev_pt = None
|
||||
|
||||
if self.prev_pt and flags & cv.EVENT_FLAG_LBUTTON:
|
||||
for dst, color in zip(self.dests, self.colors_func()):
|
||||
cv.line(dst, self.prev_pt, pt, color, 5)
|
||||
self.dirty = True
|
||||
self.prev_pt = pt
|
||||
self.show()
|
||||
|
||||
|
||||
# palette data from matplotlib/_cm.py
|
||||
_jet_data = {'red': ((0., 0, 0), (0.35, 0, 0), (0.66, 1, 1), (0.89,1, 1),
|
||||
(1, 0.5, 0.5)),
|
||||
'green': ((0., 0, 0), (0.125,0, 0), (0.375,1, 1), (0.64,1, 1),
|
||||
(0.91,0,0), (1, 0, 0)),
|
||||
'blue': ((0., 0.5, 0.5), (0.11, 1, 1), (0.34, 1, 1), (0.65,0, 0),
|
||||
(1, 0, 0))}
|
||||
|
||||
cmap_data = { 'jet' : _jet_data }
|
||||
|
||||
def make_cmap(name, n=256):
|
||||
data = cmap_data[name]
|
||||
xs = np.linspace(0.0, 1.0, n)
|
||||
channels = []
|
||||
eps = 1e-6
|
||||
for ch_name in ['blue', 'green', 'red']:
|
||||
ch_data = data[ch_name]
|
||||
xp, yp = [], []
|
||||
for x, y1, y2 in ch_data:
|
||||
xp += [x, x+eps]
|
||||
yp += [y1, y2]
|
||||
ch = np.interp(xs, xp, yp)
|
||||
channels.append(ch)
|
||||
return np.uint8(np.array(channels).T*255)
|
||||
|
||||
def nothing(*arg, **kw):
|
||||
pass
|
||||
|
||||
def clock():
|
||||
return cv.getTickCount() / cv.getTickFrequency()
|
||||
|
||||
@contextmanager
|
||||
def Timer(msg):
|
||||
print(msg, '...',)
|
||||
start = clock()
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
print("%.2f ms" % ((clock()-start)*1000))
|
||||
|
||||
class StatValue:
|
||||
def __init__(self, smooth_coef = 0.5):
|
||||
self.value = None
|
||||
self.smooth_coef = smooth_coef
|
||||
def update(self, v):
|
||||
if self.value is None:
|
||||
self.value = v
|
||||
else:
|
||||
c = self.smooth_coef
|
||||
self.value = c * self.value + (1.0-c) * v
|
||||
|
||||
class RectSelector:
|
||||
def __init__(self, win, callback):
|
||||
self.win = win
|
||||
self.callback = callback
|
||||
cv.setMouseCallback(win, self.onmouse)
|
||||
self.drag_start = None
|
||||
self.drag_rect = None
|
||||
def onmouse(self, event, x, y, flags, param):
|
||||
x, y = np.int16([x, y]) # BUG
|
||||
if event == cv.EVENT_LBUTTONDOWN:
|
||||
self.drag_start = (x, y)
|
||||
return
|
||||
if self.drag_start:
|
||||
if flags & cv.EVENT_FLAG_LBUTTON:
|
||||
xo, yo = self.drag_start
|
||||
x0, y0 = np.minimum([xo, yo], [x, y])
|
||||
x1, y1 = np.maximum([xo, yo], [x, y])
|
||||
self.drag_rect = None
|
||||
if x1-x0 > 0 and y1-y0 > 0:
|
||||
self.drag_rect = (x0, y0, x1, y1)
|
||||
else:
|
||||
rect = self.drag_rect
|
||||
self.drag_start = None
|
||||
self.drag_rect = None
|
||||
if rect:
|
||||
self.callback(rect)
|
||||
def draw(self, vis):
|
||||
if not self.drag_rect:
|
||||
return False
|
||||
x0, y0, x1, y1 = self.drag_rect
|
||||
cv.rectangle(vis, (x0, y0), (x1, y1), (0, 255, 0), 2)
|
||||
return True
|
||||
@property
|
||||
def dragging(self):
|
||||
return self.drag_rect is not None
|
||||
|
||||
|
||||
def grouper(n, iterable, fillvalue=None):
|
||||
'''grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx'''
|
||||
args = [iter(iterable)] * n
|
||||
output = it.zip_longest(fillvalue=fillvalue, *args)
|
||||
return output
|
||||
|
||||
def mosaic(w, imgs):
|
||||
'''Make a grid from images.
|
||||
|
||||
w -- number of grid columns
|
||||
imgs -- images (must have same size and format)
|
||||
'''
|
||||
imgs = iter(imgs)
|
||||
img0 = next(imgs)
|
||||
pad = np.zeros_like(img0)
|
||||
imgs = it.chain([img0], imgs)
|
||||
rows = grouper(w, imgs, pad)
|
||||
return np.vstack(list(map(np.hstack, rows)))
|
||||
|
||||
def getsize(img):
|
||||
h, w = img.shape[:2]
|
||||
return w, h
|
||||
|
||||
def mdot(*args):
|
||||
return reduce(np.dot, args)
|
||||
|
||||
def draw_keypoints(vis, keypoints, color = (0, 255, 255)):
|
||||
for kp in keypoints:
|
||||
x, y = kp.pt
|
||||
cv.circle(vis, (int(x), int(y)), 2, color)
|
||||
Executable
+194
@@ -0,0 +1,194 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
'''
|
||||
SVM and KNearest digit recognition.
|
||||
|
||||
Sample loads a dataset of handwritten digits from 'digits.png'.
|
||||
Then it trains a SVM and KNearest classifiers on it and evaluates
|
||||
their accuracy.
|
||||
|
||||
Following preprocessing is applied to the dataset:
|
||||
- Moment-based image deskew (see deskew())
|
||||
- Digit images are split into 4 10x10 cells and 16-bin
|
||||
histogram of oriented gradients is computed for each
|
||||
cell
|
||||
- Transform histograms to space with Hellinger metric (see [1] (RootSIFT))
|
||||
|
||||
|
||||
[1] R. Arandjelovic, A. Zisserman
|
||||
"Three things everyone should know to improve object retrieval"
|
||||
http://www.robots.ox.ac.uk/~vgg/publications/2012/Arandjelovic12/arandjelovic12.pdf
|
||||
|
||||
Usage:
|
||||
digits.py
|
||||
'''
|
||||
|
||||
|
||||
# Python 2/3 compatibility
|
||||
from __future__ import print_function
|
||||
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
|
||||
# built-in modules
|
||||
from multiprocessing.pool import ThreadPool
|
||||
|
||||
from numpy.linalg import norm
|
||||
|
||||
# local modules
|
||||
from common import clock, mosaic
|
||||
|
||||
|
||||
|
||||
SZ = 20 # size of each digit is SZ x SZ
|
||||
CLASS_N = 10
|
||||
DIGITS_FN = 'digits.png'
|
||||
|
||||
def split2d(img, cell_size, flatten=True):
|
||||
h, w = img.shape[:2]
|
||||
sx, sy = cell_size
|
||||
cells = [np.hsplit(row, w//sx) for row in np.vsplit(img, h//sy)]
|
||||
cells = np.array(cells)
|
||||
if flatten:
|
||||
cells = cells.reshape(-1, sy, sx)
|
||||
return cells
|
||||
|
||||
def load_digits(fn):
|
||||
fn = cv.samples.findFile(fn)
|
||||
print('loading "%s" ...' % fn)
|
||||
digits_img = cv.imread(fn, cv.IMREAD_GRAYSCALE)
|
||||
digits = split2d(digits_img, (SZ, SZ))
|
||||
labels = np.repeat(np.arange(CLASS_N), len(digits)/CLASS_N)
|
||||
return digits, labels
|
||||
|
||||
def deskew(img):
|
||||
m = cv.moments(img)
|
||||
if abs(m['mu02']) < 1e-2:
|
||||
return img.copy()
|
||||
skew = m['mu11']/m['mu02']
|
||||
M = np.float32([[1, skew, -0.5*SZ*skew], [0, 1, 0]])
|
||||
img = cv.warpAffine(img, M, (SZ, SZ), flags=cv.WARP_INVERSE_MAP | cv.INTER_LINEAR)
|
||||
return img
|
||||
|
||||
|
||||
class KNearest(object):
|
||||
def __init__(self, k = 3):
|
||||
self.k = k
|
||||
self.model = cv.ml.KNearest_create()
|
||||
|
||||
def train(self, samples, responses):
|
||||
self.model.train(samples, cv.ml.ROW_SAMPLE, responses)
|
||||
|
||||
def predict(self, samples):
|
||||
_retval, results, _neigh_resp, _dists = self.model.findNearest(samples, self.k)
|
||||
return results.ravel()
|
||||
|
||||
def load(self, fn):
|
||||
self.model = cv.ml.KNearest_load(fn)
|
||||
|
||||
def save(self, fn):
|
||||
self.model.save(fn)
|
||||
|
||||
class SVM(object):
|
||||
def __init__(self, C = 1, gamma = 0.5):
|
||||
self.model = cv.ml.SVM_create()
|
||||
self.model.setGamma(gamma)
|
||||
self.model.setC(C)
|
||||
self.model.setKernel(cv.ml.SVM_RBF)
|
||||
self.model.setType(cv.ml.SVM_C_SVC)
|
||||
|
||||
def train(self, samples, responses):
|
||||
self.model.train(samples, cv.ml.ROW_SAMPLE, responses)
|
||||
|
||||
def predict(self, samples):
|
||||
return self.model.predict(samples)[1].ravel()
|
||||
|
||||
def load(self, fn):
|
||||
self.model = cv.ml.SVM_load(fn)
|
||||
|
||||
def save(self, fn):
|
||||
self.model.save(fn)
|
||||
|
||||
def evaluate_model(model, digits, samples, labels):
|
||||
resp = model.predict(samples)
|
||||
err = (labels != resp).mean()
|
||||
print('error: %.2f %%' % (err*100))
|
||||
|
||||
confusion = np.zeros((10, 10), np.int32)
|
||||
for i, j in zip(labels, resp):
|
||||
confusion[i, int(j)] += 1
|
||||
print('confusion matrix:')
|
||||
print(confusion)
|
||||
print()
|
||||
|
||||
vis = []
|
||||
for img, flag in zip(digits, resp == labels):
|
||||
img = cv.cvtColor(img, cv.COLOR_GRAY2BGR)
|
||||
if not flag:
|
||||
img[...,:2] = 0
|
||||
vis.append(img)
|
||||
return mosaic(25, vis)
|
||||
|
||||
def preprocess_simple(digits):
|
||||
return np.float32(digits).reshape(-1, SZ*SZ) / 255.0
|
||||
|
||||
def preprocess_hog(digits):
|
||||
samples = []
|
||||
for img in digits:
|
||||
gx = cv.Sobel(img, cv.CV_32F, 1, 0)
|
||||
gy = cv.Sobel(img, cv.CV_32F, 0, 1)
|
||||
mag, ang = cv.cartToPolar(gx, gy)
|
||||
bin_n = 16
|
||||
bin = np.int32(bin_n*ang/(2*np.pi))
|
||||
bin_cells = bin[:10,:10], bin[10:,:10], bin[:10,10:], bin[10:,10:]
|
||||
mag_cells = mag[:10,:10], mag[10:,:10], mag[:10,10:], mag[10:,10:]
|
||||
hists = [np.bincount(b.ravel(), m.ravel(), bin_n) for b, m in zip(bin_cells, mag_cells)]
|
||||
hist = np.hstack(hists)
|
||||
|
||||
# transform to Hellinger kernel
|
||||
eps = 1e-7
|
||||
hist /= hist.sum() + eps
|
||||
hist = np.sqrt(hist)
|
||||
hist /= norm(hist) + eps
|
||||
|
||||
samples.append(hist)
|
||||
return np.float32(samples)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print(__doc__)
|
||||
|
||||
digits, labels = load_digits(DIGITS_FN)
|
||||
|
||||
print('preprocessing...')
|
||||
# shuffle digits
|
||||
rand = np.random.RandomState(321)
|
||||
shuffle = rand.permutation(len(digits))
|
||||
digits, labels = digits[shuffle], labels[shuffle]
|
||||
|
||||
digits2 = list(map(deskew, digits))
|
||||
samples = preprocess_hog(digits2)
|
||||
|
||||
train_n = int(0.9*len(samples))
|
||||
cv.imshow('test set', mosaic(25, digits[train_n:]))
|
||||
digits_train, digits_test = np.split(digits2, [train_n])
|
||||
samples_train, samples_test = np.split(samples, [train_n])
|
||||
labels_train, labels_test = np.split(labels, [train_n])
|
||||
|
||||
|
||||
print('training KNearest...')
|
||||
model = KNearest(k=4)
|
||||
model.train(samples_train, labels_train)
|
||||
vis = evaluate_model(model, digits_test, samples_test, labels_test)
|
||||
cv.imshow('KNearest test', vis)
|
||||
|
||||
print('training SVM...')
|
||||
model = SVM(C=2.67, gamma=5.383)
|
||||
model.train(samples_train, labels_train)
|
||||
vis = evaluate_model(model, digits_test, samples_test, labels_test)
|
||||
cv.imshow('SVM test', vis)
|
||||
print('saving SVM as "digits_svm.dat"...')
|
||||
model.save('digits_svm.dat')
|
||||
|
||||
cv.waitKey(0)
|
||||
cv.destroyAllWindows()
|
||||
Executable
+132
@@ -0,0 +1,132 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
'''
|
||||
Digit recognition adjustment.
|
||||
Grid search is used to find the best parameters for SVM and KNearest classifiers.
|
||||
SVM adjustment follows the guidelines given in
|
||||
http://www.csie.ntu.edu.tw/~cjlin/papers/guide/guide.pdf
|
||||
|
||||
Usage:
|
||||
digits_adjust.py [--model {svm|knearest}]
|
||||
|
||||
--model {svm|knearest} - select the classifier (SVM is the default)
|
||||
|
||||
'''
|
||||
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
|
||||
from multiprocessing.pool import ThreadPool
|
||||
|
||||
from digits import *
|
||||
|
||||
def cross_validate(model_class, params, samples, labels, kfold = 3, pool = None):
|
||||
n = len(samples)
|
||||
folds = np.array_split(np.arange(n), kfold)
|
||||
def f(i):
|
||||
model = model_class(**params)
|
||||
test_idx = folds[i]
|
||||
train_idx = list(folds)
|
||||
train_idx.pop(i)
|
||||
train_idx = np.hstack(train_idx)
|
||||
train_samples, train_labels = samples[train_idx], labels[train_idx]
|
||||
test_samples, test_labels = samples[test_idx], labels[test_idx]
|
||||
model.train(train_samples, train_labels)
|
||||
resp = model.predict(test_samples)
|
||||
score = (resp != test_labels).mean()
|
||||
print(".", end='')
|
||||
return score
|
||||
if pool is None:
|
||||
scores = list(map(f, range(kfold)))
|
||||
else:
|
||||
scores = pool.map(f, range(kfold))
|
||||
return np.mean(scores)
|
||||
|
||||
|
||||
class App(object):
|
||||
def __init__(self):
|
||||
self._samples, self._labels = self.preprocess()
|
||||
|
||||
def preprocess(self):
|
||||
digits, labels = load_digits(DIGITS_FN)
|
||||
shuffle = np.random.permutation(len(digits))
|
||||
digits, labels = digits[shuffle], labels[shuffle]
|
||||
digits2 = list(map(deskew, digits))
|
||||
samples = preprocess_hog(digits2)
|
||||
return samples, labels
|
||||
|
||||
def get_dataset(self):
|
||||
return self._samples, self._labels
|
||||
|
||||
def run_jobs(self, f, jobs):
|
||||
pool = ThreadPool(processes=cv.getNumberOfCPUs())
|
||||
ires = pool.imap_unordered(f, jobs)
|
||||
return ires
|
||||
|
||||
def adjust_SVM(self):
|
||||
Cs = np.logspace(0, 10, 15, base=2)
|
||||
gammas = np.logspace(-7, 4, 15, base=2)
|
||||
scores = np.zeros((len(Cs), len(gammas)))
|
||||
scores[:] = np.nan
|
||||
|
||||
print('adjusting SVM (may take a long time) ...')
|
||||
def f(job):
|
||||
i, j = job
|
||||
samples, labels = self.get_dataset()
|
||||
params = dict(C = Cs[i], gamma=gammas[j])
|
||||
score = cross_validate(SVM, params, samples, labels)
|
||||
return i, j, score
|
||||
|
||||
ires = self.run_jobs(f, np.ndindex(*scores.shape))
|
||||
for count, (i, j, score) in enumerate(ires):
|
||||
scores[i, j] = score
|
||||
print('%d / %d (best error: %.2f %%, last: %.2f %%)' %
|
||||
(count+1, scores.size, np.nanmin(scores)*100, score*100))
|
||||
print(scores)
|
||||
|
||||
print('writing score table to "svm_scores.npz"')
|
||||
np.savez('svm_scores.npz', scores=scores, Cs=Cs, gammas=gammas)
|
||||
|
||||
i, j = np.unravel_index(scores.argmin(), scores.shape)
|
||||
best_params = dict(C = Cs[i], gamma=gammas[j])
|
||||
print('best params:', best_params)
|
||||
print('best error: %.2f %%' % (scores.min()*100))
|
||||
return best_params
|
||||
|
||||
def adjust_KNearest(self):
|
||||
print('adjusting KNearest ...')
|
||||
def f(k):
|
||||
samples, labels = self.get_dataset()
|
||||
err = cross_validate(KNearest, dict(k=k), samples, labels)
|
||||
return k, err
|
||||
best_err, best_k = np.inf, -1
|
||||
for k, err in self.run_jobs(f, range(1, 9)):
|
||||
if err < best_err:
|
||||
best_err, best_k = err, k
|
||||
print('k = %d, error: %.2f %%' % (k, err*100))
|
||||
best_params = dict(k=best_k)
|
||||
print('best params:', best_params, 'err: %.2f' % (best_err*100))
|
||||
return best_params
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import getopt
|
||||
import sys
|
||||
|
||||
print(__doc__)
|
||||
|
||||
args, _ = getopt.getopt(sys.argv[1:], '', ['model='])
|
||||
args = dict(args)
|
||||
args.setdefault('--model', 'svm')
|
||||
args.setdefault('--env', '')
|
||||
if args['--model'] not in ['svm', 'knearest']:
|
||||
print('unknown model "%s"' % args['--model'])
|
||||
sys.exit(1)
|
||||
|
||||
t = clock()
|
||||
app = App()
|
||||
if args['--model'] == 'knearest':
|
||||
app.adjust_KNearest()
|
||||
else:
|
||||
app.adjust_SVM()
|
||||
print('work time: %f s' % (clock() - t))
|
||||
Executable
+109
@@ -0,0 +1,109 @@
|
||||
#!/usr/bin/env python
|
||||
'''
|
||||
Digit recognition from video.
|
||||
|
||||
Run digits.py before, to train and save the SVM.
|
||||
|
||||
Usage:
|
||||
digits_video.py [{camera_id|video_file}]
|
||||
'''
|
||||
|
||||
# Python 2/3 compatibility
|
||||
from __future__ import print_function
|
||||
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
|
||||
# built-in modules
|
||||
import os
|
||||
import sys
|
||||
|
||||
# local modules
|
||||
import video
|
||||
from common import mosaic
|
||||
|
||||
from digits import *
|
||||
|
||||
def main():
|
||||
try:
|
||||
src = sys.argv[1]
|
||||
except:
|
||||
src = 0
|
||||
cap = video.create_capture(src, fallback='synth:bg={}:noise=0.05'.format(cv.samples.findFile('sudoku.png')))
|
||||
|
||||
classifier_fn = 'digits_svm.dat'
|
||||
if not os.path.exists(classifier_fn):
|
||||
print('"%s" not found, run digits.py first' % classifier_fn)
|
||||
return
|
||||
|
||||
model = cv.ml.SVM_load(classifier_fn)
|
||||
|
||||
while True:
|
||||
_ret, frame = cap.read()
|
||||
gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
|
||||
|
||||
|
||||
bin = cv.adaptiveThreshold(gray, 255, cv.ADAPTIVE_THRESH_MEAN_C, cv.THRESH_BINARY_INV, 31, 10)
|
||||
bin = cv.medianBlur(bin, 3)
|
||||
contours, heirs = cv.findContours( bin.copy(), cv.RETR_CCOMP, cv.CHAIN_APPROX_SIMPLE)
|
||||
try:
|
||||
heirs = heirs[0]
|
||||
except:
|
||||
heirs = []
|
||||
|
||||
for cnt, heir in zip(contours, heirs):
|
||||
_, _, _, outer_i = heir
|
||||
if outer_i >= 0:
|
||||
continue
|
||||
x, y, w, h = cv.boundingRect(cnt)
|
||||
if not (16 <= h <= 64 and w <= 1.2*h):
|
||||
continue
|
||||
pad = max(h-w, 0)
|
||||
x, w = x - (pad // 2), w + pad
|
||||
cv.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0))
|
||||
|
||||
bin_roi = bin[y:,x:][:h,:w]
|
||||
|
||||
m = bin_roi != 0
|
||||
if not 0.1 < m.mean() < 0.4:
|
||||
continue
|
||||
'''
|
||||
gray_roi = gray[y:,x:][:h,:w]
|
||||
v_in, v_out = gray_roi[m], gray_roi[~m]
|
||||
if v_out.std() > 10.0:
|
||||
continue
|
||||
s = "%f, %f" % (abs(v_in.mean() - v_out.mean()), v_out.std())
|
||||
cv.putText(frame, s, (x, y), cv.FONT_HERSHEY_PLAIN, 1.0, (200, 0, 0), thickness = 1)
|
||||
'''
|
||||
|
||||
s = 1.5*float(h)/SZ
|
||||
m = cv.moments(bin_roi)
|
||||
c1 = np.float32([m['m10'], m['m01']]) / m['m00']
|
||||
c0 = np.float32([SZ/2, SZ/2])
|
||||
t = c1 - s*c0
|
||||
A = np.zeros((2, 3), np.float32)
|
||||
A[:,:2] = np.eye(2)*s
|
||||
A[:,2] = t
|
||||
bin_norm = cv.warpAffine(bin_roi, A, (SZ, SZ), flags=cv.WARP_INVERSE_MAP | cv.INTER_LINEAR)
|
||||
bin_norm = deskew(bin_norm)
|
||||
if x+w+SZ < frame.shape[1] and y+SZ < frame.shape[0]:
|
||||
frame[y:,x+w:][:SZ, :SZ] = bin_norm[...,np.newaxis]
|
||||
|
||||
sample = preprocess_hog([bin_norm])
|
||||
digit = model.predict(sample)[1].ravel()
|
||||
cv.putText(frame, '%d'%digit, (x, y), cv.FONT_HERSHEY_PLAIN, 1.0, (200, 0, 0), thickness = 1)
|
||||
|
||||
|
||||
cv.imshow('frame', frame)
|
||||
cv.imshow('bin', bin)
|
||||
ch = cv.waitKey(1)
|
||||
if ch == 27:
|
||||
break
|
||||
|
||||
print('Done')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print(__doc__)
|
||||
main()
|
||||
cv.destroyAllWindows()
|
||||
Executable
+69
@@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
|
||||
from numpy import random
|
||||
|
||||
def make_gaussians(cluster_n, img_size):
|
||||
points = []
|
||||
ref_distrs = []
|
||||
for _i in range(cluster_n):
|
||||
mean = (0.1 + 0.8*random.rand(2)) * img_size
|
||||
a = (random.rand(2, 2)-0.5)*img_size*0.1
|
||||
cov = np.dot(a.T, a) + img_size*0.05*np.eye(2)
|
||||
n = 100 + random.randint(900)
|
||||
pts = random.multivariate_normal(mean, cov, n)
|
||||
points.append( pts )
|
||||
ref_distrs.append( (mean, cov) )
|
||||
points = np.float32( np.vstack(points) )
|
||||
return points, ref_distrs
|
||||
|
||||
def draw_gaussain(img, mean, cov, color):
|
||||
x, y = mean
|
||||
w, u, _vt = cv.SVDecomp(cov)
|
||||
ang = np.arctan2(u[1, 0], u[0, 0])*(180/np.pi)
|
||||
s1, s2 = np.sqrt(w)*3.0
|
||||
cv.ellipse(img, (int(x), int(y)), (int(s1), int(s2)), ang, 0, 360, color, 1, cv.LINE_AA)
|
||||
|
||||
|
||||
def main():
|
||||
cluster_n = 5
|
||||
img_size = 512
|
||||
|
||||
print('press any key to update distributions, ESC - exit\n')
|
||||
|
||||
while True:
|
||||
print('sampling distributions...')
|
||||
points, ref_distrs = make_gaussians(cluster_n, img_size)
|
||||
|
||||
print('EM (opencv) ...')
|
||||
em = cv.ml.EM_create()
|
||||
em.setClustersNumber(cluster_n)
|
||||
em.setCovarianceMatrixType(cv.ml.EM_COV_MAT_GENERIC)
|
||||
em.trainEM(points)
|
||||
means = em.getMeans()
|
||||
covs = em.getCovs() # Known bug: https://github.com/opencv/opencv/pull/4232
|
||||
found_distrs = zip(means, covs)
|
||||
print('ready!\n')
|
||||
|
||||
img = np.zeros((img_size, img_size, 3), np.uint8)
|
||||
for x, y in np.int32(points):
|
||||
cv.circle(img, (x, y), 1, (255, 255, 255), -1)
|
||||
for m, cov in ref_distrs:
|
||||
draw_gaussain(img, m, cov, (0, 255, 0))
|
||||
for m, cov in found_distrs:
|
||||
draw_gaussain(img, m, cov, (0, 0, 255))
|
||||
|
||||
cv.imshow('gaussian mixture', img)
|
||||
ch = cv.waitKey(0)
|
||||
if ch == 27:
|
||||
break
|
||||
|
||||
print('Done')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print(__doc__)
|
||||
main()
|
||||
cv.destroyAllWindows()
|
||||
Executable
+194
@@ -0,0 +1,194 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
'''
|
||||
The sample demonstrates how to train Random Trees classifier
|
||||
(or Boosting classifier, or MLP, or Knearest, or Support Vector Machines) using the provided dataset.
|
||||
|
||||
We use the sample database letter-recognition.data
|
||||
from UCI Repository, here is the link:
|
||||
|
||||
Newman, D.J. & Hettich, S. & Blake, C.L. & Merz, C.J. (1998).
|
||||
UCI Repository of machine learning databases
|
||||
[http://www.ics.uci.edu/~mlearn/MLRepository.html].
|
||||
Irvine, CA: University of California, Department of Information and Computer Science.
|
||||
|
||||
The dataset consists of 20000 feature vectors along with the
|
||||
responses - capital latin letters A..Z.
|
||||
The first 10000 samples are used for training
|
||||
and the remaining 10000 - to test the classifier.
|
||||
======================================================
|
||||
USAGE:
|
||||
letter_recog.py [--model <model>]
|
||||
[--data <data fn>]
|
||||
[--load <model fn>] [--save <model fn>]
|
||||
|
||||
Models: RTrees, KNearest, Boost, SVM, MLP
|
||||
'''
|
||||
|
||||
# Python 2/3 compatibility
|
||||
from __future__ import print_function
|
||||
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
|
||||
def load_base(fn):
|
||||
a = np.loadtxt(fn, np.float32, delimiter=',', converters={ 0 : lambda ch : ord(ch)-ord('A') })
|
||||
samples, responses = a[:,1:], a[:,0]
|
||||
return samples, responses
|
||||
|
||||
class LetterStatModel(object):
|
||||
class_n = 26
|
||||
train_ratio = 0.5
|
||||
|
||||
def load(self, fn):
|
||||
self.model = self.model.load(fn)
|
||||
def save(self, fn):
|
||||
self.model.save(fn)
|
||||
|
||||
def unroll_samples(self, samples):
|
||||
sample_n, var_n = samples.shape
|
||||
new_samples = np.zeros((sample_n * self.class_n, var_n+1), np.float32)
|
||||
new_samples[:,:-1] = np.repeat(samples, self.class_n, axis=0)
|
||||
new_samples[:,-1] = np.tile(np.arange(self.class_n), sample_n)
|
||||
return new_samples
|
||||
|
||||
def unroll_responses(self, responses):
|
||||
sample_n = len(responses)
|
||||
new_responses = np.zeros(sample_n*self.class_n, np.int32)
|
||||
resp_idx = np.int32( responses + np.arange(sample_n)*self.class_n )
|
||||
new_responses[resp_idx] = 1
|
||||
return new_responses
|
||||
|
||||
class RTrees(LetterStatModel):
|
||||
def __init__(self):
|
||||
self.model = cv.ml.RTrees_create()
|
||||
|
||||
def train(self, samples, responses):
|
||||
self.model.setMaxDepth(20)
|
||||
self.model.train(samples, cv.ml.ROW_SAMPLE, responses.astype(int))
|
||||
|
||||
def predict(self, samples):
|
||||
_ret, resp = self.model.predict(samples)
|
||||
return resp.ravel()
|
||||
|
||||
|
||||
class KNearest(LetterStatModel):
|
||||
def __init__(self):
|
||||
self.model = cv.ml.KNearest_create()
|
||||
|
||||
def train(self, samples, responses):
|
||||
self.model.train(samples, cv.ml.ROW_SAMPLE, responses)
|
||||
|
||||
def predict(self, samples):
|
||||
_retval, results, _neigh_resp, _dists = self.model.findNearest(samples, k = 10)
|
||||
return results.ravel()
|
||||
|
||||
|
||||
class Boost(LetterStatModel):
|
||||
def __init__(self):
|
||||
self.model = cv.ml.Boost_create()
|
||||
|
||||
def train(self, samples, responses):
|
||||
_sample_n, var_n = samples.shape
|
||||
new_samples = self.unroll_samples(samples)
|
||||
new_responses = self.unroll_responses(responses)
|
||||
var_types = np.array([cv.ml.VAR_NUMERICAL] * var_n + [cv.ml.VAR_CATEGORICAL, cv.ml.VAR_CATEGORICAL], np.uint8)
|
||||
|
||||
self.model.setWeakCount(15)
|
||||
self.model.setMaxDepth(10)
|
||||
self.model.train(cv.ml.TrainData_create(new_samples, cv.ml.ROW_SAMPLE, new_responses.astype(int), varType = var_types))
|
||||
|
||||
def predict(self, samples):
|
||||
new_samples = self.unroll_samples(samples)
|
||||
_ret, resp = self.model.predict(new_samples)
|
||||
|
||||
return resp.ravel().reshape(-1, self.class_n).argmax(1)
|
||||
|
||||
|
||||
class SVM(LetterStatModel):
|
||||
def __init__(self):
|
||||
self.model = cv.ml.SVM_create()
|
||||
|
||||
def train(self, samples, responses):
|
||||
self.model.setType(cv.ml.SVM_C_SVC)
|
||||
self.model.setC(1)
|
||||
self.model.setKernel(cv.ml.SVM_RBF)
|
||||
self.model.setGamma(.1)
|
||||
self.model.train(samples, cv.ml.ROW_SAMPLE, responses.astype(int))
|
||||
|
||||
def predict(self, samples):
|
||||
_ret, resp = self.model.predict(samples)
|
||||
return resp.ravel()
|
||||
|
||||
|
||||
class MLP(LetterStatModel):
|
||||
def __init__(self):
|
||||
self.model = cv.ml.ANN_MLP_create()
|
||||
|
||||
def train(self, samples, responses):
|
||||
_sample_n, var_n = samples.shape
|
||||
new_responses = self.unroll_responses(responses).reshape(-1, self.class_n)
|
||||
layer_sizes = np.int32([var_n, 100, 100, self.class_n])
|
||||
|
||||
self.model.setLayerSizes(layer_sizes)
|
||||
self.model.setTrainMethod(cv.ml.ANN_MLP_BACKPROP)
|
||||
self.model.setBackpropMomentumScale(0.0)
|
||||
self.model.setBackpropWeightScale(0.001)
|
||||
self.model.setTermCriteria((cv.TERM_CRITERIA_COUNT, 20, 0.01))
|
||||
self.model.setActivationFunction(cv.ml.ANN_MLP_SIGMOID_SYM, 2, 1)
|
||||
|
||||
self.model.train(samples, cv.ml.ROW_SAMPLE, np.float32(new_responses))
|
||||
|
||||
def predict(self, samples):
|
||||
_ret, resp = self.model.predict(samples)
|
||||
return resp.argmax(-1)
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
import getopt
|
||||
import sys
|
||||
|
||||
models = [RTrees, KNearest, Boost, SVM, MLP] # NBayes
|
||||
models = dict( [(cls.__name__.lower(), cls) for cls in models] )
|
||||
|
||||
|
||||
args, dummy = getopt.getopt(sys.argv[1:], '', ['model=', 'data=', 'load=', 'save='])
|
||||
args = dict(args)
|
||||
args.setdefault('--model', 'svm')
|
||||
args.setdefault('--data', 'letter-recognition.data')
|
||||
|
||||
datafile = cv.samples.findFile(args['--data'])
|
||||
|
||||
print('loading data %s ...' % datafile)
|
||||
samples, responses = load_base(datafile)
|
||||
Model = models[args['--model']]
|
||||
model = Model()
|
||||
|
||||
train_n = int(len(samples)*model.train_ratio)
|
||||
if '--load' in args:
|
||||
fn = args['--load']
|
||||
print('loading model from %s ...' % fn)
|
||||
model.load(fn)
|
||||
else:
|
||||
print('training %s ...' % Model.__name__)
|
||||
model.train(samples[:train_n], responses[:train_n])
|
||||
|
||||
print('testing...')
|
||||
train_rate = np.mean(model.predict(samples[:train_n]) == responses[:train_n].astype(int))
|
||||
test_rate = np.mean(model.predict(samples[train_n:]) == responses[train_n:].astype(int))
|
||||
|
||||
print('train rate: %f test rate: %f' % (train_rate*100, test_rate*100))
|
||||
|
||||
if '--save' in args:
|
||||
fn = args['--save']
|
||||
print('saving model to %s ...' % fn)
|
||||
model.save(fn)
|
||||
|
||||
print('Done')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print(__doc__)
|
||||
main()
|
||||
cv.destroyAllWindows()
|
||||
@@ -0,0 +1,121 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
|
||||
# Python 2/3 compatibility
|
||||
from __future__ import print_function
|
||||
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
|
||||
from numpy import pi, sin, cos
|
||||
|
||||
|
||||
defaultSize = 512
|
||||
|
||||
class TestSceneRender():
|
||||
|
||||
def __init__(self, bgImg = None, fgImg = None,
|
||||
deformation = False, speed = 0.25, **params):
|
||||
self.time = 0.0
|
||||
self.timeStep = 1.0 / 30.0
|
||||
self.foreground = fgImg
|
||||
self.deformation = deformation
|
||||
self.speed = speed
|
||||
|
||||
if bgImg is not None:
|
||||
self.sceneBg = bgImg.copy()
|
||||
else:
|
||||
self.sceneBg = np.zeros((defaultSize, defaultSize,3), np.uint8)
|
||||
|
||||
self.w = self.sceneBg.shape[0]
|
||||
self.h = self.sceneBg.shape[1]
|
||||
|
||||
if fgImg is not None:
|
||||
self.foreground = fgImg.copy()
|
||||
self.center = self.currentCenter = (int(self.w/2 - fgImg.shape[0]/2), int(self.h/2 - fgImg.shape[1]/2))
|
||||
|
||||
self.xAmpl = self.sceneBg.shape[0] - (self.center[0] + fgImg.shape[0])
|
||||
self.yAmpl = self.sceneBg.shape[1] - (self.center[1] + fgImg.shape[1])
|
||||
|
||||
self.initialRect = np.array([ (self.h/2, self.w/2), (self.h/2, self.w/2 + self.w/10),
|
||||
(self.h/2 + self.h/10, self.w/2 + self.w/10), (self.h/2 + self.h/10, self.w/2)]).astype(int)
|
||||
self.currentRect = self.initialRect
|
||||
|
||||
def getXOffset(self, time):
|
||||
return int( self.xAmpl*cos(time*self.speed))
|
||||
|
||||
|
||||
def getYOffset(self, time):
|
||||
return int(self.yAmpl*sin(time*self.speed))
|
||||
|
||||
def setInitialRect(self, rect):
|
||||
self.initialRect = rect
|
||||
|
||||
def getRectInTime(self, time):
|
||||
|
||||
if self.foreground is not None:
|
||||
tmp = np.array(self.center) + np.array((self.getXOffset(time), self.getYOffset(time)))
|
||||
x0, y0 = tmp
|
||||
x1, y1 = tmp + self.foreground.shape[0:2]
|
||||
return np.array([y0, x0, y1, x1])
|
||||
else:
|
||||
x0, y0 = self.initialRect[0] + np.array((self.getXOffset(time), self.getYOffset(time)))
|
||||
x1, y1 = self.initialRect[2] + np.array((self.getXOffset(time), self.getYOffset(time)))
|
||||
return np.array([y0, x0, y1, x1])
|
||||
|
||||
def getCurrentRect(self):
|
||||
|
||||
if self.foreground is not None:
|
||||
|
||||
x0 = self.currentCenter[0]
|
||||
y0 = self.currentCenter[1]
|
||||
x1 = self.currentCenter[0] + self.foreground.shape[0]
|
||||
y1 = self.currentCenter[1] + self.foreground.shape[1]
|
||||
return np.array([y0, x0, y1, x1])
|
||||
else:
|
||||
x0, y0 = self.currentRect[0]
|
||||
x1, y1 = self.currentRect[2]
|
||||
return np.array([x0, y0, x1, y1])
|
||||
|
||||
def getNextFrame(self):
|
||||
img = self.sceneBg.copy()
|
||||
|
||||
if self.foreground is not None:
|
||||
self.currentCenter = (self.center[0] + self.getXOffset(self.time), self.center[1] + self.getYOffset(self.time))
|
||||
img[self.currentCenter[0]:self.currentCenter[0]+self.foreground.shape[0],
|
||||
self.currentCenter[1]:self.currentCenter[1]+self.foreground.shape[1]] = self.foreground
|
||||
else:
|
||||
self.currentRect = self.initialRect + int( 30*cos(self.time*self.speed) + 50*sin(self.time*self.speed))
|
||||
if self.deformation:
|
||||
self.currentRect[1:3] += int(self.h/20*cos(self.time))
|
||||
cv.fillConvexPoly(img, self.currentRect, (0, 0, 255))
|
||||
|
||||
self.time += self.timeStep
|
||||
return img
|
||||
|
||||
def resetTime(self):
|
||||
self.time = 0.0
|
||||
|
||||
|
||||
def main():
|
||||
backGr = cv.imread(cv.samples.findFile('graf1.png'))
|
||||
fgr = cv.imread(cv.samples.findFile('box.png'))
|
||||
|
||||
render = TestSceneRender(backGr, fgr)
|
||||
|
||||
while True:
|
||||
|
||||
img = render.getNextFrame()
|
||||
cv.imshow('img', img)
|
||||
|
||||
ch = cv.waitKey(3)
|
||||
if ch == 27:
|
||||
break
|
||||
|
||||
print('Done')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print(__doc__)
|
||||
main()
|
||||
cv.destroyAllWindows()
|
||||
@@ -0,0 +1,62 @@
|
||||
import cv2 as cv
|
||||
import numpy as np
|
||||
|
||||
# Set up training data
|
||||
## [setup1]
|
||||
labels = np.array([1, -1, -1, -1])
|
||||
trainingData = np.matrix([[501, 10], [255, 10], [501, 255], [10, 501]], dtype=np.float32)
|
||||
## [setup1]
|
||||
|
||||
# Train the SVM
|
||||
## [init]
|
||||
svm = cv.ml.SVM_create()
|
||||
svm.setType(cv.ml.SVM_C_SVC)
|
||||
svm.setKernel(cv.ml.SVM_LINEAR)
|
||||
svm.setTermCriteria((cv.TERM_CRITERIA_MAX_ITER, 100, 1e-6))
|
||||
## [init]
|
||||
## [train]
|
||||
svm.train(trainingData, cv.ml.ROW_SAMPLE, labels)
|
||||
## [train]
|
||||
|
||||
# Data for visual representation
|
||||
width = 512
|
||||
height = 512
|
||||
image = np.zeros((height, width, 3), dtype=np.uint8)
|
||||
|
||||
# Show the decision regions given by the SVM
|
||||
## [show]
|
||||
green = (0,255,0)
|
||||
blue = (255,0,0)
|
||||
for i in range(image.shape[0]):
|
||||
for j in range(image.shape[1]):
|
||||
sampleMat = np.matrix([[j,i]], dtype=np.float32)
|
||||
response = svm.predict(sampleMat)[1]
|
||||
|
||||
if response == 1:
|
||||
image[i,j] = green
|
||||
elif response == -1:
|
||||
image[i,j] = blue
|
||||
## [show]
|
||||
|
||||
# Show the training data
|
||||
## [show_data]
|
||||
thickness = -1
|
||||
cv.circle(image, (501, 10), 5, ( 0, 0, 0), thickness)
|
||||
cv.circle(image, (255, 10), 5, (255, 255, 255), thickness)
|
||||
cv.circle(image, (501, 255), 5, (255, 255, 255), thickness)
|
||||
cv.circle(image, ( 10, 501), 5, (255, 255, 255), thickness)
|
||||
## [show_data]
|
||||
|
||||
# Show support vectors
|
||||
## [show_vectors]
|
||||
thickness = 2
|
||||
sv = svm.getUncompressedSupportVectors()
|
||||
|
||||
for i in range(sv.shape[0]):
|
||||
cv.circle(image, (int(sv[i,0]), int(sv[i,1])), 6, (128, 128, 128), thickness)
|
||||
## [show_vectors]
|
||||
|
||||
cv.imwrite('result.png', image) # save the image
|
||||
|
||||
cv.imshow('SVM Simple Example', image) # show it to the user
|
||||
cv.waitKey()
|
||||
@@ -0,0 +1,117 @@
|
||||
from __future__ import print_function
|
||||
import cv2 as cv
|
||||
import numpy as np
|
||||
import random as rng
|
||||
|
||||
NTRAINING_SAMPLES = 100 # Number of training samples per class
|
||||
FRAC_LINEAR_SEP = 0.9 # Fraction of samples which compose the linear separable part
|
||||
|
||||
# Data for visual representation
|
||||
WIDTH = 512
|
||||
HEIGHT = 512
|
||||
I = np.zeros((HEIGHT, WIDTH, 3), dtype=np.uint8)
|
||||
|
||||
# --------------------- 1. Set up training data randomly ---------------------------------------
|
||||
trainData = np.empty((2*NTRAINING_SAMPLES, 2), dtype=np.float32)
|
||||
labels = np.empty((2*NTRAINING_SAMPLES, 1), dtype=np.int32)
|
||||
|
||||
rng.seed(100) # Random value generation class
|
||||
|
||||
# Set up the linearly separable part of the training data
|
||||
nLinearSamples = int(FRAC_LINEAR_SEP * NTRAINING_SAMPLES)
|
||||
|
||||
## [setup1]
|
||||
# Generate random points for the class 1
|
||||
trainClass = trainData[0:nLinearSamples,:]
|
||||
# The x coordinate of the points is in [0, 0.4)
|
||||
c = trainClass[:,0:1]
|
||||
c[:] = np.random.uniform(0.0, 0.4 * WIDTH, c.shape)
|
||||
# The y coordinate of the points is in [0, 1)
|
||||
c = trainClass[:,1:2]
|
||||
c[:] = np.random.uniform(0.0, HEIGHT, c.shape)
|
||||
|
||||
# Generate random points for the class 2
|
||||
trainClass = trainData[2*NTRAINING_SAMPLES-nLinearSamples:2*NTRAINING_SAMPLES,:]
|
||||
# The x coordinate of the points is in [0.6, 1]
|
||||
c = trainClass[:,0:1]
|
||||
c[:] = np.random.uniform(0.6*WIDTH, WIDTH, c.shape)
|
||||
# The y coordinate of the points is in [0, 1)
|
||||
c = trainClass[:,1:2]
|
||||
c[:] = np.random.uniform(0.0, HEIGHT, c.shape)
|
||||
## [setup1]
|
||||
|
||||
#------------------ Set up the non-linearly separable part of the training data ---------------
|
||||
## [setup2]
|
||||
# Generate random points for the classes 1 and 2
|
||||
trainClass = trainData[nLinearSamples:2*NTRAINING_SAMPLES-nLinearSamples,:]
|
||||
# The x coordinate of the points is in [0.4, 0.6)
|
||||
c = trainClass[:,0:1]
|
||||
c[:] = np.random.uniform(0.4*WIDTH, 0.6*WIDTH, c.shape)
|
||||
# The y coordinate of the points is in [0, 1)
|
||||
c = trainClass[:,1:2]
|
||||
c[:] = np.random.uniform(0.0, HEIGHT, c.shape)
|
||||
## [setup2]
|
||||
|
||||
#------------------------- Set up the labels for the classes ---------------------------------
|
||||
labels[0:NTRAINING_SAMPLES,:] = 1 # Class 1
|
||||
labels[NTRAINING_SAMPLES:2*NTRAINING_SAMPLES,:] = 2 # Class 2
|
||||
|
||||
#------------------------ 2. Set up the support vector machines parameters --------------------
|
||||
print('Starting training process')
|
||||
## [init]
|
||||
svm = cv.ml.SVM_create()
|
||||
svm.setType(cv.ml.SVM_C_SVC)
|
||||
svm.setC(0.1)
|
||||
svm.setKernel(cv.ml.SVM_LINEAR)
|
||||
svm.setTermCriteria((cv.TERM_CRITERIA_MAX_ITER, int(1e7), 1e-6))
|
||||
## [init]
|
||||
|
||||
#------------------------ 3. Train the svm ----------------------------------------------------
|
||||
## [train]
|
||||
svm.train(trainData, cv.ml.ROW_SAMPLE, labels)
|
||||
## [train]
|
||||
print('Finished training process')
|
||||
|
||||
#------------------------ 4. Show the decision regions ----------------------------------------
|
||||
## [show]
|
||||
green = (0,100,0)
|
||||
blue = (100,0,0)
|
||||
for i in range(I.shape[0]):
|
||||
for j in range(I.shape[1]):
|
||||
sampleMat = np.matrix([[j,i]], dtype=np.float32)
|
||||
response = svm.predict(sampleMat)[1]
|
||||
|
||||
if response == 1:
|
||||
I[i,j] = green
|
||||
elif response == 2:
|
||||
I[i,j] = blue
|
||||
## [show]
|
||||
|
||||
#----------------------- 5. Show the training data --------------------------------------------
|
||||
## [show_data]
|
||||
thick = -1
|
||||
# Class 1
|
||||
for i in range(NTRAINING_SAMPLES):
|
||||
px = trainData[i,0]
|
||||
py = trainData[i,1]
|
||||
cv.circle(I, (int(px), int(py)), 3, (0, 255, 0), thick)
|
||||
|
||||
# Class 2
|
||||
for i in range(NTRAINING_SAMPLES, 2*NTRAINING_SAMPLES):
|
||||
px = trainData[i,0]
|
||||
py = trainData[i,1]
|
||||
cv.circle(I, (int(px), int(py)), 3, (255, 0, 0), thick)
|
||||
## [show_data]
|
||||
|
||||
#------------------------- 6. Show support vectors --------------------------------------------
|
||||
## [show_vectors]
|
||||
thick = 2
|
||||
sv = svm.getUncompressedSupportVectors()
|
||||
|
||||
for i in range(sv.shape[0]):
|
||||
cv.circle(I, (int(sv[i,0]), int(sv[i,1])), 6, (128, 128, 128), thick)
|
||||
## [show_vectors]
|
||||
|
||||
cv.imwrite('result.png', I) # save the Image
|
||||
cv.imshow('SVM for Non-Linear Training Data', I) # show it to the user
|
||||
cv.waitKey()
|
||||
@@ -0,0 +1,73 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import cv2 as cv
|
||||
import numpy as np
|
||||
|
||||
SZ=20
|
||||
bin_n = 16 # Number of bins
|
||||
|
||||
|
||||
affine_flags = cv.WARP_INVERSE_MAP|cv.INTER_LINEAR
|
||||
|
||||
## [deskew]
|
||||
def deskew(img):
|
||||
m = cv.moments(img)
|
||||
if abs(m['mu02']) < 1e-2:
|
||||
return img.copy()
|
||||
skew = m['mu11']/m['mu02']
|
||||
M = np.float32([[1, skew, -0.5*SZ*skew], [0, 1, 0]])
|
||||
img = cv.warpAffine(img,M,(SZ, SZ),flags=affine_flags)
|
||||
return img
|
||||
## [deskew]
|
||||
|
||||
## [hog]
|
||||
def hog(img):
|
||||
gx = cv.Sobel(img, cv.CV_32F, 1, 0)
|
||||
gy = cv.Sobel(img, cv.CV_32F, 0, 1)
|
||||
mag, ang = cv.cartToPolar(gx, gy)
|
||||
bins = np.int32(bin_n*ang/(2*np.pi)) # quantizing binvalues in (0...16)
|
||||
bin_cells = bins[:10,:10], bins[10:,:10], bins[:10,10:], bins[10:,10:]
|
||||
mag_cells = mag[:10,:10], mag[10:,:10], mag[:10,10:], mag[10:,10:]
|
||||
hists = [np.bincount(b.ravel(), m.ravel(), bin_n) for b, m in zip(bin_cells, mag_cells)]
|
||||
hist = np.hstack(hists) # hist is a 64 bit vector
|
||||
return hist
|
||||
## [hog]
|
||||
|
||||
img = cv.imread(cv.samples.findFile('digits.png'),0)
|
||||
if img is None:
|
||||
raise Exception("we need the digits.png image from samples/data here !")
|
||||
|
||||
|
||||
cells = [np.hsplit(row,100) for row in np.vsplit(img,50)]
|
||||
|
||||
# First half is trainData, remaining is testData
|
||||
train_cells = [ i[:50] for i in cells ]
|
||||
test_cells = [ i[50:] for i in cells]
|
||||
|
||||
###### Now training ########################
|
||||
|
||||
deskewed = [list(map(deskew,row)) for row in train_cells]
|
||||
hogdata = [list(map(hog,row)) for row in deskewed]
|
||||
trainData = np.float32(hogdata).reshape(-1,64)
|
||||
responses = np.repeat(np.arange(10),250)[:,np.newaxis]
|
||||
|
||||
svm = cv.ml.SVM_create()
|
||||
svm.setKernel(cv.ml.SVM_LINEAR)
|
||||
svm.setType(cv.ml.SVM_C_SVC)
|
||||
svm.setC(2.67)
|
||||
svm.setGamma(5.383)
|
||||
|
||||
svm.train(trainData, cv.ml.ROW_SAMPLE, responses)
|
||||
svm.save('svm_data.dat')
|
||||
|
||||
###### Now testing ########################
|
||||
|
||||
deskewed = [list(map(deskew,row)) for row in test_cells]
|
||||
hogdata = [list(map(hog,row)) for row in deskewed]
|
||||
testData = np.float32(hogdata).reshape(-1,bin_n*4)
|
||||
result = svm.predict(testData)[1]
|
||||
|
||||
####### Check Accuracy ########################
|
||||
mask = result==responses
|
||||
correct = np.count_nonzero(mask)
|
||||
print(correct*100.0/result.size)
|
||||
Executable
+228
@@ -0,0 +1,228 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
'''
|
||||
Video capture sample.
|
||||
|
||||
Sample shows how VideoCapture class can be used to acquire video
|
||||
frames from a camera of a movie file. Also the sample provides
|
||||
an example of procedural video generation by an object, mimicking
|
||||
the VideoCapture interface (see Chess class).
|
||||
|
||||
'create_capture' is a convenience function for capture creation,
|
||||
falling back to procedural video in case of error.
|
||||
|
||||
Usage:
|
||||
video.py [--shotdir <shot path>] [source0] [source1] ...'
|
||||
|
||||
sourceN is an
|
||||
- integer number for camera capture
|
||||
- name of video file
|
||||
- synth:<params> for procedural video
|
||||
|
||||
Synth examples:
|
||||
synth:bg=lena.jpg:noise=0.1
|
||||
synth:class=chess:bg=lena.jpg:noise=0.1:size=640x480
|
||||
|
||||
Keys:
|
||||
ESC - exit
|
||||
SPACE - save current frame to <shot path> directory
|
||||
|
||||
'''
|
||||
|
||||
# Python 2/3 compatibility
|
||||
from __future__ import print_function
|
||||
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
|
||||
import re
|
||||
|
||||
from numpy import pi, sin, cos
|
||||
|
||||
# local modules
|
||||
from tst_scene_render import TestSceneRender
|
||||
import common
|
||||
|
||||
class VideoSynthBase(object):
|
||||
def __init__(self, size=None, noise=0.0, bg = None, **params):
|
||||
self.bg = None
|
||||
self.frame_size = (640, 480)
|
||||
if bg is not None:
|
||||
self.bg = cv.imread(cv.samples.findFile(bg))
|
||||
h, w = self.bg.shape[:2]
|
||||
self.frame_size = (w, h)
|
||||
|
||||
if size is not None:
|
||||
w, h = map(int, size.split('x'))
|
||||
self.frame_size = (w, h)
|
||||
self.bg = cv.resize(self.bg, self.frame_size)
|
||||
|
||||
self.noise = float(noise)
|
||||
|
||||
def render(self, dst):
|
||||
pass
|
||||
|
||||
def read(self, dst=None):
|
||||
w, h = self.frame_size
|
||||
|
||||
if self.bg is None:
|
||||
buf = np.zeros((h, w, 3), np.uint8)
|
||||
else:
|
||||
buf = self.bg.copy()
|
||||
|
||||
self.render(buf)
|
||||
|
||||
if self.noise > 0.0:
|
||||
noise = np.zeros((h, w, 3), np.int8)
|
||||
cv.randn(noise, np.zeros(3), np.ones(3)*255*self.noise)
|
||||
buf = cv.add(buf, noise, dtype=cv.CV_8UC3)
|
||||
return True, buf
|
||||
|
||||
def isOpened(self):
|
||||
return True
|
||||
|
||||
class Book(VideoSynthBase):
|
||||
def __init__(self, **kw):
|
||||
super(Book, self).__init__(**kw)
|
||||
backGr = cv.imread(cv.samples.findFile('graf1.png'))
|
||||
fgr = cv.imread(cv.samples.findFile('box.png'))
|
||||
self.render = TestSceneRender(backGr, fgr, speed = 1)
|
||||
|
||||
def read(self, dst=None):
|
||||
noise = np.zeros(self.render.sceneBg.shape, np.int8)
|
||||
cv.randn(noise, np.zeros(3), np.ones(3)*255*self.noise)
|
||||
|
||||
return True, cv.add(self.render.getNextFrame(), noise, dtype=cv.CV_8UC3)
|
||||
|
||||
class Cube(VideoSynthBase):
|
||||
def __init__(self, **kw):
|
||||
super(Cube, self).__init__(**kw)
|
||||
self.render = TestSceneRender(cv.imread(cv.samples.findFile('pca_test1.jpg')), deformation = True, speed = 1)
|
||||
|
||||
def read(self, dst=None):
|
||||
noise = np.zeros(self.render.sceneBg.shape, np.int8)
|
||||
cv.randn(noise, np.zeros(3), np.ones(3)*255*self.noise)
|
||||
|
||||
return True, cv.add(self.render.getNextFrame(), noise, dtype=cv.CV_8UC3)
|
||||
|
||||
class Chess(VideoSynthBase):
|
||||
def __init__(self, **kw):
|
||||
super(Chess, self).__init__(**kw)
|
||||
|
||||
w, h = self.frame_size
|
||||
|
||||
self.grid_size = sx, sy = 10, 7
|
||||
white_quads = []
|
||||
black_quads = []
|
||||
for i, j in np.ndindex(sy, sx):
|
||||
q = [[j, i, 0], [j+1, i, 0], [j+1, i+1, 0], [j, i+1, 0]]
|
||||
[white_quads, black_quads][(i + j) % 2].append(q)
|
||||
self.white_quads = np.float32(white_quads)
|
||||
self.black_quads = np.float32(black_quads)
|
||||
|
||||
fx = 0.9
|
||||
self.K = np.float64([[fx*w, 0, 0.5*(w-1)],
|
||||
[0, fx*w, 0.5*(h-1)],
|
||||
[0.0,0.0, 1.0]])
|
||||
|
||||
self.dist_coef = np.float64([-0.2, 0.1, 0, 0])
|
||||
self.t = 0
|
||||
|
||||
def draw_quads(self, img, quads, color = (0, 255, 0)):
|
||||
img_quads = cv.projectPoints(quads.reshape(-1, 3), self.rvec, self.tvec, self.K, self.dist_coef) [0]
|
||||
img_quads.shape = quads.shape[:2] + (2,)
|
||||
for q in img_quads:
|
||||
cv.fillConvexPoly(img, np.int32(q*4), color, cv.LINE_AA, shift=2)
|
||||
|
||||
def render(self, dst):
|
||||
t = self.t
|
||||
self.t += 1.0/30.0
|
||||
|
||||
sx, sy = self.grid_size
|
||||
center = np.array([0.5*sx, 0.5*sy, 0.0])
|
||||
phi = pi/3 + sin(t*3)*pi/8
|
||||
c, s = cos(phi), sin(phi)
|
||||
ofs = np.array([sin(1.2*t), cos(1.8*t), 0]) * sx * 0.2
|
||||
eye_pos = center + np.array([cos(t)*c, sin(t)*c, s]) * 15.0 + ofs
|
||||
target_pos = center + ofs
|
||||
|
||||
R, self.tvec = common.lookat(eye_pos, target_pos)
|
||||
self.rvec = common.mtx2rvec(R)
|
||||
|
||||
self.draw_quads(dst, self.white_quads, (245, 245, 245))
|
||||
self.draw_quads(dst, self.black_quads, (10, 10, 10))
|
||||
|
||||
|
||||
classes = dict(chess=Chess, book=Book, cube=Cube)
|
||||
|
||||
presets = dict(
|
||||
empty = 'synth:',
|
||||
lena = 'synth:bg=lena.jpg:noise=0.1',
|
||||
chess = 'synth:class=chess:bg=lena.jpg:noise=0.1:size=640x480',
|
||||
book = 'synth:class=book:bg=graf1.png:noise=0.1:size=640x480',
|
||||
cube = 'synth:class=cube:bg=pca_test1.jpg:noise=0.0:size=640x480'
|
||||
)
|
||||
|
||||
|
||||
def create_capture(source = 0, fallback = presets['chess']):
|
||||
'''source: <int> or '<int>|<filename>|synth [:<param_name>=<value> [:...]]'
|
||||
'''
|
||||
source = str(source).strip()
|
||||
|
||||
# Win32: handle drive letter ('c:', ...)
|
||||
source = re.sub(r'(^|=)([a-zA-Z]):([/\\a-zA-Z0-9])', r'\1?disk\2?\3', source)
|
||||
chunks = source.split(':')
|
||||
chunks = [re.sub(r'\?disk([a-zA-Z])\?', r'\1:', s) for s in chunks]
|
||||
|
||||
source = chunks[0]
|
||||
try: source = int(source)
|
||||
except ValueError: pass
|
||||
params = dict( s.split('=') for s in chunks[1:] )
|
||||
|
||||
cap = None
|
||||
if source == 'synth':
|
||||
Class = classes.get(params.get('class', None), VideoSynthBase)
|
||||
try: cap = Class(**params)
|
||||
except: pass
|
||||
else:
|
||||
cap = cv.VideoCapture(source)
|
||||
if 'size' in params:
|
||||
w, h = map(int, params['size'].split('x'))
|
||||
cap.set(cv.CAP_PROP_FRAME_WIDTH, w)
|
||||
cap.set(cv.CAP_PROP_FRAME_HEIGHT, h)
|
||||
if cap is None or not cap.isOpened():
|
||||
print('Warning: unable to open video source: ', source)
|
||||
if fallback is not None:
|
||||
return create_capture(fallback, None)
|
||||
return cap
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
import getopt
|
||||
|
||||
print(__doc__)
|
||||
|
||||
args, sources = getopt.getopt(sys.argv[1:], '', 'shotdir=')
|
||||
args = dict(args)
|
||||
shotdir = args.get('--shotdir', '.')
|
||||
if len(sources) == 0:
|
||||
sources = [ 0 ]
|
||||
|
||||
caps = list(map(create_capture, sources))
|
||||
shot_idx = 0
|
||||
while True:
|
||||
imgs = []
|
||||
for i, cap in enumerate(caps):
|
||||
ret, img = cap.read()
|
||||
imgs.append(img)
|
||||
cv.imshow('capture %d' % i, img)
|
||||
ch = cv.waitKey(1)
|
||||
if ch == 27:
|
||||
break
|
||||
if ch == ord(' '):
|
||||
for i, img in enumerate(imgs):
|
||||
fn = '%s/shot_%d_%03d.bmp' % (shotdir, i, shot_idx)
|
||||
cv.imwrite(fn, img)
|
||||
print(fn, 'saved')
|
||||
shot_idx += 1
|
||||
cv.destroyAllWindows()
|
||||
@@ -0,0 +1,211 @@
|
||||
#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;
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
#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;
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
#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;
|
||||
}
|
||||
Reference in New Issue
Block a user