Ask Your Question
0

Unable to train SVM Model using a vector of 2D Points using openCv

asked 2018-10-30 06:34:14 -0600

Hi,

I have three classes: 0,1 and 2. These three classes basically consist of a vector of 2D Points. I am trying to train them and use SVM For predicting a correct class,for a given set of 2D Points.

So, basically my input is std::vector<point2d> and output is just a label (like 0,1,2). I am using openCv 3.4 and I wrote the below code. I am getting lot of errors like "channels is not a member of cv:;DataType"

void getSCMCategoryClass( std::vector<Point2d> Tn, std::vector<Point2d> R1n, std::vector<Point2d> R2n, std::vector<Point2d> R3n)
{
    // 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):
    std::vector<std::vector<Point2d>> trainingList;
    trainingList.push_back( R1n );
    trainingList.push_back( R2n );
    trainingList.push_back( R3n );
    Mat trainData( 3, 1, CV_32F );
    Mat trainLabels( 3, 1, CV_32S );

for ( int r = 0; r < 3; r++ )
{
    trainData.at<std::vector<Point2d>>( r, 0 ) = trainingList.at(r); 
    trainLabels.at<int>( r, 0 ) = r; 
}

//// 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, 1, CV_32F );
testData.at<std::vector<Point2d>>( 0, 0 ) = Tn; 

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

}

I understand that,while inserting the elements inside training Data,I cannot use data types like "point2d". How do I make the code workable?

edit retag flag offensive close merge delete

Comments

no wait, you cannot put all contours of 1 class into the same vector<Point2d>.

make it a vector<vector<Point2d>>, for ALL your train samples (not per class !) push_back() each contour, one by one, and keep track of the labels, e.g. class0 is from 0 to 30, class 1 from 30 to 80, etc.

if you have 150 samples, and each feature is has 100 points, that would be a vector[150][100]

berak gravatar imageberak ( 2018-10-30 06:51:42 -0600 )edit

how about assigning Label? Could you once have a look at it and let me know I wrote like this:

trainLabels.at<int>( r, 0 ) = r;

Programming_Enthusiast gravatar imageProgramming_Enthusiast ( 2018-10-30 07:42:26 -0600 )edit

1 answer

Sort by ยป oldest newest most voted
0

answered 2018-10-30 06:46:01 -0600

berak gravatar image

updated 2018-10-30 06:46:41 -0600

it's indeed a type problem here. the train (& test) data may only have a single channel.

if you want to put (2d) Points into it, you have to do it like:

    Mat trainData(nsamples, npoints * 2, CV_32F); // single channel, but cols*2 !
    for (size_t r=0; r < contours.size(); r++) {
        for (size_t c=0; c < contours[r].size(); c++) {
            traindata.at<float>(r, c*2) = contours[r][c].x;
            traindata.at<float>(r, c*2+1) = contours[r][c].y;
        }
   }
edit flag offensive delete link more

Comments

I modified accordingly and when I run it,I get exception.

std::vector<std::vector<Point2d>> trainingList;
trainingList.push_back( R1n );
trainingList.push_back( R2n );
trainingList.push_back( R3n );
Mat trainData( 3, R1n.size()*2, CV_32F );
Mat trainLabels( 3, 1, CV_32S );


for ( size_t r = 0; r < trainingList.size(); r++ )
{
    for ( size_t c = 0; c < trainingList.at(r).size(); c++ )
    {
        trainData.at<double>( r, c*2  ) = trainingList.at(r).at(c).x;
        trainData.at<double>( r, c * 2 + 1 ) = trainingList.at( r ).at( c ).y;
    }
    trainLabels.at<int>( r, 0 ) = r;
}
Programming_Enthusiast gravatar imageProgramming_Enthusiast ( 2018-10-30 07:04:56 -0600 )edit

not sure,why its happening, the MAT Size here is 3x390.In the first 'for loop' itself,it is going into excpetion. Wierd!

Programming_Enthusiast gravatar imageProgramming_Enthusiast ( 2018-10-30 07:10:12 -0600 )edit

Really,wierd,I just changed my code..instead of "double",I used "float" dataType and it runs fine now!

Programming_Enthusiast gravatar imageProgramming_Enthusiast ( 2018-10-30 07:13:15 -0600 )edit

please read the comment to your question , again.

berak gravatar imageberak ( 2018-10-30 07:14:19 -0600 )edit

also NO, if your Mat is CV_32F, you need mat.at<float>() , not double.

berak gravatar imageberak ( 2018-10-30 07:15:20 -0600 )edit

yeah,right.I changed it to FLOAT Now..But results are really bad in this case :(..I dont think, 1$'s normalize() function works well :(

Programming_Enthusiast gravatar imageProgramming_Enthusiast ( 2018-10-30 07:16:36 -0600 )edit

This if my final revised code:

void getSCMCategoryClass( std::vector<Point2d> Tn, std::vector<Point2d> R1n, std::vector<Point2d> R2n, std::vector<Point2d> R3n)
{
    // 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):
    std::vector<std::vector<Point2d>> trainingList;
    trainingList.push_back( R1n );
    trainingList.push_back( R2n );
    trainingList.push_back( R3n );
    Mat trainData( 3, R1n.size()*2, CV_32F );
    Mat trainLabels( 3, 1, CV_32S );
Programming_Enthusiast gravatar imageProgramming_Enthusiast ( 2018-10-30 07:26:12 -0600 )edit

for ( size_t r = 0; r < trainingList.size(); r++ ) { for ( size_t c = 0; c < trainingList.at(r).size(); c++ ) { trainData.at<float>( r, c*2 ) = trainingList.at(r).at(c).x; trainData.at<float>( r, c * 2 + 1 ) = trainingList.at( r ).at( c ).y; } trainLabels.at<int>( r, 0 ) = r; }

    //// 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, R1n.size() * 2, CV_32F );
Programming_Enthusiast gravatar imageProgramming_Enthusiast ( 2018-10-30 07:26:45 -0600 )edit

..

for ( size_t c = 0; c < Tn.size(); c++ )
{
     testData.at<float>( 0, c * 2 ) = Tn.at(c).x;
     testData.at<float>( 0, c * 2 + 1 ) = Tn.at( c ).y;
}

int predicted_label = ( int )svm->predict( testData );
Programming_Enthusiast gravatar imageProgramming_Enthusiast ( 2018-10-30 07:26:58 -0600 )edit

trainLabels.at<int>( r, 0 ) = r;

Is the line fine (or) do I need to assign Labels something differently?? Please look into it and let me know,if I am using SVM Properly.

Programming_Enthusiast gravatar imageProgramming_Enthusiast ( 2018-10-30 07:27:37 -0600 )edit

Question Tools

1 follower

Stats

Asked: 2018-10-30 06:34:14 -0600

Seen: 201 times

Last updated: Oct 30 '18