Opencv SVM 的使用方法:
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/ml/ml.hpp>
usingnamespace cv;
int main()
{
// Data for visual representation
int width = 512, height= 512;
Mat image = Mat::zeros(height,width, CV_8UC3);
// NO.1 将数据储存在MAT矩阵中,建立训练样本
//训练数据
float labels[4] = { 1.0,-1.0, -1.0, -1.0 };
float trainingData[4][2]= { { 501, 10 },{ 255, 10 },{ 501, 255 },{ 10, 501 } };
//函数 CvSVM::train 要求训练数据储存于float类型的 Mat 结构中, 因此我们定义了以下矩阵 :Mat labelsMat、 Mat trainingDataMat
Mat labelsMat(3, 1, CV_32FC1, labels);
Mat trainingDataMat(3,2, CV_32FC1, trainingData);
// NO.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);
//此教程中,我们以可线性分割的分属两类的训练样本简单讲解了SVM的基本原理。
//然而,SVM的实际应用情形可能复杂得多(比如非线性分割数据问题,SVM核函数的选择问题等等)。
//总而言之,我们需要在训练之前对SVM做一些参数设定。这些参数保存在类 CvSVMParams 中
/*VM类型.这里我们选择了 CvSVM::C_SVC 类型,该类型可以用于n - 类分类问题(n \geq 2)。这个参数定义在 CvSVMParams.svm_type 属性中.Note CvSVM::C_SVC 类型的重要特征是它可以处理非完美分类的问题(及训练数据不可以完全的线性分割)。在本例中这一特征的意义并不大,因为我们的数据是可以线性分割的,我们这里选择它是因为它是最常被使用的SVM类型。
*SVM 核类型. 我们没有讨论核函数,因为对于本例的样本,核函数的讨论没有必要。然而,有必要简单说一下核函数背后的主要思想,核函数的目的是为了将训练样本映射到更有利于可线性分割的样本集。映射的结果是增加了样本向量的维度,这一过程通过核函数完成。此处我们选择的核函数类型是 CvSVM::LINEAR 表示不需要进行映射。该参数由 CvSVMParams.kernel_type 属性定义。
*算法终止条件 .SVM训练的过程就是一个通过 迭代 方式解决约束条件下的二次优化问题,这里我们指定一个最大迭代次数和容许误差,以允许算法在适当的条件下停止计算。该参数定义在 cvTermCriteria 结构中。*/
// NO.3 训练SVM
CvSVM SVM;
SVM.train(trainingDataMat,labelsMat, Mat(), Mat(), params);
//调用函数 CvSVM::train 来建立SVM模型
// NO.4 SVM区域分割
Vec3b green(0, 255, 0),blue(255, 0, 0);
// Show the decision regions given by the 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;
elseif (response == -1)
image.at<Vec3b>(j, i) = blue;
}
//函数 CvSVM::predict 通过重建训练完毕的支持向量机来将输入的样本分类。本例中我们通过该函数给向量空间着色,
//及将图像中的每个像素当作卡迪尔平面上的一点,每一点的着色取决于SVM对该点的分类类别:绿色表示标记为1的点,
//蓝色表示标记为 - 1的点。
// NO.5 训练数据
// Show the training data
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);
// NO.6 支持向量
// Show support vectors
thickness= 2;
lineType= 8;
int c = SVM.get_support_vector_count();
for (int i = 0; i < c;++i)
{
constfloat* 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); // save the image
imshow("SVM Simple Example", image); // show it to theuser
waitKey(0);
//这里用了几个函数来获取支持向量的信息。 函数CvSVM::get_support_vector_count 输出支持向量的数量,函数CvSVM::get_support_vector 根据输入支持向量的索引来获取指定位置的支持向量。 通过这一方法我们找到训练样本的支持向量并突出显示它们。
//程序创建了一张图像,在其中显示了训练样本,其中一个类显示为白色圆圈,另一个类显示为黑色圆圈。
//训练得到SVM,并将图像的每一个像素分类。分类的结果将图像分为蓝绿两部分,中间线就是最优分割超平面。
//最后支持向量通过灰色边框加重显示。
}