Ask Your Question
0

Training and prediction of class using SVM in OpenCv

asked 2018-10-29 19:32:55 -0600

Hi,

I have three classes (0,1 and 2),and for each class I have set of x,y data. Now my training dataset is considered like this. For class 0, I have some 30 x,y coordinates data.In case of class 1, some 40 x,y coordinates data and for class2, some 50 x,y coordinates data. I want to implement SVM using openCv library. I went through the following link https://docs.opencv.org/2.4/doc/tutor.... I want to modify the code to accomodate my own data set. I would be really glad,if someone can let me know the changes needs to be done in the below code,so that,I can train my data for the three classes and also,if I pass a contour( consisting of a list of x,y values), I want to predict is classification using SVM.

The code from the above link is as follows:

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/ml/ml.hpp>

using namespace cv;

int main()
{
// Data for visual representation
int width = 512, height = 512;
Mat image = Mat::zeros(height, width, CV_8UC3);

// Set up training data
float labels[4] = {1.0, -1.0, -1.0, -1.0};
Mat labelsMat(4, 1, CV_32FC1, labels);

float trainingData[4][2] = { {501, 10}, {255, 10}, {501, 255}, {10, 501} };
Mat trainingDataMat(4, 2, CV_32FC1, trainingData);

// Set up SVM's parameters
CvSVMParams params;
params.svm_type    = CvSVM::C_SVC;
params.kernel_type = CvSVM::LINEAR;
params.term_crit   = cvTermCriteria(CV_TERMCRIT_ITER, 100, 1e-6);

// Train the SVM
CvSVM SVM;
SVM.train(trainingDataMat, labelsMat, Mat(), Mat(), params);

Vec3b green(0,255,0), blue (255,0,0);
// Show the decision regions given by the SVM
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;
int c     = SVM.get_support_vector_count();

for (int i = 0; i < c; ++i)
{
    const float* v = SVM.get_support_vector(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

which opencv version do you use ?

(for 3.x you should use more recent docs)

berak gravatar imageberak ( 2018-10-30 01:28:36 -0600 )edit

I am using 3.4 version. Could you please provide some sample code ,so that I Can try it out with my training and testing set. As written above, for each testing data,I have set of coordinates data! I want to use SVM With a threshold of 80 percent.

Programming_Enthusiast gravatar imageProgramming_Enthusiast ( 2018-10-30 02:40:57 -0600 )edit

1 answer

Sort by ยป oldest newest most voted
0

answered 2018-10-30 02:57:52 -0600

berak gravatar image

updated 2018-10-30 03:06:45 -0600

note, that for machine learning, all features need to have exactly the same size ! (so, if you want to do that on raw coords, you need to re-sample those, apply procrustes, or similar)

assuming (for simplicity, now), that your features are the 8 histogram bins from the freeman chain in your last question, you could try like this:

// 1. we need to setup the traindata (a Mat of N rows, and 8 cols, each feature on a row) 
// and trainlabels (a Mat with N rows, and 1 col):
Mat trainData(N,8,CV_32F);
Mat trainLabels(N,1,CV_32S);

for (int r=0; r<N; r++) {
    for (int c=0; c<8; c++) {
        trainData.at<float>(r,c) = one_histogram[c]; // ??? no idea, what you have, exactly
    }
    trainLabels.at<int>(r,0) = a_label; // ??? a number from 0 to num_classes
}

// 2. now we can setup the SVM, and train it:
Ptr<SVM> svm = SVM::create();
svm->setType(SVM::C_SVC);
svm->setKernel(SVM::LINEAR);
svm->train(trainData, ROW_SAMPLE, trainLabels);

// 3. now to the prediction (on a single sample):
Mat testData(1,8,CV_32F);
for (int c=0; c<8; c++) {
    testData.at<float>(0,c) = one_histogram[c]; // ??? same as above
}

int predicted_label = (int)svm->predict(testData);

good luck !

edit flag offensive delete link more

Comments

My data set consists of coordinates data (x and y values seperated by space).My data set is as follows:

Lets,consider Label 0:

x1 y1
x2 y2
.
.
.

xn yn
Programming_Enthusiast gravatar imageProgramming_Enthusiast ( 2018-10-30 03:02:54 -0600 )edit

yea, that won't work. you don't want to classify single points, but contours (or something derived from that)

IF you go for contours, it would be:

x1 y1 x2 y2 x3 y3 ... xn yn

but you need a fixed n for all features.

besides that, the same, known problems with rotation and scale apply here, too !

the main difference between an SVM and a plain L2 norm is, that it learns a threshold value per feature dimension instead of a single number.

berak gravatar imageberak ( 2018-10-30 03:12:46 -0600 )edit

I am not sure,how I can resample it :(.

Programming_Enthusiast gravatar imageProgramming_Enthusiast ( 2018-10-30 04:25:43 -0600 )edit

there is an example in the other answer.

it now depends on what you want to do. if you want to find out, how the SVM works, i'd suggest, you rotate your dataset manually, as good as possible, and try with the freeman chain histograms.

if you want quick & dirty matching results, rotate the contours a few times, and try something simle, like matchShapes() or hausdorff distance (which does not have the "same size" restriction)

and again: shape module

berak gravatar imageberak ( 2018-10-30 04:31:21 -0600 )edit

yeah,I tried the $1 Dollar sample code,which you shared yesterday! It does not work at all in my case! I am not even able to detect line :(

Programming_Enthusiast gravatar imageProgramming_Enthusiast ( 2018-10-30 04:36:57 -0600 )edit

ah,Some confusion here! So,you mean to say, first generate freeman chain codes for testing and training dataset. And for comparing,freeman chain codes of testing and training datasets, use SVM? Am I right? (or) do you have something in your mind?

Programming_Enthusiast gravatar imageProgramming_Enthusiast ( 2018-10-30 04:46:10 -0600 )edit

yes, that was meant here, exactly.

and the 1$ sample has a convenient "resample" function there. look again.

berak gravatar imageberak ( 2018-10-30 04:54:48 -0600 )edit

yes,right.So,I can use this function for resampling as well as normalizing my data right? And,what do you suggest pass for the variable 'nNumSamples' here??

void normalize( const vector<Point> &points, int nNumSamples, vector<Point2d> &pts )
{
    resample( points, nNumSamples, pts );
    Point2d c = centroid( pts );
    rotateToZero( pts, c );
    scaleTo( pts );
    translate( pts, c );
}
Programming_Enthusiast gravatar imageProgramming_Enthusiast ( 2018-10-30 05:06:56 -0600 )edit

yes indeed. try. nNumSamples might be just the length of your largest contour. or something between the largest & the smallest.

berak gravatar imageberak ( 2018-10-30 05:09:50 -0600 )edit

Ok,I will try this then.Just to summarise, Lets say.we have 3 training sets, T1,T2,T3 and one testing set R1. Then,we check the size of these four contours,lets say S1,S2,S3,S4. Now, nNumSamples = max{S1,S2,S3,S4}. Now,I use the above normalize function and after getting the preprocessed data,I generate freeman chain codes.And finally, use SVM To classify the test data from its freeman chain code. Do you have something else in your mind?

Programming_Enthusiast gravatar imageProgramming_Enthusiast ( 2018-10-30 05:25:03 -0600 )edit

Question Tools

1 follower

Stats

Asked: 2018-10-29 19:32:55 -0600

Seen: 337 times

Last updated: Oct 30 '18