OpenCV svm java,使用opencv实现支持向量机(SVM)

支持向量机的百度百科:http://baike.baidu.com/link?url=be_sHxP-L6kpwFWCrFTDgd5KRR3xlye3N-QI_ndE8lyKEoZJGFxuYfrWHviFq8DZBAGhU3Uh39gZlOFEvElrip4hh6qAi_rYFdcPm7TumAAa428tZ1rV8z9eSmOY1tFMYc7BPKEIx1f_W79E4i-R9q

机器学习:

机器学习是研究计算机怎样模拟或实现人类的学习行为,以获取新的知识或技能,重新组织已有的知识结构使之不断改善自身的性能。它是人工智能的核心,是使计算机具有智能的根本途径,其应用遍及人工智能的各个领域。

机器学习的大致分类:

1)分类(模式识别):要求系统依据已知的分类知识对输入的未知模式(该模式的描述)作分析,以确定输入模式的类属,例如手写识别(识别是不是这个数)。

2)问题求解:要求对于给定的目标状态,寻找一个将当前状态转换为目标状态的动作序列。

SVM一般是用来分类的

一般首先从二维的分类做起,扩展到三维,以及超维度的分类划分,下面是一个二维空间,将空间中的两个点分类:

61849d554001?from=groupmessage

SVM的学习在于经过训练后可以找到最合适的线或平面将空间进行分割,实现点的分类。

在低维度的空间中难以分割的图像,如:

61849d554001?from=groupmessage

线性不可分

解决方法可以采用将其扩展到高维度的空间中,实现分割:

61849d554001?from=groupmessage

三维空间

不考虑具体的函数实现原理,只分析以怎样的心态和角度来应用支持向量机,解决一些现实中需要解决的问题,现在假设已知一定数量的点坐标和其两种不同的分类状况,需要将其在二维空间中进行分割,在图像中绘制分割状况,问题就会变得易懂。下面开始分析SVM的代码实现过程:

首先,如果我们想要在一个空间里分类两类不同的点,首先需要知道每个点的具体坐标,在接收到的图片信息中,我们需要知道每个点的坐标值,还需要每一个点的分类。

可以即将上述的两类数值要求存入两个数组内,假设共有n个点,那么首先设置Datetrain[n][2],这时可以在下标为0的列中存储每个点的横坐标,在下标为1的列中存储每个点的纵坐标。每个点对应一个分组,可以把每个分组标记为1,-1,每个点的分组信息存储为一个数组中:label[n]。

存储好点的信息,下面就需要进行训练了,训练需要实例化向量机,因此创建CvSVM类型的对象SVM,CVSVM的训练方法为:

CvSVM::train(const CvMat* trainData,

const CvMat* responses,

const CvMat* varIdx=0,

const CvMat* sampleIdx=0,

CvSVMParams params=CvSVMParams()

)

其中,参数信息:

1、trainData: 练习数据,必须是CV_32FC1 (32位浮点类型,单通道)。数据必须是CV_ROW_SAMPLE的,即特点向量以行来存储。

2、responses: 响应数据,凡是是1D向量存储在CV_32SC1 (仅仅用在分类题目上)或者CV_32FC1格局。

3、varIdx: 指定感爱好的特点。可所以整数(32sC1)向量,例如以0为开端的索引,或者8位(8uC1)的应用的特点或者样本的掩码。用户也可以传入NULL指针,用来默示练习中应用所有变量/样本。

4、sampleIdx: 指定感爱好的样本。描述同上。

5、params: SVM参数。

可以看出,练习数据trainData就是已经存储的数组Datetrain,而相应数据responses就相对于数组label,为了达到SVM训练相对应的数据类型,可以进行转化:

Mat trainingDataMat(n, 2, CV_32FC1, Datatrain);

Mat labelsMat(n,1, CV_32FC1, label);

接下来需要重点介绍的是SVM参数params:

在opencv2中,有专门的CvSVMParams方法来对训练支持向量机SVM进行参数的设置,CvSVMParams的构造方法如下,都是对于SVM训练的参数设定:

struct CvSVMParams

