Ask Your Question
0

LibSVM and OpenCV 3.1 [closed]

asked 2017-04-19 04:48:59 -0600

alexMm1 gravatar image

Hi Guys,

someone of you knows how to include LibSVM (http://www.csie.ntu.edu.tw/~cjlin/lib...) in OpenCV ? I would like to use LibSVM instead of OpenCV SVM that is less powerfull (i.e. no probability is given in multi-class problem).

I have an example with the predict function (http://kuantinglai.blogspot.it/2013/0...) but I don't know how to create the model.

Thanks in advance

M.

edit retag flag offensive reopen merge delete

Closed for the following reason the question is answered, right answer was accepted by alexMm1
close date 2017-05-24 10:45:53.202632

2 answers

Sort by ยป oldest newest most voted
2

answered 2017-04-20 01:14:25 -0600

berak gravatar image

libsvm's data model differs a bit from opencv's, if you have a feature [X,Y,Z] in opencv, you need one svm_node for X, another for Y, another for Z, and also a final terminating node:

(1,X) (2,Y) (3,Z) (-1,0)

to train it, you have to construct an svm_problem, which holds a 2d x array with the training data, and an 1d y array for the labels. (the blog post you quote, unfortunately goes cheap, and only shows, how to setup the test data)

#include "svm.h"
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;

#define Malloc(type,n) (type *)malloc((n)*sizeof(type))

class Model {
    static void silent(const char *) {}; // silence libsvm training debug output
    static svm_node *make_node(const Mat &A, int r=0) { // for a single row opencv feature
        const float *dataPtr = A.ptr<float>(r); // Get data from OpenCV Mat
        svm_node *x_space = Malloc(svm_node, A.cols+1); // one more for the terminator
        for (int c=0; c<A.cols; c++) {
            x_space[c].index = c+1;  // Index starts from 1; Pre-computed kernel starts from 0
            x_space[c].value = dataPtr[c];
        }
        x_space[A.cols].index = -1;  // End of sequence
        return x_space;
    }
    svm_model *model;
    svm_problem prob;
public:

    Model(const String &filename) {
        model = svm_load_model(filename.c_str());
        CV_Assert(model != 0);
        prob.l=0;
    }

    Model(const Mat &A, const Mat &L) {
        svm_set_print_string_function(silent); // comment to see the debug output
        svm_parameter param = {0};
        param.svm_type = C_SVC;
        param.kernel_type = LINEAR;
        param.cache_size = 100;
        param.C = 1;
        param.eps = 1e-3;
        param.probability = 1;

        prob.l = A.rows;
        prob.y = Malloc(double, prob.l);
        prob.x = Malloc(svm_node *, prob.l);
        for (int r=0; r<prob.l; r++) {
            prob.x[r] = make_node(A, r);
            prob.y[r] = L.at<int>(r, 0);
        }
        model = svm_train(&prob, &param);
    }

    ~Model() {
        // fixme: if i ever *use* an svm_problem (it's ok with a model loaded from file),
        //   i can't release it after training, but have to keep it around
        //   for the lifetime of the model (s.a. svm.h:69), why ?
        if (prob.l) { // no need to do anything, if model was loaded from file
            for (int r=0; r<prob.l; r++) free(prob.x[r]);
            free(prob.x);
            free(prob.y);
        }
        svm_free_and_destroy_model(&model);
    }

    void probability(const Mat &query, Mat &result) {
        svm_node *x = make_node(query);
        double prob_est[2], prediction = svm_predict_probability(model, x, prob_est);
        result.push_back(prediction);
        result.push_back(prob_est[0]);
        result.push_back(prob_est[1]);
        free(x);
    }

    double predict(const Mat &query) { // a row sample
        svm_node *x = make_node(query);
        double prediction = svm_predict(model, x);
        free(x);
        return prediction;
    }

    bool save(const String &filename) {
        svm_save_model(filename.c_str(), model);
    }
};

int main(int argc, char **argv)
{   // demo, opencv like data
    Mat A = Mat::eye(5,5,CV_32F); // five very distinct vectors
    Mat L = (Mat_<int>(5,1) << 1,2,3,4,5); // each one is unique (multiclass)

    Model model(A,L); // from opencv data
    model.save("5x5.txt");
    //Model model("5x5.txt"); // or load from file (e.g. from svm-train)
    for (int r ...
(more)
edit flag offensive delete link more
2

answered 2017-04-19 08:46:24 -0600

Just use them next to each other. Use OpenCV to generate your data vector, then feed that one into libSVM for training. The OpenCV HOG trainer is a great example of how to combine it!

edit flag offensive delete link more

Comments

Thanks @StevenPuttemans ... one more question: if I have a cv::Mat structure instead of a file? all my features are in a Mat structure (as asked from the openCV SVM implementation)

alexMm1 gravatar imagealexMm1 ( 2017-04-19 08:54:16 -0600 )edit

Question Tools

2 followers

Stats

Asked: 2017-04-19 04:48:59 -0600

Seen: 1,253 times

Last updated: Apr 20 '17