OpenCV中的SVM支持向量机

本文主要介绍了OpenCV中支持向量机(SVM)的概念,包括其作为分类器的作用、如何界定最优超平面以及如何计算最优超平面。通过最大化间隔来寻找最优超平面,并利用拉格朗日乘数法求解权重向量和偏置。通过实例展示了SVM如何将图像分为两类,并突出显示支持向量。
摘要由CSDN通过智能技术生成

主要来自OpenCV教程

1、什么是支持向量机SVM

      支持向量机是一个分类器,正式的定义是一个能够将不同类样本在样本空间分隔的超平面,换句话说,给定一些标记(label)好的训练样本,SVM算法输出一个最优化的分隔超平面。

     如何来界定一个超平面是不是最优的:

假设给定一些分别属于两类的2维点,这些点可以通过直线分隔,我们要找到一条最优的分割线。

 

在上面的图中,你可以直觉的观察到有多重可能的直线可以将样本分开,也可以凭直觉来定义一条评价直线好坏的标准:

       距离样本太近的直线不是最优的,因为这样的直线对噪声敏感度高,泛化性差。因此要找到一条直线,离所有的点的距离最远。由此,SVM算法的实质是找出一个能够将某个值最大化的超平面,这个值就是超平面离所有训练样本的最小距离。这个最小距离用SVM术语来说叫做间隔。概括说就是最优分割超平面,最大化训练数据的间隔。

The Optimal hyperplane

 

2、如何计算最优超平面

公式一定义了超平面的表达式:

f(x) = \beta_{0} + \beta^{T} x,

 
            公式(1)

      \beta 叫做权重向量\beta_{0} 叫做偏置(bias)

最优超平面可以有无数种表达方式,即通过任意的缩放\beta\beta_{0}。习惯上使用公式二来表达最优超平面

|\beta_{0} + \beta^{T} x| = 1

 
             公式(2)

式中x表示离超平面最近的那些点。这些点被称为支持向量。

通过几何学的知识,我们知道点x到超平面(\beta\beta_{0})的距离为:

\mathrm{distance} = \frac{|\beta_{0} + \beta^{T} x|}{||\beta||}.

 

特别的是,对于该超平面,表达式中的分子为1,因此支持向量到该超平面的距离是:

\mathrm{distance}_{\text{ support vectors}} = \frac{|\beta_{0} + \beta^{T} x|}{||\beta||} = \frac{1}{||\beta||}.

 

刚才介绍的间隔,这里表示为M,它的取值是最近距离的2倍:

M = \frac{2}{||\beta||}

 

最后最大化M转化为附加限制条件下最小化寒素L(\beta)。限制条件隐含超平面将所有训练样本x_{i}正确分类的条件

\min_{\beta, \beta_{0}} L(\beta) = \frac{1}{2}||\beta||^{2} \text{ subject to } y_{i}(\beta^{T} x_{i} + \beta_{0}) \geq 1 \text{ } \forall i,

 

式中y_{i}表示样本的类别标记。

这是一个拉格朗日优化问题,可以通过拉格朗日乘数法得到最优超平面的权重向量 \beta 和偏置\beta_{0}

 

#include <opencv2\opencv.hpp>

using namespace cv;

int main()
{
    //数据可视化表示
	int width = 512, 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;     //n(n>2)的分类器,其中参数C是异常惩罚因子,可以进行不完全分类
	//params.svm_type  = CvSVM::NU_SVC;    //n(n>2)类似不完全分类的分类器,参数nu(nu属于[0,1]),取代了C_SVC类型的异常惩罚因子C;
	//params.svm_type  = CvSVM::ONE_CLASS;  //单分类器,用一个分界线对特征空间进行分割。

	params.kernel_type = CvSVM::LINEAR;  //线性核函数,此核函数在分类是速度最快,分类将在原始空间中完成;
	//params.kernel_type = CvSVM::POLY;    //多项式核
	//params.kernel_type = CvSVM::RBF;     //径向基核,对于大部分情况都是选择此类型
	//params.kernel_type = CvSVM::SIGMOID;  //sigmoid核函数

	params.term_crit  = cvTermCriteria(CV_TERMCRIT_ITER, 100, 1e-6); //SVM迭代终止条件,CV_TERMCRIT_ITER为终止条件类型,100为最大迭代次数,1e-6为结果的准确率

	//训练SVM
	CvSVM SVM;
	SVM.train(trainingDataMat, labelsMat, Mat(), Mat(), params);
	Vec3b green(0,255,0), blue(255,0,0);

	//显示SVM划分出的决测区域
	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;
	cv::circle(image, Point(501,  10), 5, Scalar(  0,  0,  0), thickness, lineType);
	cv::circle(image, Point(255,  10), 5, Scalar(255,255,255), thickness, lineType);
	cv::circle(image, Point(501, 255), 5, Scalar(255,255,255), thickness, lineType);
	cv::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 Simple Example", image);
	cv::waitKey(0);
}


       程序创建了一张图像,在其中显示了训练样本,即图中的四个点,分成了两类,其中一个类显示为白色圆圈,另一个类显示为黑色圆圈。 

      训练得到SVM,并将图像的每一个像素分类,分类的结果将图像分为蓝绿两部分,中间线就是最优分割超平面。

     最后将支持向量通过灰色边框加重显示,即那四个训练样本点。

The seperated planes

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值