{

CvSVMParams();

CvSVMParams( int _svm_type, int _kernel_type,

double _degree, double _gamma,double _coef0,

double _C, double _nu, double_p,

CvMat* _class_weights, CvTermCriteria_term_crit );

int svm_type;

int kernel_type;

double degree; // for poly

double gamma; // for poly/rbf/sigmoid

double coef0; // for poly/sigmoid

double C; // for CV_SVM_C_SVC, CV_SVM_EPS_SVR andCV_SVM_NU_SVR

double nu; // forCV_SVM_NU_SVC, CV_SVM_ONE_CLASS, and CV_SVM_NU_SVR

double p; // forCV_SVM_EPS_SVR

CvMat* class_weights; // forCV_SVM_C_SVC

CvTermCriteria term_crit; // termination criteria

};```

第一个参数:svm_type,SVM的类型

作用主要在于使用SVM处理每一个数据点时的分类问题,包括处理意外的点,如果需要拟合高维度的图像时的拟合距离等。

CvSVM::C_SVC:表示在不能精确地使用线性曲线来分割时,可以忽略某些点,但是需要保持尽量最好地线性分类

CvSVM::NU_SVC:n类似然不完全分类的分类器。参数nu取代了c,其值在区间【0,1】中,nu越大,决策边界越平滑。

CvSVM::ONE_CLASS : 单分类器,把当前需要分类的所有数据归为一个类,线性分界线用于区分当前类和另外一个类

CvSVM::EPS_SVR :回归。 训练集中的特征向量和拟合出来的超平面的距离需要小于p。异常值惩罚因子C被采用。

CvSVM::NU_SVR :回归;nu 代替了p

第二个参数:kernel_type,核类型:

核函数的基本作用就是接受两个低维空间里的向量,能够计算出经过某个变换后在高维空间里的向量内积值。因此,核类型的作用在于选择哪种方法进行多维度的参数拟合。

CvSVM::LINEAR :线性核函数,当前维度内进行分界,最快的选择

CvSVM::POLY :多项式核: d(x,y)= (gamma•(x•y)+coef0)degree

CvSVM::RBF :径向基,对于大多数情况都是一个较好的选择:d(x,y)= exp(-gamma•|x-y|2)

CvSVM::SIGMOID: sigmoid函数被用作核函数:d(x,y) = tanh(gamma·(x•y)+coef0)

下面是不同的核函数,其中K(w,x),他接受低维空间的输入值,却能算出高维空间的内积值,可以选择性阅读了解:

(1)线性核函数![](http://upload-images.jianshu.io/upload_images/1825077-9eae42ebaf95b52c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

(2)多项式核函数![](http://upload-images.jianshu.io/upload_images/1825077-7c6b30ee088d7566.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

(3)径向基(RBF)核函数(高斯核函数)![](http://upload-images.jianshu.io/upload_images/1825077-325d0454112cfd06.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

(4)Sigmoid核函数(二层神经收集核函数)![](http://upload-images.jianshu.io/upload_images/1825077-1a1a897ba3a941c0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

C, nu, p:在一般的SVM优化求解时的参数。

class_weights:可选权重,赋给指定的类别。一般乘以C以后去影响不同类别的错误分类惩罚项。权重越大,某一类别的误分类数据的惩罚项就越大。

最后一个:term_crit:SVM的迭代训练过程的中止。(解决了部分受约束二次最优问题),迭代中止的方法有两种:

1、迭代到了一定的次数而中止

2、迭代到了指定的阙值后中止

这部分在学习特征检测时就有涉及,今天再次回顾:

TermCriteria(

int type,

int maxcount,

double epsilon

)

其中type取TermCriteria::MAX_ITER/TerCriteria::COUNT时表示迭代到最大次数中止,这时参数maxcount起作用;

type取TermCriteria::EPS时表示迭代到制定阙值后中止,这时参数epsilon起作用;

type取TermCriteria::EPS+TermCriteria::MAX_ITER时表示出现以上任意一种情况后都中止,这时两个参数都起作用。

到这里,已经可以对参数进行训练了,训练后得到的分界线可以由SVM.predict(Mat sampleMat)预测函数来判断,判断的结果则为label中的设定1,-1来进行标记,依次对每一个坐标进行预测都能得到该坐标的分类状况,坐标应化为Mat型的SampleMat来进行预判。

下面上代码:

include

include

include

using namespace cv;

int main()

{

// 视觉表达数据的设置(Data for visual representation)

int width = 512, height = 512;

//图片的宽,高,以及通道数(第三通道),初始化零矩阵,表示矩阵是0,黑色底面

Mat image = Mat::zeros(height, width, CV_8UC3);

//建立训练数据( Set up training data)

/*训练的是四个点,点的值分别为+1与-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);

//imshow("【train】",trainingDataMat);

//设置支持向量机的参数(Set up SVM's parameters)

CvSVMParams params;

/*SVM的类型:C_SVC:允许用异常惩罚因子C进行不完全分类 */

params.svm_type = CvSVM::C_SVC;

/*核类型 LINEAR:没有任何向映像至高维空间,线性区分在原始特征空间中被完成 */

params.kernel_type = CvSVM::LINEAR;

/*迭代到指定阙值后终止*/

params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER, 100, 1e-6);

// 训练支持向量机(Train the SVM)

CvSVM SVM;//初始化值

SVM.train(trainingDataMat, labelsMat, Mat(), Mat(), params);//开始训练

//两种颜色

Vec3b green(0,255,0), blue (255,0,0);

//显示由SVM给出的决定区域 (Show the decision regions given by the SVM)

for (int i = 0; i < image.rows; ++i)

for (int j = 0; j < image.cols; ++j)

{

//创建了一个一行两列的矩阵图像,并且将这两个图像的像素分别设置为当前像素点的行数和列数

//或者使用cvmSet(CvMat* mat, int row, int col, double value

Mat sampleMat = (Mat_(1,2) << i,j);

//当前样本被分到哪一个类,预测函数

float response = SVM.predict(sampleMat);

if (response == 1)

image.at(j, i) = green;

else if (response == -1)

image.at(j, i) = blue;

}

//显示训练数据 (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);

//显示支持向量 (Show support vectors)

thickness = 2;

lineType = 8;

//获得支持向量的个数

int c = SVM.get_support_vector_count();

std::cout << c << std::endl;

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); // 显示图像

waitKey(0);

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值