0

I'm using SVM to do classification, and I do the training in one project, testing in another, in order to train only once.

The TRAINing part is as follows:

classifier->trainAuto(trainData);
string svmDir = "/File/Dir/";
string svmFile = "svmClassifier.xml";
classifier->save(svmDir+svmFile);

And the TESTing part is:

string svmDir = "/File/Dir/";
string svmFile = "svmClassifier.xml";
Ptr<ml::SVM> classifier = ml::SVM::load<ml::SVM>(svmDir+svmFile);
...
float response = classifier->predict(tDescriptor);

The prediction gives all 0s (all negative). But when I do the prediction right after the SVM training in the Training Project, the predictions are correct (I used breakpoint before "predict", the tDescriptor passed to predict are the same in both projects.) So I think there might be something wrong with saving and loading process..

Can the auto trained SVM be saved and loaded? Or it must be in the statModel?

Thanks for help!

Sikun LIN
  • 1
  • 1
  • 3
  • Try adding these lines after saving: `{cv::FileStorage fs(svmDir+svmFile, cv::FileStorage::APPEND); fs << "format" << 3; }`. Probably is the same issue as [here](http://stackoverflow.com/questions/31766258/the-label-type-must-be-float-if-you-want-to-read-the-xml-files-of-random-forest) – Miki Sep 30 '15 at 10:27
  • @Miki Hi, I added that line and retrained/retested, but it doesn't work for me – Sikun LIN Sep 30 '15 at 10:38
  • It was just a guess. In fact that problem was for random trees, not svm. If you post an mvce with dummy data, like in the question I posted, we can check – Miki Sep 30 '15 at 10:40
  • @Miki Thanks for the reply! In this case the parameters of svm are auto selected by itself, and no compilation error occurs, so I really don't know what else to include? – Sikun LIN Sep 30 '15 at 11:25
  • Copy the code in the other question, and replace the random tree stuff with yours. If you can setup a code that we can copy&paste&run you'll get an answer much sooner. – Miki Sep 30 '15 at 11:28

1 Answers1

0

The flowing code was taken and modified from Introduction to Support Vector Machines for open CV. I saved the SVM parameters from the object svmOld "trainedSVM.xml". Then loaded the XML file and used them to create the object svmNew.

#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()
{



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

    // Set up training data
    int Lable[] = { 1, -1, -1, -1 };
    Mat labelsMat(4, 1, CV_32S, Lable);


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

    // 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 the SVM with given parameters
    Ptr<TrainData> td = TrainData::create(trainingDataMat, ROW_SAMPLE, labelsMat);
    svmOld->train(td);
    //same svm 
    svmOld->save("trainedSVM.xml");


    //Initialize SVM object   
    Ptr<SVM> svmNew = SVM::create();
    //Load Previously saved SVM from XML 

    svmNew = SVM::load<SVM>("trainedSVM.xml");



    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 = svmNew->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 = svmNew->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);
    return(0);
}
  • Hi, the svm can be saved and loaded correctly when it's linear, but when using unlinear kernels, there will be some problems. It's due to the not correctly getting format in the saved SVM during reading – Sikun LIN May 25 '16 at 10:14