Ask Your Question
1

SVM::getSupportVectors returns wrong answers

asked 2015-12-22 11:09:44 -0600

Pt_pan gravatar image

updated 2015-12-22 11:15:25 -0600

Hi! I'm running the demo program presented in the OpenCV tutorial(introduction to SVM) website , but I get a different result from the result shown in the link.

image description

As you can see from the picture, the support vectors are not correctly plotted. Those three points(support vectors) that are closest to the separate line are not encircled by gray rings.

I single stepped into the code and found that SVM::getSupportVectors() returned only one vector that is very cloes to (0, 0), which is highlighted by a gray ring in the upper left corner.

Any idea about what is going wrong? I'm using OpenCV 3.0.0 with VS2015 in Win7.

The code is as follows (I copied the code from the tutorial and pasted it into VS).

#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**)
{
// Data for visual representation
int width = 512, height = 512;
Mat image = Mat::zeros(height, width, CV_8UC3);
// 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);
// Train the SVM
Ptr<SVM> svm = SVM::create();
svm->setType(SVM::C_SVC);
svm->setKernel(SVM::LINEAR);
svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 100, 1e-6));
svm->train(trainingDataMat, ROW_SAMPLE, labelsMat);
// Show the decision regions given by the SVM
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 the training data
int thickness = -1;
int lineType = 8;
circle( image, Point(501,  10), 5, Scalar(  0,   0,   0), thickness, lineType );
circle( image, Point(255,  10), 5, Scalar(255, 255, 255), thickness, lineType );
circle( image, Point(501, 255), 5, Scalar(255, 255, 255), thickness, lineType );
circle( image, Point( 10, 501), 5, Scalar(255, 255, 255), thickness, lineType );
// Show support vectors
thickness = 2;
lineType  = 8;
Mat sv = svm->getSupportVectors();
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, lineType);
}
imwrite("result.png", image);        // save the image
imshow("SVM Simple Example", image); // show it to the user
waitKey(0);
}
edit retag flag offensive close merge delete

Comments

1

This is an old issue, related to compressing the Support Vectors for linear kernels. It seems that some updates have been made to get uncompressed vectors (https://github.com/Itseez/opencv/pull... and https://github.com/Itseez/opencv/pull...). Still the docs probably need an update

LorenaGdL gravatar imageLorenaGdL ( 2015-12-22 11:28:48 -0600 )edit

Oh, and by the way, the trick was to use a POLY kernel of degree=1, instead of a linear kernel

LorenaGdL gravatar imageLorenaGdL ( 2015-12-22 11:35:20 -0600 )edit

Thank you! It works fine after I used SVM::POLY instead of SVM::LINEAR.

Pt_pan gravatar imagePt_pan ( 2015-12-23 05:30:20 -0600 )edit

1 answer

Sort by ยป oldest newest most voted
3

answered 2015-12-29 09:44:34 -0600

Pt_pan gravatar image

updated 2015-12-29 09:45:31 -0600

Thanks to LorenaGdL, I think I know the cause of the problem.

In the case of linear SVM, getSupportVectors() actually returns one "compressed" support vector that can be used in fast prediction. This method improves performance but have difficulty retrieving "uncompressed" support vectors. In the 3.1.0 version of OpenCV, this has been fixed by adding another function SVM::getUncompressedSupportVectors(), which returns all support vectors as a matrix.

One possible solution, as suggested by LorenaGdL, is to use a POLY type of kernel. The following code set a SVM to have a POLY kernel that behaves the same as a LINEAR kernel.

svm->setKernel(SVM::POLY);
svm->setGamma(1);
svm->setCoef0(0);
svm->setDegree(1.0);
edit flag offensive delete link more

Question Tools

1 follower

Stats

Asked: 2015-12-22 11:09:44 -0600

Seen: 1,287 times

Last updated: Dec 29 '15