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实现的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV支持向量机(SVM)介绍

支持向量机SVM及python实现

机器学习--支持向量机 (SVM)算法的原理及优缺点

SVM支持向量机,训练与分类的实现(有标签)

支持向量机原理

Svm算法原理及实现