1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
|
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "test_precomp.hpp"
namespace opencv_test { namespace {
using cv::ml::SVM;
using cv::ml::TrainData;
static Ptr<TrainData> makeRandomData(int datasize)
{
cv::Mat samples = cv::Mat::zeros( datasize, 2, CV_32FC1 );
cv::Mat responses = cv::Mat::zeros( datasize, 1, CV_32S );
RNG &rng = cv::theRNG();
for (int i = 0; i < datasize; ++i)
{
int response = rng.uniform(0, 2); // Random from {0, 1}.
samples.at<float>( i, 0 ) = rng.uniform(0.f, 0.5f) + response * 0.5f;
samples.at<float>( i, 1 ) = rng.uniform(0.f, 0.5f) + response * 0.5f;
responses.at<int>( i, 0 ) = response;
}
return TrainData::create( samples, cv::ml::ROW_SAMPLE, responses );
}
static Ptr<TrainData> makeCircleData(int datasize, float scale_factor, float radius)
{
// Populate samples with data that can be split into two concentric circles
cv::Mat samples = cv::Mat::zeros( datasize, 2, CV_32FC1 );
cv::Mat responses = cv::Mat::zeros( datasize, 1, CV_32S );
for (int i = 0; i < datasize; i+=2)
{
const float pi = 3.14159f;
const float angle_rads = (i/datasize) * pi;
const float x = radius * cos(angle_rads);
const float y = radius * cos(angle_rads);
// Larger circle
samples.at<float>( i, 0 ) = x;
samples.at<float>( i, 1 ) = y;
responses.at<int>( i, 0 ) = 0;
// Smaller circle
samples.at<float>( i + 1, 0 ) = x * scale_factor;
samples.at<float>( i + 1, 1 ) = y * scale_factor;
responses.at<int>( i + 1, 0 ) = 1;
}
return TrainData::create( samples, cv::ml::ROW_SAMPLE, responses );
}
static Ptr<TrainData> makeRandomData2(int datasize)
{
cv::Mat samples = cv::Mat::zeros( datasize, 2, CV_32FC1 );
cv::Mat responses = cv::Mat::zeros( datasize, 1, CV_32S );
RNG &rng = cv::theRNG();
for (int i = 0; i < datasize; ++i)
{
int response = rng.uniform(0, 2); // Random from {0, 1}.
samples.at<float>( i, 0 ) = 0;
samples.at<float>( i, 1 ) = (0.5f - response) * rng.uniform(0.f, 1.2f) + response;
responses.at<int>( i, 0 ) = response;
}
return TrainData::create( samples, cv::ml::ROW_SAMPLE, responses );
}
//==================================================================================================
TEST(ML_SVM, trainauto)
{
const int datasize = 100;
cv::Ptr<TrainData> data = makeRandomData(datasize);
ASSERT_TRUE(data);
cv::Ptr<SVM> svm = SVM::create();
ASSERT_TRUE(svm);
svm->trainAuto( data, 10 ); // 2-fold cross validation.
float test_data0[2] = {0.25f, 0.25f};
cv::Mat test_point0 = cv::Mat( 1, 2, CV_32FC1, test_data0 );
float result0 = svm->predict( test_point0 );
float test_data1[2] = {0.75f, 0.75f};
cv::Mat test_point1 = cv::Mat( 1, 2, CV_32FC1, test_data1 );
float result1 = svm->predict( test_point1 );
EXPECT_NEAR(result0, 0, 0.001);
EXPECT_NEAR(result1, 1, 0.001);
}
TEST(ML_SVM, trainauto_sigmoid)
{
const int datasize = 100;
const float scale_factor = 0.5;
const float radius = 2.0;
cv::Ptr<TrainData> data = makeCircleData(datasize, scale_factor, radius);
ASSERT_TRUE(data);
cv::Ptr<SVM> svm = SVM::create();
ASSERT_TRUE(svm);
svm->setKernel(SVM::SIGMOID);
svm->setGamma(10.0);
svm->setCoef0(-10.0);
svm->trainAuto( data, 10 ); // 2-fold cross validation.
float test_data0[2] = {radius, radius};
cv::Mat test_point0 = cv::Mat( 1, 2, CV_32FC1, test_data0 );
EXPECT_FLOAT_EQ(svm->predict( test_point0 ), 0);
float test_data1[2] = {scale_factor * radius, scale_factor * radius};
cv::Mat test_point1 = cv::Mat( 1, 2, CV_32FC1, test_data1 );
EXPECT_FLOAT_EQ(svm->predict( test_point1 ), 1);
}
TEST(ML_SVM, trainAuto_regression_5369)
{
const int datasize = 100;
Ptr<TrainData> data = makeRandomData2(datasize);
cv::Ptr<SVM> svm = SVM::create();
svm->trainAuto( data, 10 ); // 2-fold cross validation.
float test_data0[2] = {0.25f, 0.25f};
cv::Mat test_point0 = cv::Mat( 1, 2, CV_32FC1, test_data0 );
float result0 = svm->predict( test_point0 );
float test_data1[2] = {0.75f, 0.75f};
cv::Mat test_point1 = cv::Mat( 1, 2, CV_32FC1, test_data1 );
float result1 = svm->predict( test_point1 );
EXPECT_EQ(0., result0);
EXPECT_EQ(1., result1);
}
TEST(ML_SVM, getSupportVectors)
{
// Set up training data
int labels[4] = {1, -1, -1, -1};
float trainingData[4][2] = { {501, 10}, {255, 10}, {501, 255}, {10, 501} };
Mat trainingDataMat(4, 2, CV_32FC1, trainingData);
Mat labelsMat(4, 1, CV_32SC1, labels);
Ptr<SVM> svm = SVM::create();
ASSERT_TRUE(svm);
svm->setType(SVM::C_SVC);
svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 100, 1e-6));
// Test retrieval of SVs and compressed SVs on linear SVM
svm->setKernel(SVM::LINEAR);
svm->train(trainingDataMat, cv::ml::ROW_SAMPLE, labelsMat);
Mat sv = svm->getSupportVectors();
EXPECT_EQ(1, sv.rows); // by default compressed SV returned
sv = svm->getUncompressedSupportVectors();
EXPECT_EQ(3, sv.rows);
// Test retrieval of SVs and compressed SVs on non-linear SVM
svm->setKernel(SVM::POLY);
svm->setDegree(2);
svm->train(trainingDataMat, cv::ml::ROW_SAMPLE, labelsMat);
sv = svm->getSupportVectors();
EXPECT_EQ(3, sv.rows);
sv = svm->getUncompressedSupportVectors();
EXPECT_EQ(0, sv.rows); // inapplicable for non-linear SVMs
}
}} // namespace
|