简体   繁体   English

OpenCV SVM培训数据

[英]OpenCV SVM Training Data

I would like to learn svm implementation by using opencv 3.00 library in C++ and Visual Studio 2013. My code: 我想通过在C ++和Visual Studio 2013中使用opencv 3.00库来学习svm实现。我的代码:

#include<stdio.h>
#include<math.h>
#include<opencv\cv.h>
#include<opencv\highgui.h>
#include<opencv2\objdetect\objdetect.hpp>
#include<opencv2\highgui\highgui.hpp>
#include<opencv2\imgproc\imgproc.hpp>
#include<vector>
#include <windows.h>
#include <atlstr.h>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <opencv2\imgproc\imgproc.hpp>
#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv\cvaux.hpp>

using namespace cv;
using namespace std;

#include <opencv2\ml.hpp>

using namespace cv;

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

    // Set up training data
    float labels[4] = { 1.0, -1.0, -1.0, -1.0 };
    Mat labelsMat(4, 1, CV_32FC1, 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<ml::SVM> svm = ml::SVM::create();
    // edit: the params struct got removed,
    // we use setter/getter now:
    svm->setType(ml::SVM::C_SVC);
    svm->setKernel(ml::SVM::LINEAR);
    svm->setGamma(3);

    svm->train(trainingDataMat, ml::ROW_SAMPLE, labelsMat);

    Mat res;   // output


    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, res);

        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);

} 

After running this code, I got that error: 运行此代码后,我收到了错误:

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 cv::ml::SVMImpl::train, 
file C:\builds\master_PackSlave-win64-vc12-shared\opencv\modules\ml\src\svm.cpp, line 1610

I debugged that code. 我调试了那段代码。 The debugger stops at this line: svm->train(trainingDataMat, ml::ROW_SAMPLE, labelsMat); 调试器在此行停止: svm->train(trainingDataMat, ml::ROW_SAMPLE, labelsMat);

It says: 它说:

 First-chance exception at 0x000007FEFDA5AAAD in train.exe: Microsoft C++ exception: cv::Exception at memory location 0x00000000001CEE50.
    Unhandled exception at 0x000007FEFDA5AAAD in train.exe: Microsoft C++ exception: cv::Exception at memory location 0x00000000001CEE50.

Besides, it says that: 此外,它说:

(Win32): Loaded 'C:\OpenCV3.0.0\opencv\build\x64\vc12\bin\opencv_world300d.dll'. Cannot find or open the PDB file.

Actually, what I understand is that the problem is related to the memory. 实际上,我理解的是问题与记忆有关。

The type of responses cannot be float or double . responses的类型不能是floatdouble

Change 更改

float labels[4] = { 1.0, -1.0, -1.0, -1.0 };
Mat labelsMat(4, 1, CV_32FC1, labels);

to

int labels[4] = { 1, -1, -1, -1 };
Mat labelsMat(4, 1, CV_32S, labels);

BTW, if you are using Linear kernel, the only parameter is C , so you do not need to setGamma . 顺便说一句,如果你使用的是线性内核,唯一的参数是C ,所以你不需要setGamma


Another problem is the way to get the predicted response. 另一个问题是获得预测响应的方法。 Since each time there is only one sample to predict, if you want to use the return value as the response, you should not pass res to predict . 由于每次只有一个样本要预测,如果要将返回值用作响应,则不应将res传递给predict

You can change 你可以改变

float response = svm->predict(sampleMat, res);

to

float response = svm->predict(sampleMat);

Otherwise, if you want to use res , then the return value is no longer the response value. 否则,如果要使用res ,则返回值不再是响应值。 But you can get the response from res instead. 但你可以从res获得响应。

You can change 你可以改变

if (response == 1)
    image.at<Vec3b>(i, j) = green;
else if (response == -1)
    image.at<Vec3b>(i, j) = blue;
}

to

if (res.at<float>(0) == 1)
    image.at<Vec3b>(i, j) = green;
else if (res.at<float>(0) == -1)
    image.at<Vec3b>(i, j) = blue;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM