OpenCV unable to set up SVM Parameters

2019-01-09 11:54发布

问题:

I have just started my learning on SVM using C++ OpenCV and was referring to the SVM documentation here. I wanted to try out the sample source code from the link to get familiar with it first but I couldn't run the sample source code. It returns the error :

Error 1 error C2065: 'CvSVMParams' : undeclared identifier

I'm using Visual Studio 2012 with OpenCV 3.0.0. The setup process should be correct as all other codes are working well except this.

回答1:

A lot of things changed from OpenCV 2.4 to OpenCV 3.0. Among others, the machine learning module, which isn't backward compatible.

This is the OpenCV tutorial code for the SVM, update for OpenCV 3.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;

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

    // Set up training data
    int labels[4] = { 1, -1, -1, -1 };
    Mat labelsMat(4, 1, CV_32SC1, 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
    Ptr<SVM> svm = SVM::create();
    svm->setType(SVM::C_SVC);
    svm->setKernel(SVM::LINEAR);
    svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 100, 1e-6));

    // Train the SVM with given parameters
    Ptr<TrainData> td = TrainData::create(trainingDataMat, ROW_SAMPLE, labelsMat);
    svm->train(td);

    // Or train the SVM with optimal parameters
    //svm->trainAuto(td);

    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;
    Mat sv = svm->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);

}

The output should look like:



回答2:

I found the code above worked but I needed to make a small modification to convert the labels to integers. The modification is in bold:

// Set up training data **Original**:

int labels[4] = { 1, -1, -1, -1 };

Mat labelsMat(4, 1, **CV_32SC1**, labels);

// Set up training data **Modified**:

int labels[4] = { 1, -1, -1, -1 };

Mat labelsMat(4, 1, **CV_32S**, labels);