以下是opencv3.0以上SVM的定义示例:
Ptr<SVM> svm = SVM::create();//创建
svm->setType(SVM::C_SVC); //设置类型
svm->setKernel(SVM::LINEAR);//设置核
svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 100, 1e-6));//结束标准(迭代次数或者精度)
以下是网上示例在opencv3.2版本的实现:
#include "opencv2/opencv.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/ml.hpp"
using namespace cv;
using namespace cv::ml;
int main(int argc, char** argv)
{
// visual representation
int width = 512;
int height = 512;
Mat image = Mat::zeros(height, width, CV_8UC3);
// training data
int labels[4] = { 1, -1, -1, -1};
float trainingData[4][2] = { { 501, 10 }, { 255, 10 }, { 501, 255 }, { 10, 501 }};
Mat trainingDataMat(4, 2, CV_32FC1, trainingData);
Mat labelsMat(4, 1, CV_32SC1, labels);
// initial SVM
Ptr svm = SVM::create();
svm->setType(SVM::C_SVC);
svm->setKernel(SVM::LINEAR);
svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 100, 1e-6));
// train operation
svm->train(trainingDataMat, ROW_SAMPLE, labelsMat);
// prediction
Vec3b green(0, 255, 0);
Vec3b blue(255, 0, 0);
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 respose = svm->predict(sampleMat);
if (respose == 1)
image.at(i, j) = green;
else if (respose == -1)
image.at(i, j) = blue;
}
}
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);
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);
}
imshow("SVM Simple Example", image);
waitKey(0);
return 0;
}
下面增加点数再训练看看,以下是改后代码:
#include "opencv2/opencv.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/ml.hpp"
using namespace cv;
using namespace cv::ml;
int main(int argc, char** argv)
{
// visual representation
int width = 512;
int height = 512;
Mat image = Mat::zeros(height, width, CV_8UC3);
// training data
int labels[8] = { 1, -1, -1, -1,-1,-1,1,-1 };
float trainingData[8][2] = { { 501, 10 }, { 255, 10 }, { 501, 255 }, { 10, 501 },{50,320},{36,214},{78,65},{84,276} };
Mat trainingDataMat(8, 2, CV_32FC1, trainingData);
Mat labelsMat(8, 1, CV_32SC1, labels);
// initial SVM
Ptr svm = SVM::create();
svm->setType(SVM::C_SVC);
svm->setKernel(SVM::LINEAR);
svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 100, 1e-6));
// train operation
svm->train(trainingDataMat, ROW_SAMPLE, labelsMat);
// prediction
Vec3b green(0, 255, 0);
Vec3b blue(255, 0, 0);
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 respose = svm->predict(sampleMat);
if (respose == 1)
image.at(i, j) = green;
else if (respose == -1)
image.at(i, j) = blue;
}
}
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);
circle(image, Point(50,320), 5, Scalar(255,255, 255), thickness, lineType);
circle(image, Point(78,65), 5, Scalar(0, 0, 0), thickness, lineType);
circle(image, Point(36, 214), 5, Scalar(255, 255, 255), thickness, lineType);
circle(image, Point(84,276), 5, Scalar(255, 255, 255), thickness, lineType);
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);
}
imshow("SVM Simple Example", image);
waitKey(0);
return 0;
}
以下是结果图:
再试试黑点白点各4个(就是1与-1对半分)的情形,以下是修改后代码和图片:
#include "opencv2/opencv.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/ml.hpp"
using namespace cv;
using namespace cv::ml;
int main(int argc, char** argv)
{
// visual representation
int width = 512;
int height = 512;
Mat image = Mat::zeros(height, width, CV_8UC3);
// training data
int labels[8] = { 1, 1, 1, 1,-1,-1,-1,-1 };
float trainingData[8][2] = { { 501, 10 }, { 255, 10 }, { 501, 255 }, { 10, 501 },{50,320},{36,214},{78,65},{84,276} };
Mat trainingDataMat(8, 2, CV_32FC1, trainingData);
Mat labelsMat(8, 1, CV_32SC1, labels);
// initial SVM
Ptr svm = SVM::create();
svm->setType(SVM::C_SVC);
svm->setKernel(SVM::LINEAR);
svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 100, 1e-6));
// train operation
svm->train(trainingDataMat, ROW_SAMPLE, labelsMat);
// prediction
Vec3b green(0, 255, 0);
Vec3b blue(255, 0, 0);
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 respose = svm->predict(sampleMat);
if (respose == 1)
image.at(i, j) = green;
else if (respose == -1)
image.at(i, j) = blue;
}
}
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(0, 0, 0), thickness, lineType);
circle(image, Point(501, 255), 5, Scalar(0, 0, 0), thickness, lineType);
circle(image, Point(10, 501), 5, Scalar(0, 0, 0), thickness, lineType);
circle(image, Point(50,320), 5, Scalar(255,255, 255), thickness, lineType);
circle(image, Point(78,65), 5, Scalar(255, 255, 255), thickness, lineType);
circle(image, Point(36, 214), 5, Scalar(255, 255, 255), thickness, lineType);
circle(image, Point(84,276), 5, Scalar(255, 255, 255), thickness, lineType);
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);
}
imshow("SVM Simple Example", image);
waitKey(0);
return 0;
}
果然白黑点各在两边。下面打算将红色加入,并且与之对应训练数据是2,然后选择合适的点,看看会怎么样:
#include "opencv2/opencv.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/ml.hpp"
using namespace cv;
using namespace cv::ml;
int main(int argc, char** argv)
{
// visual representation
int width = 512;
int height = 512;
Mat image = Mat::zeros(height, width, CV_8UC3);
// training data
int labels[9] = { 2, 2, 2, 1,1,1,-1,-1,-1 };
float trainingData[9][2] = { { 501, 10 }, {450,200}, { 501, 255 }, { 10, 501 },{30,420},{20,360},{78,65},{84,120},{ 10, 10 }};
Mat trainingDataMat(9, 2, CV_32FC1, trainingData);
Mat labelsMat(9, 1, CV_32SC1, labels);
// initial SVM
Ptr svm = SVM::create();
svm->setType(SVM::C_SVC);
svm->setKernel(SVM::LINEAR);
svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 100, 1e-6));
// train operation
svm->train(trainingDataMat, ROW_SAMPLE, labelsMat);
// prediction
Vec3b green(0, 255, 0);
Vec3b blue(255, 0, 0);
Vec3b red(0, 0, 255);
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 respose = svm->predict(sampleMat);
if (respose == 1)
image.at(i, j) = green;
else if (respose == -1)
image.at(i, j) = blue;
else if(respose == 2)
image.at(i, j) = red;
}
}
int thickness = -1;
int lineType = 8;
circle(image, Point(501, 10), 5, Scalar(158, 148, 148), thickness, lineType);
circle(image, Point(450,200), 5, Scalar(158, 148, 148), thickness, lineType);
circle(image, Point(501, 255 ), 5, Scalar(158, 148, 148), thickness, lineType);
circle(image, Point(10, 501), 5, Scalar(0, 0, 0), thickness, lineType);
circle(image, Point(30,420), 5, Scalar(0, 0, 0), thickness, lineType);
circle(image, Point(20,360), 5, Scalar(0, 0, 0), thickness, lineType);
circle(image, Point(78,65), 5, Scalar(255, 255, 255), thickness, lineType);
circle(image, Point(84,120), 5, Scalar(255, 255, 255), thickness, lineType);
circle(image, Point(10, 10 ), 5, Scalar(255, 255, 255), thickness, lineType);
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);
}
imshow("SVM Simple Example", image);
waitKey(0);
return 0;
}
通过上述尝试,再结合SVM中LINEAR核的理论知识,应该就不难理解啦。。下面给大接个很详细的英文介绍SVM的网址:
https://en.wikipedia.org/wiki/Support_vector_machine