(一)支持向量机SVM的介绍
1--本文尝试解决下面的问题
如何使用OpenCv中的函数CvSVM::train()训练一个SVM分类器,以及用CvSVM::predit测试训练结果
2--详细探究OpenCv中的CvSVM支持向量机类的各种函数和功能
(二)什么是支持向量机(SVM)
1--支持向量机SVM---就是一个分类器,正式的定义是,一个能够将不同类样本在样本空间分割的---超平面.换
句话说,给定一写标记(Label)好的训练样本(监督式学习),SVM算法输出一个最优化的分隔超平面
2--如何来界定一个超平面是不是最优的呢?考虑如下面的问题:
假设给定一些分属两类的2维点,这些点可以通过直线分割,但是可以分割这些点的分割线有多条,我们需
要在这些分割线中找出一条---最优的分割线
实例图片如下所示:
3--在上面的图中,你可以很直接的观察到有多种可能的直线将样本分开,那是不是某条直线比其他直线
更加合适呢?我们可以凭借直觉来定义一条评价直线好坏的标准:
距离样本太近的直线不是最优的,因为这样的直线对噪声敏感度很高,泛化性很差。因此我们的目标
找到一条直线,离所有的样本点的距离最远
4--因此,SVM算法的实质就是找出一个能够将某个最大化的超平面,这个值就是超平面距离所有训练样
本的--最小距离.这个最小距离用SVM术语来说,叫做----间隔(margin)
5--概括一下,就是---最优分割超平面---最大化训练数据的问题
示例的图片如下所示:
(三)如何计算最优超平面呢?
具体的理论知识,请查看《机器学习》相关的数据
(四)基于OpenCv的SVM算法的C++的实现,代码如下所示:
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/ml/ml.hpp>
using namespace cv;
int main()
{
int width = 512;
int height = 512;
Mat image = Mat::zeros(height, width, CV_8UC3);
float labels[4] = {1.0, -1.0, -1.0, -1.0};
Mat labelsMat(3, 1, CV_32FC1, labels);
float trainingData[4][2] = { {501, 10}, {255, 10}, {501, 255}, {10, 501} };
Mat trainingDataMat(3, 2, CV_32FC1, trainingData);
CvSVMParams params;
params.svm_type = CvSVM::C_SVC;
params.kernel_type = CvSVM::LINEAR;
params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER, 100, 1e-6);
CvSVM SVM;
SVM.train(trainingDataMat, labelsMat, Mat(), Mat(), params);
Vec3b green(0,255,0), 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) << i,j);
float response = SVM.predict(sampleMat);
if (response == 1)
image.at<Vec3b>(j, i) = green;
else if (response == -1)
image.at<Vec3b>(j, i) = 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;
int c = SVM.get_support_vector_count();
for (int i = 0; i < c; ++i)
{
const float* v = SVM.get_support_vector(i);
circle( image, Point( (int) v[0], (int) v[1]), 6, Scalar(128, 128, 128), thickness, lineType);
}
imwrite("result.png", image);
imshow("SVM分类的结果", image);
waitKey(0);
}
程序运行的结果如下所示: