SVM通俗原理与OpenCV应用例子代码分析

本文介绍了SVM的基本概念和在OpenCV中的应用。通过一个多分类例子,详细讲解了如何使用OpenCV的SVM类,包括CvSVMParams、CvSVM的构造与训练方法,如train、train_auto等,以及预测和获取支持向量的相关函数。旨在帮助读者理解并掌握SVM的实际运用。

SVM(Support Vector Machine),是一种有监督的学习模型,通常用来进行模式识别、分类、以及回归分析。

概括来讲,它是一种二类分类模型,其基本模型定义为特征空间上的间隔最大的线性分类器,其学习策略便是间隔最大化,最终可转化为一个凸二次规划问题的求解。

通俗来说,我们先让用训练样本告诉两个人(例如两分类问题)哪一类东西分别是他们的。然后我们给他们一些测试样本,他们就各自去拿属于他们的,那些类别标示很明显的,当然毫无争议。但是,那些类别标示不是很明显的,他们根据我们给他们设定的规则(参数)据理力争,想拔河一样你争我夺,最后找到归属。我们的目标是找到一个最好的规则,让样本毫无争议的归属它的主人。但是,这是理想情况,现实是那条理想的规则(最优超平面)不容易找到,甚至经常出现错分的情况。

SVM的数学意义,很是深奥,推到相对复杂,在这里不做深究,这篇文章主要关注与应用。因为,笔者认为,大部分人学SVM主要是为了应用,至于原理以及改进,让那些专家大牛考虑吧。

对于理论方面,感有兴趣的朋友请参考此博文:http://blog.youkuaiyun.com/v_july_v/article/details/7624837


对于应用,最好最快的学习方法就是看例题了,接下来我们通过一个多分类的例子来详细学习OpenCV中SVM的使用。

在学习例子之后,笔者会给出OpenCV中SVM的使用介绍。

#include <cv.h>
#include <highgui.h>
#include <ml.h>
#include <time.h>
#include <ctype.h>
#include <iostream>

using namespace std;

