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算法只能分割两部分,如果需要多个分割,请先把分割出一块,把其他部分当作一个整体,然后递归分割。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值