关于SVM简介见上篇《libsvm支持向量机应用编程》,Opencv的SVM是在libsvm的基础上开发的,所以基本操作和接口函数基本一样。只是少了很多功能函数。如果用得着的话,还是libsvm好用。
CvSVM参数说明:
CvSVM参数跟libsvm的参数基本一样,不过没有libsvm那么多,很多东西简化了。
SVM类型:
C_SVC:C类支持向量分类机。n类分组(n≥2),允许用异常值惩罚因子C进行不完全分类。
NU_SVC: v类支持向量分类机。n类似然不完全分类的分类器。参数为v取代C(其值在区间[0,1]中,nu越大,决策边界越平滑)。
ONE_CLASS:单分类器,所有的训练数据提取自同一个类里,然后SVM建立了一个分界线以分割该类在特征空间中所占区域和其它类在特征空间中所占区域。
EPS_SVR: E类支持向量回归机。训练集中的特征向量和拟合出来的超平面的距离需要小于p。异常值惩罚因子C被采用。
NU_SVR:v类支持向量回归机。v代替了 p。
核函数类型:
LINEAR:线性核,相当于没有核。主要用于线性可分的数据。参数少,速度快。
POLY:多项式:(r*u'v +coef0)^degree
RBF:RBF函数:exp(-r|u-v|^2)
SIGMOID: sigmoid函数:tanh(r*u'v + coef0)
核函数的参数:
degree:poly多项式的阶数
gamma: poly/rbf/sigmoid的参数
coef0: poly/sigmoid的参数
C:惩罚因子
nu:
p: 核宽
term_crit:训练终止条件
默认值degree = 0,gamma = 1,coef0 = 0,Cvalue = 1,nu = 0,p = 0,class_weights= 0。
CvSVM使用步骤:
相比libsvm,CvSVM很多功能简化了,所以使用起来也更加简单。
(1)训练SVM
获取Mat类型的样本数据和标签数据,样本数据要按行来存放,即一个代表一个样本,而标签要以列来存放,然后调用CvSVM::train();函数进行训练。
(2)分类
调用函数CvSVM::predict实现分类。
(3)获得支持向量(所谓支持向量,就是指离分割超平面最近的几个向量,由这几个向量可以确定分割超平面。)。除了分类,也可以得到SVM的支持向量,调用函数CvSVM::get_support_vector_count获得支持向量的个数,CvSVM::get_support_vector获得对应的索引编号的支持向量。
测试源码:
实验程序主要功能为对{{0,255,0}, {255,0,0}, {0,0,255}}三组样本数据进行训练,然后使用训练结果对图像中的像素点进行分类标识。
完整的Qt工程下载:http://download.csdn.net/detail/u013752202/9253229
/*****************************
//湖南长沙·2015-11-8
*************************/
#include <QtCore/QCoreApplication>
#include "opencv2\opencv.hpp"
using namespace cv;
//训练样本:红点、蓝点。待识别数据:绿点
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// 用于保存可视化数据的矩阵
Mat image = Mat::zeros(512, 512, CV_8UC3);
for(int i=0;i<image.rows;i++){
for(int j=0;j<image.cols;j++){
if(i<image.rows/3)
image.ptr<Vec3b>(i)[j]=Vec3b(255,0,0);
else if(i<2*image.rows/3)
image.ptr<Vec3b>(i)[j]=Vec3b(0,255,0);
else
image.ptr<Vec3b>(i)[j]=Vec3b(0,0,255);
}
}
float labels[3] = {1.0, 2.0, 3.0};
Mat labelsMat(3, 1, CV_32FC1, labels);
float trainingData[3][3] = {{255,0,0}, {0,255,0}, {0,0,255}};
Mat trainingDataMat(3, 3, CV_32FC1, trainingData);
// 设置SVM参数
CvSVMParams params;
params.svm_type = CvSVM::C_SVC;//C支持向量分类机,允许用异常值惩罚因子C进行不完全分类
params.kernel_type = CvSVM::LINEAR;//使用线性内核
params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER, 100, 1e-6);//迭代训练过程的中止条件
// 对SVM进行训练
CvSVM SVM;
SVM.train(trainingDataMat, labelsMat, Mat(), Mat(), params);
string str1="blue",str2="green",str3="red";
for (int i = 100; i < image.rows; i+=image.rows/3){
int j=10;
int c0=image.ptr<Vec3b>(i)[j][0];
int c1=image.ptr<Vec3b>(i)[j][1];
int c2=image.ptr<Vec3b>(i)[j][2];
Mat sampleMat = (Mat_<float>(1,3) << c0,c1,c2);
float result = SVM.predict(sampleMat);//进行分类
//结果处理
if (result == 1.0)
putText(image,str1,Point(j,i),FONT_HERSHEY_SIMPLEX,2,Scalar(255,255,255),2,8);
else if(result == 2.0)
putText(image,str2,Point(j,i),FONT_HERSHEY_SIMPLEX,2,Scalar(255,255,255),2,8);
else if(result == 3.0)
putText(image,str3,Point(j,i),FONT_HERSHEY_SIMPLEX,2,Scalar(255,255,255),2,8);
}
imshow("SVM分类", image);
waitKey(0);
return a.exec();
}
运行结果分析:
下图为程序运行结果,可以看出图像中的像素点被正确分类标识!