int main()
{
	int size=400;               //图像尺寸
	const int s=100;            //样本点的个数

	int i,j,sv_num;
	IplImage *img=0;
	
	//SVM声明
	CvSVM svm=CvSVM();
	CvSVMParams param;  
	CvTermCriteria criteria;    //停止迭代的标准

	CvRNG rng=cvRNG(time(NULL));

	CvPoint pts[s];             //定义100个点
	float data[s*2];            //点的坐标
	int res[s];                 //点的类别

	CvMat data_mat,res_mat; 
	CvScalar rcolor;
	const float* support;

	//图像区域的初始化,清0
	img = cvCreateImage(cvSize(size,size),IPL_DEPTH_8U,3);
	cvZero(img);

	//学习数据的生成
	for(i=0;i<s;i++)
	{
		pts[i].x=cvRandInt(&rng)%size;//用随机整数赋值
		pts[i].y=cvRandInt(&rng)%size;
		
		//定义三类学习数据
		if (pts[i].y> 50 * cos(pts[i].x* CV_PI/ 100) + 200) 
		{
			cvLine(img, cvPoint(pts[i].x- 2, pts[i].y- 2), cvPoint(pts[i].x+ 2, pts[i].y+ 2), CV_RGB(255, 0, 0));
			cvLine(img, cvPoint(pts[i].x+ 2, pts[i].y- 2), cvPoint(pts[i].x- 2, pts[i].y+ 2), CV_RGB(255, 0, 0));
			res[i] = 1;
		}
		else
		{
			if (pts[i].x> 200) 
			{
				cvLine(img, cvPoint(pts[i].x- 2, pts[i].y- 2), cvPoint(pts[i].x+ 2, pts[i].y+ 2), CV_RGB(0, 255, 0));
				cvLine(img, cvPoint(pts[i].x+ 2, pts[i].y- 2), cvPoint(pts[i].x- 2, pts[i].y+ 2), CV_RGB(0, 255, 0));
				res[i] = 2;
			}
			else 
			{
				cvLine(img, cvPoint(pts[i].x- 2, pts[i].y- 2), cvPoint(pts[i].x+ 2, pts[i].y+ 2), CV_RGB(0, 0, 255));
				cvLine(img, cvPoint(pts[i].x+ 2, pts[i].y- 2), cvPoint(pts[i].x- 2, pts[i].y+ 2), CV_RGB(0, 0, 255));
				res[i] = 3;
			}

		}
	}
	
	//学习数据的显示
	cvNamedWindow("SVM_samples", CV_WINDOW_AUTOSIZE);
	cvShowImage("SVM_samples", img);
	cvWaitKey(5000);

	//学习参数的生成
	for (i= 0; i< s; i++) 
	{
		data[i* 2] = float (pts[i].x) / size;
		data[i* 2 + 1] = float (pts[i].y) / size;
	}
	
	cvInitMatHeader(&data_mat, s, 2, CV_32FC1, data);
	cvInitMatHeader(&res_mat, s, 1, CV_32SC1, res);
	
	//SVM参数设置的两种形式:经测试,第2种没有第一种效果好,因为第一种我们制定了详细的参数
	//而,第2种我们用的是默认的参数
	
	//1.
	criteria= cvTermCriteria(CV_TERMCRIT_EPS, 1000, FLT_EPSILON);//类型,最大迭代数,双精度数
	param= CvSVMParams (CvSVM::C_SVC, CvSVM::RBF, 10.0, 8.0, 1.0, 20.0, 0.5, 0.1, NULL, criteria);
	
	/*2.
	param.svm_type    = CvSVM::C_SVC;
	param.kernel_type = CvSVM::RBF;
	param.term_crit=cvTermCriteria(CV_TERMCRIT_EPS,1000,FLT_EPSILON);
	*/

	//利用训练数据和确定的学习参数,训练SVM
	svm.train(&data_mat, &res_mat, NULL, NULL, param);

	//学习结果的绘图,将size内的所有像素(特征向量)进行分类,直观的显示出分类结果
	for (i= 0; i< size; i++) 
	{
		for (j= 0; j< size; j++) 
		{
			CvMat m;
			float ret = 0.0;
			float a[] = { float (j) / size, float (i) / size };
			cvInitMatHeader(&m, 1, 2, CV_32FC1, a);
			ret= svm.predict(&m);
			switch ((int) ret) 
			{
				case 1:
				rcolor= CV_RGB(100, 0, 0);
				break;
				case 2:
				rcolor= CV_RGB(0, 100, 0);
				break;
				case 3:
				rcolor= CV_RGB(0, 0, 100);
				break;
			}
		cvSet2D(img, i, j, rcolor);
		}
	}

	//训练数据的重新绘制,注意之前的训练数据的绘制用了5S显示,现在需要重新绘制  
	for (i= 0; i< s; i++) 
	{
		CvScalar rcolor;
		switch (res[i]) 
		{
			case 1:
			rcolor= CV_RGB(255, 0, 0);
			break;
			case 2:
			rcolor= CV_RGB(0, 255, 0);
			break;
			case 3:
			rcolor= CV_RGB(0, 0, 255);
			break;
		}
		cvLine(img, cvPoint(pts[i].x- 2, pts[i].y- 2), cvPoint(pts[i].x+ 2, pts[i].y+ 2), rcolor);
		cvLine(img, cvPoint(pts[i].x+ 2, pts[i].y- 2), cvPoint(pts[i].x- 2, pts[i].y+ 2), rcolor);
	}

	//绘制支持向量,用白色的圆圈对支持向量作标记
	sv_num= svm.get_support_vector_count();
	for (i= 0; i< sv_num; i++) 
	{
		support = svm.get_support_vector(i);
		cvCircle(img, cvPoint((int) (support[0] * size), (int) (support[1] * size)), 5, CV_RGB(200, 200, 200));
	}
	
	/*
	创建一个特征向量,测试分类结果
	CvMat *zx = cvCreateMat(2,1,CV_32FC1);
	cvmSet(zx,0,0,0.56); 
	cvmSet(zx,1,0,0.28);
	float lei = svm.predict(zx);
	cout<<lei<<endl;
	*/
	 
	//显示最终的图像
	cvNamedWindow("SVM_result1", CV_WINDOW_AUTOSIZE);
	cvShowImage("SVM_result1", img);
	cvWaitKey(0);
	cvDestroyWindow("SVM");
	cvReleaseImage(&img);
	return 0;
}



运行结果:

1.学习数据显示图像:


2.分类结果图(参数设置用方法1):


3.分类结果图(参数设置用方法2):



OpenCV_SVM使用介绍:

设置SVM参数

struct CvSVMParams

SVM 训练参数结构。

该结构必须被初始化后,传给CvSVM。

CvSVMParams::CvSVMParams

构造函数

C++:
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值