mirror of
https://github.com/opencv/opencv.git
synced 2025-01-18 06:03:15 +08:00
Added to the tutorials the "Support Vector Machines for Non-Linearly Separable Data" contributed by Fernando Iglesias García. Corrected a mistake in the gpu-basics-similarity.rst file.
This commit is contained in:
parent
a51a8ad577
commit
fec995391f
@ -355,6 +355,7 @@ extlinks = {'cvt_color': ('http://opencv.willowgarage.com/documentation/cpp/imgp
|
||||
'utilitysystemfunctions':('http://opencv.itseez.com/modules/core/doc/utility_and_system_functions_and_macros.html#%s', None),
|
||||
'imgprocfilter':('http://opencv.itseez.com/modules/imgproc/doc/filtering.html#%s', None),
|
||||
'svms':('http://opencv.itseez.com/modules/ml/doc/support_vector_machines.html#%s', None),
|
||||
'drawingfunc':('http://opencv.itseez.com/modules/core/doc/drawing_functions.html#%s', None),
|
||||
'xmlymlpers':('http://opencv.itseez.com/modules/core/doc/xml_yaml_persistence.html#%s', None),
|
||||
'huivideo' : ('http://opencv.itseez.com/modules/highgui/doc/reading_and_writing_images_and_video.html#%s', None),
|
||||
'gpuinit' : ('http://opencv.itseez.com/modules/gpu/doc/initalization_and_information.html#%s', None),
|
||||
|
File diff suppressed because one or more lines are too long
BIN
doc/tutorials/ml/non_linear_svms/images/result.png
Normal file
BIN
doc/tutorials/ml/non_linear_svms/images/result.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
BIN
doc/tutorials/ml/non_linear_svms/images/sample-errors-dist.png
Normal file
BIN
doc/tutorials/ml/non_linear_svms/images/sample-errors-dist.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
1
doc/tutorials/ml/non_linear_svms/non_linear_svms.rst
Normal file
1
doc/tutorials/ml/non_linear_svms/non_linear_svms.rst
Normal file
File diff suppressed because one or more lines are too long
BIN
doc/tutorials/ml/table_of_content_ml/images/non_linear_svms.png
Normal file
BIN
doc/tutorials/ml/table_of_content_ml/images/non_linear_svms.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.1 KiB |
@ -26,6 +26,25 @@ Use the powerfull machine learning classes for statistical classification, regre
|
||||
:height: 90pt
|
||||
:width: 90pt
|
||||
|
||||
+
|
||||
.. tabularcolumns:: m{100pt} m{300pt}
|
||||
.. cssclass:: toctableopencv
|
||||
|
||||
============ ==============================================
|
||||
|NonLinSVM| **Title:** :ref:`nonLinearSvmS`
|
||||
|
||||
*Compatibility:* > OpenCV 2.0
|
||||
|
||||
*Author:* |Author_FernandoI|
|
||||
|
||||
Here you will learn how to define the optimization problem for SVMs when it is not possible to separate linearly the training data.
|
||||
|
||||
============ ==============================================
|
||||
|
||||
.. |NonLinSVM| image:: images/non_linear_svms.png
|
||||
:height: 90pt
|
||||
:width: 90pt
|
||||
|
||||
.. raw:: latex
|
||||
|
||||
\pagebreak
|
||||
@ -34,3 +53,4 @@ Use the powerfull machine learning classes for statistical classification, regre
|
||||
:hidden:
|
||||
|
||||
../introduction_to_svm/introduction_to_svm
|
||||
../non_linear_svms/non_linear_svms
|
||||
|
@ -56,7 +56,7 @@ void help()
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
help();
|
||||
help();
|
||||
Mat I1 = imread(argv[1]); // Read the two images
|
||||
Mat I2 = imread(argv[2]);
|
||||
|
||||
@ -68,7 +68,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
BufferPSNR bufferPSNR;
|
||||
BufferMSSIM bufferMSSIM;
|
||||
|
||||
|
||||
int TIMES;
|
||||
stringstream sstr(argv[3]);
|
||||
sstr >> TIMES;
|
||||
@ -103,7 +103,7 @@ int main(int argc, char *argv[])
|
||||
result = getPSNR_GPU_optimized(I1, I2, bufferPSNR);
|
||||
time = 1000*((double)getTickCount() - time)/getTickFrequency();
|
||||
cout << "Initial call GPU optimized: " << time <<" milliseconds."
|
||||
<< " With result of: " << result << endl;
|
||||
<< " With result of: " << result << endl;
|
||||
|
||||
time = (double)getTickCount();
|
||||
for (int i = 0; i < TIMES; ++i)
|
||||
@ -113,7 +113,7 @@ int main(int argc, char *argv[])
|
||||
time /= TIMES;
|
||||
|
||||
cout << "Time of PSNR GPU OPTIMIZED ( / " << TIMES << " runs): " << time
|
||||
<< " milliseconds." << " With result of: " << result << endl << endl;
|
||||
<< " milliseconds." << " With result of: " << result << endl << endl;
|
||||
|
||||
|
||||
//------------------------------- SSIM CPU -----------------------------------------------------
|
||||
@ -183,31 +183,7 @@ double getPSNR(const Mat& I1, const Mat& I2)
|
||||
}
|
||||
}
|
||||
|
||||
double getPSNR_GPU(const Mat& I1, const Mat& I2)
|
||||
{
|
||||
gpu::GpuMat gI1, gI2, gs, t1,t2;
|
||||
|
||||
gI1.upload(I1);
|
||||
gI2.upload(I2);
|
||||
|
||||
gI1.convertTo(t1, CV_32F);
|
||||
gI2.convertTo(t2, CV_32F);
|
||||
|
||||
gpu::absdiff(t1.reshape(1), t2.reshape(1), gs);
|
||||
gpu::multiply(gs, gs, gs);
|
||||
|
||||
Scalar s = gpu::sum(gs);
|
||||
double sse = s.val[0] + s.val[1] + s.val[2];
|
||||
|
||||
if( sse <= 1e-10) // for small values return zero
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
double mse =sse /(double)(gI1.channels() * I1.total());
|
||||
double psnr = 10.0*log10((255*255)/mse);
|
||||
return psnr;
|
||||
}
|
||||
}
|
||||
|
||||
double getPSNR_GPU_optimized(const Mat& I1, const Mat& I2, BufferPSNR& b)
|
||||
{
|
||||
@ -232,9 +208,36 @@ double getPSNR_GPU_optimized(const Mat& I1, const Mat& I2, BufferPSNR& b)
|
||||
}
|
||||
}
|
||||
|
||||
double getPSNR_GPU(const Mat& I1, const Mat& I2)
|
||||
{
|
||||
gpu::GpuMat gI1, gI2, gs, t1,t2;
|
||||
|
||||
gI1.upload(I1);
|
||||
gI2.upload(I2);
|
||||
|
||||
gI1.convertTo(t1, CV_32F);
|
||||
gI2.convertTo(t2, CV_32F);
|
||||
|
||||
gpu::absdiff(t1.reshape(1), t2.reshape(1), gs);
|
||||
gpu::multiply(gs, gs, gs);
|
||||
|
||||
Scalar s = gpu::sum(gs);
|
||||
double sse = s.val[0] + s.val[1] + s.val[2];
|
||||
|
||||
if( sse <= 1e-10) // for small values return zero
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
double mse =sse /(double)(gI1.channels() * I1.total());
|
||||
double psnr = 10.0*log10((255*255)/mse);
|
||||
return psnr;
|
||||
}
|
||||
}
|
||||
|
||||
Scalar getMSSIM( const Mat& i1, const Mat& i2)
|
||||
{
|
||||
const double C1 = 6.5025, C2 = 58.5225;
|
||||
/***************************** INITS **********************************/
|
||||
int d = CV_32F;
|
||||
|
||||
Mat I1, I2;
|
||||
@ -244,8 +247,10 @@ Scalar getMSSIM( const Mat& i1, const Mat& i2)
|
||||
Mat I2_2 = I2.mul(I2); // I2^2
|
||||
Mat I1_2 = I1.mul(I1); // I1^2
|
||||
Mat I1_I2 = I1.mul(I2); // I1 * I2
|
||||
|
||||
Mat mu1, mu2;
|
||||
|
||||
/*************************** END INITS **********************************/
|
||||
|
||||
Mat mu1, mu2; // PRELIMINARY COMPUTING
|
||||
GaussianBlur(I1, mu1, Size(11, 11), 1.5);
|
||||
GaussianBlur(I2, mu2, Size(11, 11), 1.5);
|
||||
|
||||
@ -282,10 +287,79 @@ Scalar getMSSIM( const Mat& i1, const Mat& i2)
|
||||
return mssim;
|
||||
}
|
||||
|
||||
Scalar getMSSIM_GPU( const Mat& i1, const Mat& i2)
|
||||
{
|
||||
const float C1 = 6.5025f, C2 = 58.5225f;
|
||||
/***************************** INITS **********************************/
|
||||
gpu::GpuMat gI1, gI2, gs1, t1,t2;
|
||||
|
||||
gI1.upload(i1);
|
||||
gI2.upload(i2);
|
||||
|
||||
gI1.convertTo(t1, CV_MAKE_TYPE(CV_32F, gI1.channels()));
|
||||
gI2.convertTo(t2, CV_MAKE_TYPE(CV_32F, gI2.channels()));
|
||||
|
||||
vector<gpu::GpuMat> vI1, vI2;
|
||||
gpu::split(t1, vI1);
|
||||
gpu::split(t2, vI2);
|
||||
Scalar mssim;
|
||||
|
||||
for( int i = 0; i < gI1.channels(); ++i )
|
||||
{
|
||||
gpu::GpuMat I2_2, I1_2, I1_I2;
|
||||
|
||||
gpu::multiply(vI2[i], vI2[i], I2_2); // I2^2
|
||||
gpu::multiply(vI1[i], vI1[i], I1_2); // I1^2
|
||||
gpu::multiply(vI1[i], vI2[i], I1_I2); // I1 * I2
|
||||
|
||||
/*************************** END INITS **********************************/
|
||||
gpu::GpuMat mu1, mu2; // PRELIMINARY COMPUTING
|
||||
gpu::GaussianBlur(vI1[i], mu1, Size(11, 11), 1.5);
|
||||
gpu::GaussianBlur(vI2[i], mu2, Size(11, 11), 1.5);
|
||||
|
||||
gpu::GpuMat mu1_2, mu2_2, mu1_mu2;
|
||||
gpu::multiply(mu1, mu1, mu1_2);
|
||||
gpu::multiply(mu2, mu2, mu2_2);
|
||||
gpu::multiply(mu1, mu2, mu1_mu2);
|
||||
|
||||
gpu::GpuMat sigma1_2, sigma2_2, sigma12;
|
||||
|
||||
gpu::GaussianBlur(I1_2, sigma1_2, Size(11, 11), 1.5);
|
||||
sigma1_2 -= mu1_2;
|
||||
|
||||
gpu::GaussianBlur(I2_2, sigma2_2, Size(11, 11), 1.5);
|
||||
sigma2_2 -= mu2_2;
|
||||
|
||||
gpu::GaussianBlur(I1_I2, sigma12, Size(11, 11), 1.5);
|
||||
sigma12 -= mu1_mu2;
|
||||
|
||||
///////////////////////////////// FORMULA ////////////////////////////////
|
||||
gpu::GpuMat t1, t2, t3;
|
||||
|
||||
t1 = 2 * mu1_mu2 + C1;
|
||||
t2 = 2 * sigma12 + C2;
|
||||
gpu::multiply(t1, t2, t3); // t3 = ((2*mu1_mu2 + C1).*(2*sigma12 + C2))
|
||||
|
||||
t1 = mu1_2 + mu2_2 + C1;
|
||||
t2 = sigma1_2 + sigma2_2 + C2;
|
||||
gpu::multiply(t1, t2, t1); // t1 =((mu1_2 + mu2_2 + C1).*(sigma1_2 + sigma2_2 + C2))
|
||||
|
||||
gpu::GpuMat ssim_map;
|
||||
gpu::divide(t3, t1, ssim_map); // ssim_map = t3./t1;
|
||||
|
||||
Scalar s = gpu::sum(ssim_map);
|
||||
mssim.val[i] = s.val[0] / (ssim_map.rows * ssim_map.cols);
|
||||
|
||||
}
|
||||
return mssim;
|
||||
}
|
||||
|
||||
Scalar getMSSIM_GPU_optimized( const Mat& i1, const Mat& i2, BufferMSSIM& b)
|
||||
{
|
||||
int cn = i1.channels();
|
||||
|
||||
const float C1 = 6.5025f, C2 = 58.5225f;
|
||||
/***************************** INITS **********************************/
|
||||
|
||||
b.gI1.upload(i1);
|
||||
b.gI2.upload(i2);
|
||||
|
130
samples/cpp/tutorial_code/ml/non_linear_svms/non_linear_svms.cpp
Normal file
130
samples/cpp/tutorial_code/ml/non_linear_svms/non_linear_svms.cpp
Normal file
@ -0,0 +1,130 @@
|
||||
#include <iostream>
|
||||
#include <opencv2/core/core.hpp>
|
||||
#include <opencv2/highgui/highgui.hpp>
|
||||
#include <opencv2/ml/ml.hpp>
|
||||
|
||||
#define NTRAINING_SAMPLES 100 // Number of training samples per class
|
||||
#define FRAC_LINEAR_SEP 0.9f // Fraction of samples which compose the linear separable part
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
void help()
|
||||
{
|
||||
cout<< "\n--------------------------------------------------------------------------" << endl
|
||||
<< "This program shows Support Vector Machines for Non-Linearly Separable Data. " << endl
|
||||
<< "Usage:" << endl
|
||||
<< "./non_linear_svms" << endl
|
||||
<< "--------------------------------------------------------------------------" << endl
|
||||
<< endl;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
help();
|
||||
|
||||
// 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_32FC1);
|
||||
Mat labels (2*NTRAINING_SAMPLES, 1, CV_32FC1);
|
||||
|
||||
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);
|
||||
|
||||
// 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(1), 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(1), 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(1), Scalar(HEIGHT));
|
||||
|
||||
//------------------ Set up the non-linearly separable part of the training data ---------------
|
||||
|
||||
// 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(1), Scalar(HEIGHT));
|
||||
|
||||
//------------------------- 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 --------------------
|
||||
CvSVMParams params;
|
||||
params.svm_type = SVM::C_SVC;
|
||||
params.C = 0.1;
|
||||
params.kernel_type = SVM::LINEAR;
|
||||
params.term_crit = TermCriteria(CV_TERMCRIT_ITER, (int)1e7, 1e-6);
|
||||
|
||||
//------------------------ 3. Train the svm ----------------------------------------------------
|
||||
cout << "Starting training process" << endl;
|
||||
CvSVM svm;
|
||||
svm.train(trainData, labels, Mat(), Mat(), params);
|
||||
cout << "Finished training process" << endl;
|
||||
|
||||
//------------------------ 4. Show the decision regions ----------------------------------------
|
||||
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) << i, j);
|
||||
float response = svm.predict(sampleMat);
|
||||
|
||||
if (response == 1) I.at<Vec3b>(j, i) = green;
|
||||
else if (response == 2) I.at<Vec3b>(j, i) = blue;
|
||||
}
|
||||
|
||||
//----------------------- 5. Show the training data --------------------------------------------
|
||||
int thick = -1;
|
||||
int lineType = 8;
|
||||
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, lineType);
|
||||
}
|
||||
// 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, lineType);
|
||||
}
|
||||
|
||||
//------------------------- 6. Show support vectors --------------------------------------------
|
||||
thick = 2;
|
||||
lineType = 8;
|
||||
int x = svm.get_support_vector_count();
|
||||
|
||||
for (int i = 0; i < x; ++i)
|
||||
{
|
||||
const float* v = svm.get_support_vector(i);
|
||||
circle( I, Point( (int) v[0], (int) v[1]), 6, Scalar(128, 128, 128), thick, lineType);
|
||||
}
|
||||
|
||||
imwrite("result.png", I); // save the Image
|
||||
imshow("SVM for Non-Linear Training Data", I); // show it to the user
|
||||
waitKey(0);
|
||||
}
|
Loading…
Reference in New Issue
Block a user