I would like to learn svm implementation by using opencv 3.00 library in C++ and Visual Studio 2013. My code:
#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);
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 befloat
ordouble
.Change
to
BTW, if you are using Linear kernel, the only parameter is
C
, so you do not need tosetGamma
.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
topredict
.You can change
to
Otherwise, if you want to use
res
, then the return value is no longer the response value. But you can get the response fromres
instead.You can change
to