SVM支持向量分类器原理及OpenCV实现
Posted 晴堂
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SVM支持向量分类器原理及OpenCV实现相关的知识,希望对你有一定的参考价值。
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实现的主要内容,如果未能解决你的问题,请参考以下文章