0
#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;
using namespace std;

int main()
{
Mat img_mat = imread("/home/buddhika/workspace/project/images/t.jpg");

// Load images in the C++ format
Size size(64,124);//the image size,e.g.64x124
resize(img_mat ,img_mat ,size);//resize image

int num_files = 1;//number of images
int img_area = 64*124;//imag size
//initialize the training matrix
//The number of rows in the matrix would be 5, and the number of   columns would be the area of the image, 64*124 = 12
Mat training_mat(num_files,img_area,CV_32FC1);
// "fill in" the rows of training_mat with the data from each image.
cvtColor(img_mat,img_mat, CV_RGB2GRAY);
 imshow("",img_mat);

int ii = 0; // Current column in training_mat
//Do this for every training image
int file_num=0;
for (int i = 0; i<img_mat.rows; i++) {
    for (int j = 0; j < img_mat.cols; j++) {
        training_mat.at<float>(file_num,ii++) = img_mat.at<uchar>(i,j);
    }
}

// training matrix set up properly to pass into the SVM functions
//set up labels for each training image
//1D matrix, where each element in the 1D matrix corresponds to each row in the 2D matrix.
//-1 for non-human and 1 for human
//labels matrix
 float label = 1.0;
 cout << training_mat.rows<< endl;
 cout << training_mat.cols<< endl;
 Mat labels(1,7936 , CV_32SC1, label);

// Set up SVM's parameters
    Ptr<SVM> svmOld = SVM::create();
    svmOld->setType(SVM::C_SVC);
    svmOld->setKernel(SVM::LINEAR);
  //  svmOld->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 100, 1e-6));

    //train it based on your data

   svmOld->train(training_mat, ROW_SAMPLE, labels);
    //same svm
  svmOld->save("positive.xml");


    //Initialize SVM object
    Ptr<SVM> svmNew = SVM::create();
    //Load Previously saved SVM from XML
    //can save the trained SVM so you don't have to retrain it every time
    svmNew = SVM::load<SVM>("positive.xml");

//To test your images using the trained SVM, simply read an image, convert it to a 1D matrix, and pass that in to svm
// td.predict( training_mat);//It will return a value based on what you set as your labels

waitKey(0);
return(0);
}

This is the code I used for positive data train using SVM. But

svmOld->train(training_mat, ROW_SAMPLE, labels);

code crashed and give following error. How I overcome from this?

OpenCV Error: Bad argument (in the case of classification problem the responses must be categorical; either specify varType when creating TrainData, or pass integer responses) in train, file /home/buddhika/Documents/OpenCV/modules/ml/src/svm.cpp, line 1618 terminate called after throwing an instance of 'cv::Exception'

mtb
  • 1,350
  • 16
  • 32

2 Answers2

1

This happens because you are specifying that your samples are on the rows of your training_mat while you are writing them on the columns.

The code where you create your training matrix should be as follows:

Mat training_mat(img_area,num_files,CV_32FC1);
// "fill in" the rows of training_mat with the data from each image.
cvtColor(img_mat,img_mat, CV_RGB2GRAY);
imshow("",img_mat);

int ii = 0; // Current column in training_mat
//Do this for every training image
int file_num=0;
for (int i = 0; i<img_mat.rows; i++) {
    for (int j = 0; j < img_mat.cols; j++) {
        training_mat.at<float>(ii++,file_num) = img_mat.at<uchar>(i,j);
    }
}

And your labels should be changed too: Mat labels(training_mat.rows,1 , CV_32SC1, label);

Sunreef
  • 4,452
  • 21
  • 33
0

I don't know that i am right or not, but i would like to try it.

Now talking about your question.As the problem seems to be the implementation of SVM.I would first advise you to study the opencv implementation of SVM first. https://docs.opencv.org/2.4/doc/tutorials/ml/introduction_to_svm/introduction_to_svm.html

What i understand from the SVM documentation is that you have to first provide the training DataSet to it with the class label. Based upon the provided training data it would train the SVM. Also you have to train it for the both positive labels as well as for the negative labels.

What you are doing is quiet wrong.I had run your code on my machine and done some debuggging on it. Use this debugged code.

Mat img_mat = imread("C:\\Users\\saurabh chandra\\Desktop\\52.png");
Mat img_mat1 = imread("C:\\Users\\saurabh chandra\\Desktop\\53.png");
Size size(64, 124);                
resize(img_mat, img_mat, size);   
resize(img_mat1, img_mat1, size);
int num_files = 2;             
int img_area = 64 * 124;      


cvtColor(img_mat, img_mat, CV_RGB2GRAY);  
cvtColor(img_mat1, img_mat1, COLOR_BGR2GRAY);

int ii = 0; 

int file_num = 0;
for (int i = 0; i<img_mat.rows; i++) 
{
for (int j = 0; j < img_mat.cols; j++) 
{
    training_mat.at<float>(file_num, ii++) = img_mat.at<uchar>(i, j);
}

 }

ii = 0;
 file_num =file_num+1;

 for (int i = 0; i<img_mat.rows; i++)
  {
     for (int j = 0; j < img_mat.cols; j++)
     {
      training_mat.at<float>(file_num, ii++) = img_mat.at<uchar>(i, j);
     }
  }


 float label[2] = { 1.0,1.0 };
 cout << training_mat.rows << endl;
 cout << training_mat.cols << endl;
 Mat labels(2, 1, CV_32SC1, label);

 Ptr<SVM> svmOld = SVM::create();
 svmOld->setType(SVM::C_SVC);
 svmOld->setKernel(SVM::LINEAR);
 svmOld->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 100, 1e-6));

 svmOld->train(training_mat, ROW_SAMPLE, labels);
 svmOld->save("positive.xml");

 waitKey(0);
 return 0;
}

This code is saving the SVM training result into Positive.xml file.I had implemented your code for two images. But i would advise you to use good and large training data for better results.

For better understanding on SVM implementation you can check here.

using OpenCV and SVM with images

If this help let me know.

theburningfire
  • 481
  • 1
  • 4
  • 20