您的位置:首页 > 运维架构

SVM支持向量分类器原理及OpenCV实现

2016-11-20 22:58 295 查看
SVM原理:

        通俗来讲,它是一种二类分类模型,其基本模型定义为特征空间上的间隔最大的线性分类器,其学习策略便是间隔最大化,最终可转化为一个凸二次规划问题的求解。假设给定一些分属于两类的2维点,这些点可以通过直线分割, 我们要找到一条最优的分割线,如下图所示:

                                                                                      


        在上面的图中, 你可以直觉的观察到有多种可能的直线可以将样本分开。 那是不是某条直线比其他的更加合适呢? 我们可以凭直觉来定义一条评价直线好坏的标准。很明显,距离样本太近的直线不是最优的,因为这样的直线对噪声敏感度高,泛化性较差。 因此我们的目标是找到一条直线,离所有点的距离最远。

由此, SVM算法的实质是找出一个能够将某个值最大化的超平面,这个值就是超平面离所有训练样本的最小距离。这个最小距离用SVM术语来说叫做 间隔(margin) 。 概括一下,最优分割超平面 最大化 训练数据的间隔。如下图中间的斜线就是最大间隔向量:

                                                                                      


至于如何去求解这个最大间隔向量,请参考http://blog.csdn.net/sealyao/article/details/6442403,说的很详细。

代码及注释:

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/ml/ml.hpp>
#include<iostream>
using namespace cv;
using namespace std;
int main()
{
int width = 512, height = 512;
Mat image = Mat::zeros(height, width, CV_8UC3);

// 1,设置样本训练数据
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);

// 2,设置SVM的初始参数
CvSVMParams params;
params.svm_type = CvSVM::C_SVC;
params.kernel_type = CvSVM::LINEAR;//直接线性化处理
params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER, 100, 1e-6);//求最大间隔向量的算法,最大迭代次数和容许误差

// 3,训练
CvSVM SVM;
SVM.train(trainingDataMat, labelsMat, Mat(), Mat(), params);

Vec3b green(0, 255, 0), blue(255, 0, 0);
//4,进行预测
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);

// Show support vectors
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);
cout << "最大间隔向量方向" << v[0] << " " << v[1] << endl;
circle(image, Point((int)v[0], (int)v[1]), 6, Scalar(0, 0, 255), thickness, lineType);
}

imwrite("resultSVM.png", image);
imshow("SVM", image);
waitKey(0);

}
                                                              


注意:SVM算法只能分割两部分,如果需要多个分割,请先把分割出一块,把其他部分当作一个整体,然后递归分割。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  svm OpenCV 机器学习