下册人教版五年级下册作文作文:歇后语编故事

 上传我的文档
 下载
 收藏
该文档贡献者很忙,什么也没留下。
 下载此文档
正在努力加载中...
基于SVM的分类算法与聚类分析
下载积分:30
内容提示:基于SVM的分类算法与聚类分析
文档格式:PDF|
浏览次数:75|
上传日期: 02:14:57|
文档星级:
全文阅读已结束,如果下载本文需要使用
 30 积分
下载此文档
该用户还上传了这些文档
基于SVM的分类算法与聚类分析
官方公共微信8570人阅读
【opencv应用】(5)
原创作品 转载请注明出
上一篇博文对图像分类理论部分做了比较详细的讲解,这一篇主要是对图像分类代码的实现进行分析。理论部分我们谈到了使用BOW模型,但是BOW模型如何构建以及整个步骤是怎么样的呢?可以参考下面的博客,这一篇博客很详细讲解了BOW模型的步骤了,主要包含以下四个步骤:
提取训练集中图片的feature
将这些feature聚成n类。这n类中的每一类就相当于是图片的“单词”,所有的n个类别构成“词汇表”。我的实现中n取1000,如果训练集很大,应增大取值。
对训练集中的图片构造bag of words,就是将图片中的feature归到不同的类中,然后统计每一类的feature的频率。这相当于统计一个文本中每一个单词出现的频率
训练一个多类分类器,将每张图片的bag of words作为feature vector,将该张图片的类别作为label。
对于未知类别的图片,计算它的bag of words,使用训练的分类器进行分类。
上面整个工程步骤所涉及到的函数,我都放在一个类categorizer里,
下面按步骤说明具体实现,程序示例有所省略,完整的程序可看工程源码。
NO.1、特征提取
对图片特征的提取包括对每张训练图片的特征提取和每张待检测图片特征的提取,我使用的是surf,所以使用opencv的SurfFeatureDetector检测特征点,然后再用SurfDescriptorExtractor抽取特征点描述符。对于特征点的检测和特征描述符的讲解可以参考中文opencv中文官网以及
我训练图片特征提取的示例代码如下:
Mat vocab_
multimap&string,Mat& ::iterator i=train_set.begin();
for(;i!=train_set.end();i++)
vector&KeyPoint&
Mat templ=(*i).
featureDecter-&detect(templ,kp);
descriptorExtractor-&compute(templ,kp,descrip);
vocab_descriptors.push_back(descrip);
注意:上述代码只是工程的一个很小的部分,有些变量在类中已经定义,在这里没有贴出来,例如上述的train_set训练图片的映射,定义为:
multimap&string,Mat& train_
将每张图片的特征描述符存储起来vocab_descriptors,然后为后面聚类和构造训练图片词典做准备。
NO.2、feature聚类
由于opencv封装了一个类BOWKMeansExtractor[2],这一步非常简单,将所有图片的feature vector丢给这个类,然后调用cluster()就可以训练(使用KMeans方法)出指定数量(步骤介绍中提到的n)的类别。输入vocab_descriptors就是第1步计算得到的结果,返回的vocab是一千个向量,每个向量是某个类别的feature的中心点。
示例代码如下:
bowtrainer-&add(vocab_descriptors);
vocab=bowtrainer-&cluster();
bowtrainer的定义如下:
bowtrainer=new BOWKMeansTrainer(clusters);
NO.3、构造bag of words
对每张图片的特征点,将其归到前面计算的类别中,统计这张图片各个类别出现的频率,作为这张图片的bag of words。由于opencv封装了BOWImgDescriptorExtractor[2]这个类,这一步也走得十分轻松,只需要把上面计算的vocab丢给它,然后用一张图片的特征点作为输入,它就会计算每一类的特征点的频率。
allsamples_bow这个map的key就是某个类别,value就是这个类别中所有图片的bag of words,即Mat中每一行都表示一张图片的bag of words。
bowDescriptorExtractor-&setVocabulary(vocab);
multimap&string,Mat& ::iterator i=train_set.begin();
for(;i!=train_set.end();i++)
vector&KeyPoint&
string cate_nam=(*i).
Mat tem_image=(*i).
Mat imageD
featureDecter-&detect(tem_image,kp);
bowDescriptorExtractor-&compute(tem_image,kp,imageDescriptor);
allsamples_bow[cate_nam].push_back(imageDescriptor);
上面部分变量的定义如下:
map&string,Mat& allsamples_
Ptr&FeatureDetector& featureD
Ptr&DescriptorExtractor& descriptorE
Ptr&BOWKMeansTrainer&
Ptr&BOWImgDescriptorExtractor& bowDescriptorE
Ptr&FlannBasedMatcher& descriptorM
NO.4、训练分类器
我使用的分类器是svm,用经典的1 vs all方法实现多类分类。对每一个类别都训练一个二元分类器。训练好后,对于待分类的feature vector,使用每一个分类器计算分在该类的可能性,然后选择那个可能性最高的类别作为这个feature vector的类别。
训练二元分类器
allsamples_bow:第3步中得到的结果。
category_name:针对哪个类别训练分类器。
svmParams:训练svm使用的参数。
stor_svms:针对category_name的分类器。
属于category_name的样本,label为1;不属于的为-1。准备好每个样本及其对应的label之后,调用CvSvm的train方法就可以了。
示例代码如下:
stor_svms=new CvSVM[categories_size]
//设置训练参数
SVMParams svmParams
svmParams.svm_type
= CvSVM::C_SVC
svmParams.kernel_type = CvSVM::LINEAR
svmParams.term_crit
= cvTermCriteria(CV_TERMCRIT_ITER, 100, 1e-6)
cout&&"训练分类器..."&&endl
for(int i=0
Mat tem_Samples( 0, allsamples_bow.at( category_name[i] ).cols, allsamples_bow.at( category_name[i] ).type() )
Mat responses( 0, 1, CV_32SC1 )
tem_Samples.push_back( allsamples_bow.at( category_name[i] ) )
Mat posResponses( allsamples_bow.at( category_name[i]).rows, 1, CV_32SC1, Scalar::all(1) )
responses.push_back( posResponses )
for ( auto itr = allsamples_bow.begin()
if ( itr -& first == category_name[i] ) {
tem_Samples.push_back( itr -& second )
Mat response( itr -& second.rows, 1, CV_32SC1, Scalar::all( -1 ) )
responses.push_back( response )
stor_svms[i].train( tem_Samples, responses, Mat(), Mat(), svmParams )
string svm_filename=string(DATA_FOLDER) + category_name[i] + string("SVM.xml")
stor_svms[i].save(svm_filename.c_str())
对于SVM的参数以及函数调用的介绍可以参考中文官网
部分变量的定义如下:
CvSVM *stor_
vector&string& category_
int categories_
NO.5、对未知图片进行分类
使用某张待分类图片的bag of words作为feature vector输入,使用每一类的分类器计算判为该类的可能性,然后使用可能性最高的那个类别作为这张图片的类别。
prediction_category就是结果,test就是某张待分类图片的bag of words。示例代码如下:
Mat input_pic=imread(train_pic_path);
imshow("输入图片:",input_pic);
cvtColor(input_pic,gray_pic,CV_BGR2GRAY);
vector&KeyPoint&
featureDecter-&detect(gray_pic,kp);
bowDescriptorExtractor-&compute(gray_pic,kp,test);
float scoreValue = stor_svms[i].predict( test, true );
float classValue = stor_svms[i].predict( test, false );
sign = ( scoreValue & 0.0f ) == ( classValue & 0.0f )? 1 : -1;
curConfidence = sign * stor_svms[i].predict( test, true );
if(curConfidence&best_score)
best_score=curC
prediction_category=cate_
上面就是四个主要步骤的部分示例代码,很多其他部分代码没有贴出来,比如说如何遍历文件夹下面的所有不同类别的图片,因为训练图片的样本比较多的话,训练图片是一个时间比较长久的,那么如何在对一张待测图片进行分类的时候,不需要每次都重复训练样本,而是直接读取之前已经训练好的BOW。。。。很多很多。
我的main函数实现如下:
int main(void)
int clusters=1000;
categorizer c(clusters);
c.bulid_vacab();
c.compute_bow_image();
c.trainSvm();
c.category_By_svm();
下面来看看我的工程部分运行结果如下:
部分分类下图所示:
左边为输入图片,右边为所匹配的类别模型。准确率为百分之八九十。
我的整个工程文件以及我的所有训练的图片存放在这里以及,需要的可以下载,自己在找训练图片写代码花了很多时间,下载完后自行解压,project data文件夹直接放在D盘就行,里面存放训练的图片和待测试图片,以及训练过程中生成的中间文件,另一个文件夹object_classfication_end则是工程文件,我用的是vs2010打开即可,下面工程里有几个要注意的地方:
1、在这个模块中使用到了c++的boost库,但是在这里有一个版本的限制。这个模块的代码只能在boost版本1.46以上使用,这个版本以下的就不能用了,直接运行就会出错,这是最需要注意的。因为在1.46版本以上中对比CsSVM这个类一些成员函数做了一些私有化的修改,所以在使用该类初始化对象时候需要注意。
2、我的模块所使用到的函数和产生的中间结果都是在一个categorizer类中声明的,由于不同的执行阶段中间结果有很多个,例如:训练图片聚类后所得到单词表矩阵,svm分类器的训练的结果等,中间结果的产生是相当耗时的,所以在刚开始就考虑到第一次运行时候把他以文件XML的格式保存下来,下次使用到的时候在读取。将一个矩阵存入文本的时候可以直接用输出流的方式将一个矩阵存入,但是读取时候如果用输入流直接一个矩阵变量的形式读取,那就肯定报错,因为输入流不支持直接对矩阵的操作,所以这时候只能对矩阵的元素一个一个进行读取了。
3、在测试的时候,如果输入的图片太小,或者全为黑色,当经过特征提取和单词构造完成使用svm进行分类时候会出现错误。经过调试代码,发现上述图片在生成该图片的单词的时候所得到的单词矩阵会是一个空矩阵,即该矩阵的行列数都为0,所以在使用svm分类器时候就出错。所以在使用每个输入图片的单词矩阵的时候先做一个判断,如果该矩阵行列数都为0,那么该图片直接跳过。
&&相关文章推荐
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:57969次
积分:1553
积分:1553
排名:千里之外
原创:98篇
评论:42条
中国科学技术大学硕士在读,关注机器学习,我的github: /TanDongXu,欢迎大神指点.
(4)(6)(7)(4)(31)(40)(6)您所在位置: &
&nbsp&&nbsp&nbsp&&nbsp
基于SVM图像分类方法研究.pdf54页
本文档一共被下载:
次 ,您可全文免费在线阅读后下载本文档。
文档加载中...广告还剩秒
需要金币:200 &&
你可能关注的文档:
··········
··········
r 摘 要 图像的自动分类在许多领域都是一项关键的任务,其中包括图像检索、可
视场景的目标检测、网络信息过滤、医学图像应用等等。当直接在图像上进行
操作时,传统的分类方法由于数据的高维特性表现差,很难取得较好的效果。 Vector
而支持向量机 Support
被广泛运用到图像分类中。 由于支持向量机的分类性能极大程度地依赖于核参数的选择,因此,本文
着重研究了核参数选择方法,并利用不同的颜色、纹理特征对图像进行分类。 本文所做的主要工作如下: 1.分析了支持向量机核函数中各个参数对分类模型的影响,使用网格搜索法
和粒子群算法对模型中的参数进行了优化,比较各方法对SVM核参数的寻优能
力。 2.对彩色图像在HSV空间使用不同的量化方法提取颜色特征,针对传统直
方图丢失颜色空间信息的情况,使用一种区域加权直方图与颜色矩结合的颜色
特征提取方法。纹理方面,使用灰度共生矩阵法、LBP分别提取出图像的纹理
特征,对LBP模式的进行了降维方面的研究,分析了LBP统一模式的不足。 3.应用PSO算法的SVM对图像进行分类,对图像的色彩、纹理等多种特征
的分类能力进行了测试和比较,分析了不同参数优化方法对图像分类准确率的
影响。 关键词:支持向量机,灰度共生矩阵,局部二值模式,颜色直方图 Abstract classificationof iscriticaltaskin information
Automatic images manyareas,includingretrieval,
visualscene data in detection,Intemetfiltering,medicalapplications,etc.Whenoperateddirectly conventionalmethodsdifficulttoobtainresultsbecause
the are image,the always good theypoor
dimension Vector overcomethe Machine SVM Call high performance.However,Support in
defectof hasbeen
used classification. hi曲-d
正在加载中,请稍后...machine learning(29)
OpenCV(14)
因为《opencv_tutorial》这部分只有两个例子,就先暂时介绍两个例子好了,在refman中ml板块有:统计模型、普通的贝叶斯分类器、KNN、SVM、决策树、boosting、随机树、EM(期望最大化)、NN(神经网络)、LR(逻辑回归)和training data(训练数据)
这部分要特别说明:http://www./opencvdoc/2.3.2/html/doc/tutorials/ml/introduction_to_svm/introduction_to_svm.html#introductiontosvms或者是《opencv即使是3.0tutorials》中都还是使用的CvSVM::train这样的函数,但是在对应的《opencv2refman,3.0》中并没有这个,而是改成了SVM类了,在2.4.10中还是保留的CvSVM的,也就是这里3.0之前和之后得区别对待一下。
这里还是先介绍CvSVM的版本,毕竟手头上有2.4.10的,当然也在装3.0版本的,看着到时候在直接上3.0beta的SVM版本的。下面的都是照搬的,http://www./opencvdoc/2.3.2/html/doc/tutorials/ml/introduction_to_svm/introduction_to_svm.html#introductiontosvms。先照搬,然后理解他们 ,接着在加上自己的一些想法
一、svm的介绍
& & 支持向量机 (SVM) 是一个类分类器,正式的定义是一个能够将不同类样本在样本空间分隔的超平面。 换句话说,给定一些标记(label)好的训练样本 (监督式学习), SVM算法输出一个最优化的分隔超平面。
如何来界定一个超平面是不是最优的呢? 考虑如下问题:假设给定一些分属于两类的2维点,这些点可以通过直线分割, 我们要找到一条最优的分割线.
在上面的图中, 你可以直觉的观察到有多种可能的直线可以将样本分开。 那是不是某条直线比其他的更加合适呢? 我们可以凭直觉来定义一条评价直线好坏的标准:距离样本太近的直线不是最优的,因为这样的直线对噪声敏感度高,泛化性较差。 因此我们的目标是找到一条直线,离所有点的距离最远。
由此,SVM算法的实质是找出一个能够将某个值最大化的超平面(关于超平面的更加详细的说明可以参考T. Hastie, R. Tibshirani 和 J. H. Friedman的书籍&Elements
of Statistical Learning&, section 4.5 (Seperating
Hyperplanes)。),这个值就是超平面离所有训练样本的最小距离。这个最小距离用SVM术语来说叫做&间隔(margin)&。 概括一下,最优分割超平面&最大化&训练数据的间隔。
下面的公式定义了超平面的表达式:
&叫做权重向量,&叫做偏置。最优超平面可以有无数种表达方式,即通过任意的缩放和,习惯上我们使用以下方式来表达最优超平面:
式中 x&表示离超平面最近的那些点。 这些点被称为&支持向量**。 该超平面也称为 **canonical 超平面.通过几何学的知识,我们知道点&x&到超平面(,)&的距离为:
特别的,对于 canonical 超平面, 表达式中的分子为1,因此支持向量到canonical 超平面的距离是:
刚才我们介绍了间隔(margin),这里表示为 M&,
它的取值是最近距离的2倍:
最后最大化
M&转化为在附加限制条件下最小化函数L()&。
限制条件隐含超平面将所有训练样本 xi&正确分类的条件,
式中 yi&表示样本的类别标记。这是一个拉格朗日优化问题,可以通过拉格朗日乘数法得到最优超平面的权重向量&和偏置&。
#include &opencv2/core/core.hpp&
#include &opencv2/highgui/highgui.hpp&
#include &opencv2/ml/ml.hpp&
using namespace cv;
int main()
int width = 512, height = 512;
Mat image = Mat::zeros(height, width, CV_8UC3);//生成可显示结果的画布
// 建立训练数据:标签及对应数据集 而且train中要求是flotat,这里使用四个实参的Mat构造函数的初始化方式。
float labels[4] = {1.0, -1.0, -1.0, -1.0};//训练集合的标签
Mat labelsMat(3, 1, CV_32FC1, labels);//生成矩阵形式,函数&&要求训练数据储存于float类型的&&结构中
float trainingData[4][2] = { {501, 10}, {255, 10}, {501, 255}, {10, 501} };//训练集合的数据
Mat trainingDataMat(3, 2, CV_32FC1, trainingData);//生成矩阵形式,函数&&要求训练数据储存于float类型的&&结构中,即需要的是CV_32FC1类型。
// Set up SVM's parameters填充需要的参数结构
CvSVMParams params;
params.svm_type
= CvSVM::C_SVC;//表示c-支持向量分类,n-类别分类(n&=2);
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);//训练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);//svm的预测
//下面两个语句就是进行不同类别使用不同的颜色进行区分
if (response == 1)
image.at&Vec3b&(j, i)
else if (response == -1)
image.at&Vec3b&(j, i)
// Show the training data 将训练的时间进行使用小圆圈显示,更加直观
int thickness = -1;
int lineType = 8;
circle( image, Point(501,
10), 5, Scalar(
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;
= SVM.get_support_vector_count();//返回svm的支持向量的个数
//将支持向量画出来
for (int i = 0; i & c; ++i)
const float* v = SVM.get_support_vector(i);
circle( image,
Point( (int) v[0], (int) v[1]),
Scalar(128, 128, 128), thickness, lineType);
imwrite(&result.png&, image);
// save the image 保存这幅图片
imshow(&SVM Simple Example&, image); // show it to the user显示这幅图片
waitKey(0);
上面的是例子程序,从注释中就能够看出,在opencv中训练一个svm是相当容易和简单的,不过这是否与封装的好,还是所支持的内容有限有关就不知道了,不过它是基于libsvm的,不会差,至于libsvm的实现算法,好像听说新版和旧版的不一样,不过这都是核心的地方,不了解也没关系。
CvSVMParams结构体(在3.0版本的refman中说的是类,虽然在cpp中两者只有默认权限的差别,不过还是可以看出3.0更加往着cpp方向实现了)
是svm的训练参数。该结构必须被初始化并传递给CVSVM的训练方法
构造函数原型:CvSVMParams::CvSVMParams()
& & & & & & & & & & & & & &CvSVMParams::CvSVMParams(int svm_type, int kernel_type, double degree, double gamma, double&coef0, double Cvalue, double nu, double p, CvMat* class_weights,&CvTermCriteria term_crit);
& & svm_type:svm公式的类型,可能的值为:
& & & & & & & & & & &– CvSVM::C_SVC :C-支持向量分类,n-类 分类(n&=2),允许使用惩罚乘数C对离群点进行不完美分离的惩罚。
& & & & & & & & & & &– CvSVM::NU_SVC &:--支持向量分类,有着可能的不完美分离的n-类分类。参数(范围为0..1,更大的值表示决策面更加的平滑)用来代替上面的C。
& & & & & & & & & &– CvSVM::ONE_CLASS :分布估计(单类svm)。所有的训练数据都来自于同一个类别,svm构建一个边界用来将这个类与剩下的其他所有训练数据在特征空间中分隔开。
& & & & & & & & & &&– CvSVM::EPS_SVR &:支持向量回归。介于来自训练集的特征向量与所拟合的超平面之间的距离必须小于
p 。对于离群点来说,会使用惩罚乘数C。
& & & & & & & & & & &– CvSVM::NU_SVR &:支持向量回归,用来代替
& & & & & & & & 见 【libsvm】参考更详细的说明
& & kernel_type :svm核函数类型。可能的值为:
& & & & & & & & & & & & & &– CvSVM::LINEAR &线性核函数。没有映射操作,只是在最初的特征空间中使用线性决策(或者是回归)。这是最快的选择。(当然结果。。)
& & & & & & & & & & & &– CvSVM::POLY & & 多项式核函数:
& & & & & & & & & & &&– CvSVM::RBF & & & 径向基函数,在大多数情况下都是一个很好的选择,
& & & & & & & & & & &– CvSVM::SIGMOID & sigmoid核函数,
& & degree &:核函数(POLY)的参数degree;
& & gamma :核函数(POLY/RBF/SIGMOID)的参数;
& & coef0 & :核函数(POLY/SIGMOID)的参数coef0;
& &Cvalue &:SVM优化问题(C_SVC/EPS_SVR/NU_SVR)的参数C;
& & nu &:SVM优化问题(NU_SVC/ONE_CLASS/NU_SVR)的参数;
& & p & :SVM优化问题(EPS_SVR)的参数;
& & class_weights :在C_SVC问题中可选的权重,指定给具体的类别。这样得到的结果就是class#i 变成了.所以这些权重是影响着不同类别的错误分类惩罚的程度的。更大的权值表示在相对的类的错误分类数据的更大的惩罚。
& & term_crit :解决受限二次优化问题的部分情况下迭代svm训练过程的终止条件。你可以指定tolerance 和/或者 最大迭代次数。
该默认构造函数的初始化内容是:
CvSVMParams::CvSVMParams() :
&span style=&white-space:pre&& &/span&svm_type(CvSVM::C_SVC), kernel_type(CvSVM::RBF), degree(0),
&span style=&white-space:pre&&
&/span&gamma(1), coef0(0), C(1), nu(0), p(0), class_weights(0)
term_crit = cvTermCriteria( CV_TERMCRIT_ITER+CV_TERMCRIT_EPS, 1000, FLT_EPSILON );
}终止条件结构函数:
CvTermCriteria
cvTermCriteria( int type, int max_iter, double epsilon )
t.max_iter = max_
t.epsilon = (float)
}该函数是内联函数,返回的值为CvTermCriteria结构体。看得出该函数还是c接口想使用c语言来模拟面向对象的结构,其中的参数为:
& & type:
& & & & & & - CV_TERMCRIT_ITER &在当算法迭代次数超过max_iter的时候终止。
& & & & & & - CV_TERMCRIT_EPS & 在当算法得到的精度低于epsolon时终止;
& & & & & & -CV_TERMCRIT_ITER+CV_TERMCRIT_EPS &当算法迭代超过max_iter或者当获得的精度低于epsilon的时候,哪个先满足就停止。
& & max_iter:
& & & & & & 迭代的最大次数;
& & epsilon:
& & & & & & 要求的精度
svm训练的函数原型:bool CvSVM::train(const Mat& trainData, const Mat& responses, const Mat& varIdx=Mat(), const&Mat& sampleIdx=Mat(), CvSVMParams params=CvSVMParams() );
& & & & & & & & & & & & & & & & & & & & bool CvSVM::train(const CvMat* trainData, const CvMat* responses, const CvMat* varIdx=0, const&CvMat* sampleIdx=0, CvSVMParams params=CvSVMParams() );
该方法是用来训练SVM模型的,它与通常的CvStatModel::train()(该函数为统计模型部分的一个函数,后面的不同分类器训练函数都与该函数类似,这里并没有仔细介绍该函数,所以下面的参数暂时没介绍,下面的约束条件帮助有限,留待我更新统计模型部分的介绍,然后引过来)有着一样便利的约束条件:
& & &a、只有CV_ROW_SAMPLE的数据分布才被支持;
& & &b、输入的变量都是有序的
& & &c、输出的变量可以是分类的((params.svm_type=CvSVM::C_SVC 或者&params.svm_type=CvSVM::NU_SVC) 或者有序的(params.svm_type=CvSVM::EPS_SVR 或者&params.svm_type=CvSVM::NU_SVR),或者根本没要求(params.svm_type=CvSVM::ONE_CLASS)。
&参数列表:
& & &d、不支持缺省的测量方法;
所有的其他参数都在CvSVMParams结构体中。
svm预测的函数原型: &float CvSVM::predict(const Mat& sample, bool returnDFVal=false ) const
& & & & & & & & & & & & & & & & & & & & &float CvSVM::predict(const CvMat* sample, bool returnDFVal=false ) const
& & & & & & & & & & & & & & & & & & & &&float CvSVM::predict(const CvMat* samples, CvMat* results) const;
参数列表:
& & & &sample:为了预测的输入样本;
& & & &samples:为了预测的输入的一群样本;
& & & &returnDFVal :指定返回值的类型。如果为true,而且问题是2分类,那么该方法返回的与边缘之间有符号距离的决策函数的值;不然该函数返回一个类别标签(分类)或者估计函数值(回归)。
& & & &return &:输出有关样本群的预测响应值。(就是针对许多样本得到的预测结果)
如果你传递一个样本那么就得到一个预测结果。如果你想传递几个样本那么急救该传递给results一个矩阵用来保存预测的结果。
得到支持向量的个数和某个支持向量的函数原型:int CvSVM::get_support_vector_count() const
& & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & const float* CvSVM::get_support_vector(int i) const
参数列表: i 用来索引某个具体的支持向量。
第一个函数返回支持向量的个数;第二个可以返回某个支持向量。
赠送一个,返回变量个数的函数原型:int CvSVM::get_var_count() const
该函数返回特征的数量(也就是变量的个数)
二、支持向量机对线性不可分数据的处理
& &为什么需要将支持向量机优化问题扩展到线性不可分的情形? 在多数计算机视觉运用中,我们需要的不仅仅是一个简单的SVM线性分类器, 我们需要更加强大的工具来解决&训练数据无法用一个超平面分割&的情形。我们以人脸识别来做一个例子,训练数据包含一组人脸图像和一组非人脸图像(除了人脸之外的任何物体)。
这些训练数据超级复杂,以至于为每个样本找到一个合适的表达 (特征向量) 以让它们能够线性分割是非常困难的。
& &还记得我们用支持向量机来找到一个最优超平面。 既然现在训练数据线性不可分,我们必须承认这个最优超平面会将一些样本划分到错误的类别中。 在这种情形下的优化问题,需要将&错分类(misclassification)&当作一个变量来考虑。新的模型需要包含原来线性可分情形下的最优化条件,即最大间隔(margin),
以及在线性不可分时分类错误最小化。
& &还是从最大化&间隔&这一条件来推导我们的最优化问题的模型(这在上面&已经讨论了):
& & & & & & & & & & & & & & & & & & & & & & &&
& & & & & & & & & & & & & & & & & & & & &
在这个模型中加入错分类变量有多种方法。比如,我们可以最小化一个函数,该函数定义为在原来模型的基础上再加上一个常量乘以样本被错误分类的次数:
然而,这并不是一个好的解决方案,其中一个原因是它没有考虑错分类的样本距离同类样本所属区域的大小。
因此一个更好的方法是考虑&错分类样本离同类区域的距离:
这里为每一个样本定义一个新的参数&&,
这个参数包含对应样本离同类区域的距离。 下图显示了两类线性不可分的样本,以及一个分割超平面和错分类样本距离同类区域的距离。
红色和蓝色直线表示各自区域的边际间隔, 每个&&表示从错分类样本到同类区域边际间隔的距离。
最后我们得到最优问题的最终模型:
关于参数C的选择, 明显的取决于训练样本的分布情况。 尽管并不存在一个普遍的答案,但是记住下面几点规则还是有用的:
& a、C比较大时分类错误率较小,但是间隔也较小。 在这种情形下, 错分类对模型函数产生较大的影响,既然优化的目的是为了最小化这个模型函数,那么错分类的情形必然会受到抑制。
& b、C比较小时,间隔较大,但是分类错误率也较大。在这种情形下,模型函数中错分类之和这一项对优化过程的影响变小,优化过程将更加关注于寻找到一个能产生较大间隔的超平面。
(这里的两个例子我都直接复制了完整的代码,而没有拆分成重要的函数说说,就是为了能更加的好理解,拆分成简单的几个函数是为了方便记忆,这里主要还是为了理解。后续修改3.0版本的时候有可能会删减!!)
#include &iostream&
#include &opencv2/core/core.hpp&
#include &opencv2/highgui/highgui.hpp&
#include &opencv2/ml/ml.hpp&
#define NTRAINING_SAMPLES
// 每个类别中训练样本的个数
#define FRAC_LINEAR_SEP
// 构成线性可分样本的分数,可以当成是为了将int类型转换成float类型的
using namespace cv;
using namespace std;
//该代码是使用两个不同的数据集来说明的即线性可分的数据和非线性可分的数据。
int main()
// 创建最后显示的画布
const int WIDTH = 512, HEIGHT = 512;
Mat I = Mat::zeros(HEIGHT, WIDTH, CV_8UC3);
//--------------------- 1. 随机生成训练数据 ---------------------------------------
Mat trainData(2*NTRAINING_SAMPLES, 2, CV_32FC1);//训练数据为2部分×100个样本/部分,行表示样本,列表是变量,即特征
Mat labels
(2*NTRAINING_SAMPLES, 1, CV_32FC1);//训练数据的标签
RNG rng(100); // 随机值生成器
// 建立数据的线性可分部分
int nLinearSamples = (int) (FRAC_LINEAR_SEP * NTRAINING_SAMPLES);
class 1 生成随机样本
Mat trainClass = trainData.rowRange(0, nLinearSamples);//类别1所占用的空间为行[0,nLinearSamples)
// x的坐标范围 [0, 0.4)
Mat c = trainClass.colRange(0, 1);//取第一列取值为[a,b)
rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(0.4 * WIDTH));//填充数值
// y的坐标范围 [0, 1)
c = trainClass.colRange(1,2);//取第二列
rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(HEIGHT));//填充数值
// class 2 生成随机样本
trainClass = trainData.rowRange(2*NTRAINING_SAMPLES-nLinearSamples, 2*NTRAINING_SAMPLES);
// x的坐标范围 [0.6, 1]
c = trainClass.colRange(0 , 1); //取第一列
rng.fill(c, RNG::UNIFORM, Scalar(0.6*WIDTH), Scalar(WIDTH));//填充数值
// y的坐标范围 [0, 1)
c = trainClass.colRange(1,2);//取第二列
rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(HEIGHT));//填充数值
//------------------ 为训练数据的第二个部分:线性不可分部分添加数据 ---------------
// 为 classes 1 and 2 随机生成样本点
trainClass = trainData.rowRange(
nLinearSamples, 2*NTRAINING_SAMPLES-nLinearSamples);
// x的坐标范围 [0.4, 0.6)
c = trainClass.colRange(0,1);//取第一列
rng.fill(c, RNG::UNIFORM, Scalar(0.4*WIDTH), Scalar(0.6*WIDTH)); //填充数值
// y的坐标范围 [0, 1)
c = trainClass.colRange(1,2);//取第二列
rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(HEIGHT));//填充数值
//------------------------- Set up the labels for the classes ---------------------------------
labels.rowRange(
NTRAINING_SAMPLES).setTo(1);
// Class 1的标签
labels.rowRange(NTRAINING_SAMPLES, 2*NTRAINING_SAMPLES).setTo(2);
// Class 2的标签
//------------------------ 2. 设置SVM的参数 --------------------
CvSVMParams params;
params.svm_type
= SVM::C_SVC;
params.kernel_type = SVM::LINEAR;
params.term_crit
= TermCriteria(CV_TERMCRIT_ITER, (int)1e7, 1e-6);
//------------------------ 3. 训练SVM ----------------------------------------------------
cout && &Starting training process& && endl;
CvSVM svm;
svm.train(trainData, labels, Mat(), Mat(), params);
cout && &Finished training process& && endl;
//------------------------ 4. 显示预测结果在画布上 ----------------------------------------
Vec3b green(0,100,0), blue (100,0,0);//不同类别的颜色
for (int i = 0; i & I.rows; ++i)
for (int j = 0; j & I.cols; ++j)
Mat sampleMat = (Mat_&float&(1,2) && i, j);
float response = svm.predict(sampleMat);//得到单个样本的预测值
(response == 1)
I.at&Vec3b&(j, i)
else if (response == 2)
I.at&Vec3b&(j, i)
//----------------------- 5. 将训练数据显示在画布上,使用小圆圈标记------------------------------------
int thick = -1;
int lineType = 8;
float px, py;
// Class 1
for (int i = 0; i & NTRAINING_SAMPLES; ++i)
px = trainData.at&float&(i,0);
py = trainData.at&float&(i,1);
circle(I, Point( (int) px,
(int) py ), 3, Scalar(0, 255, 0), thick, lineType);
// Class 2
for (int i = NTRAINING_SAMPLES; i &2*NTRAINING_SAMPLES; ++i)
px = trainData.at&float&(i,0);
py = trainData.at&float&(i,1);
circle(I, Point( (int) px, (int) py ), 3, Scalar(255, 0, 0), thick, lineType);
//------------------------- 6. 显示支持向量 --------------------------------------------
thick = 2;
= svm.get_support_vector_count();
for (int i = 0; i & x; ++i)
const float* v = svm.get_support_vector(i);
circle( I,
Point( (int) v[0], (int) v[1]), 6, Scalar(128, 128, 128), thick, lineType);
imwrite(&result.png&, I);
// save the Image
imshow(&SVM for Non-Linear Training Data&, I); // show it to the user
waitKey(0);
用随机数来填充数组的函数原型:void RNG::fill(InputOutputArray mat, int distType, InputArray a, InputArray b, bool saturateRange=&false );
参数列表:输入输出矩阵、分布类型、第一个分布的参数、第二个分布参数、饱和范围;
第一个参数:2D或者N维矩阵;当前的不支持超过4通道的矩阵,使用Mat::reshape()作为一个可能的解决方案;
第二个参数:分布蕾西,RNG::UNIFORM或者RNG::NORMAL.(即是均匀分布还是正太分布)
第三个参数:第一个分布参数;在均匀分布中,这是一个包含的下限值;在正太分布中,这是一个均值;
第四个参数:第二个分布参数:在均匀分布中,这是一个不包含的上限值;在正太分布中,这是一个标准差(标准差矩阵的对角线或者 & & & & & 全标准差矩阵,此处疑问,是两个矩阵的对角线还是前面那个矩阵的对角线???)。
第五个参数:预饱和标识;只对均匀分布有效;如果该值为true,该方法会首先将a和b转换成可接受的值的范围(按照mat的数据类 & & & & & & & 型)然后用范围【saturate(a),saturate(b))来生成均匀分布的随机值;如果该值为false,该方法会首先按照原 & & & & 始的范围【a,b)生成均匀分布随机值,然后进行饱和操作,也就是说,例如RNG().fill(mat_8u,
RNG::UNIFORM, -DBL_MAX, & & & & &DBL_MAX),将会生成一个数组差不多用0和255填满的数组,因为范围(0,255)明显小于&【-DBL_MAX, DBL_MAX)。
& &每个使用随机值来填充矩阵的方法都来自特定的分布。RNG的状态也是按照新生成的值更新的。在多通道图像的情况中,每个通道都是独立填充的,也就是说RNG不会直接从非对焦协方差矩阵的多维度高斯分布中采样。所以该方法是从有着0均值和单一协方差矩阵的多维度标准高斯分布中进行采样的,然后接着使用ransform()来转换生成具体的高斯分布的样本值。
对一个矩阵头生成具体的行范围的函数原型:Mat Mat::rowRange(int startrow, int endrow) const
& & & & & & & & & & & & & & & & & & & & & Mat Mat::rowRange(const Range& r) const;
参数列表:
& & startrow: 一个基于0索引的行范围的开始,包含
& & endrow &:一个基于0索引的行范围的结束,不包含
& & r :Range结构,用来包含开始和结束索引。
对一个矩阵头生成具体的列范围的函数原型:Mat Mat::colRange(int startcol, int endcol) const
& & & & & & & & & & & & & & & & & & & & & &Mat Mat::colRange(const Range& r) const;
参数列表:&
& & startrow: 一个基于0索引的列范围的开始,包含
& & endrow &:一个基于0索引的列范围的结束,不包含
& & r :Range结构,用来包含开始和结束索引。
上面两个方法都是用来对一个新的矩阵头指定需要生成的行列区域,相似于Mat::row()和Mat::col(),而且复杂度是O(1).
相对于最上面的终止方法的类class TermCriteria:
class CV_EXPORTS TermCriteria{
COUNT=1, //!& the maximum number of iterations or elements to compute
MAX_ITER=COUNT, //!& ditto
EPS=2 //!& the desired accuracy or change in parameters at which the iterative algorithm stops
//! default constructor
TermCriteria();
//! full constructor
TermCriteria(int type, int maxCount, double epsilon);
//! conversion from CvTermCriteria
TermCriteria(const CvTermCriteria& criteria);
//! conversion to CvTermCriteria
operator CvTermCriteria()
//!& the type of termination criteria: COUNT, EPS or COUNT + EPS
int maxC // the maximum number of iterations/elements
// the desired accuracy
该类用来为迭代算法定义终止标准。你可以通过默认构造函数进行初始化然后重载任何参数,或者这个结构可以完全使用构造函数的高级变量来全部的初始化。
TermCriteria类的构造函数:TermCriteria::TermCriteria()
& & & & & & & & & & & & & TermCriteria::TermCriteria(int type, int maxCount, double epsilon)
& & & & & & & & & & & & & TermCriteria::TermCriteria(const CvTermCriteria& criteria)
参数列表:
& & & & &type :终止标准的类型:TermCriteria::COUNT, TermCriteria::EPS 或者&TermCriteria::COUNT + TermCriteria::EPS;
& & & & maxCount:迭代或者计算元素的最大次数;
& & & & epsilon:在迭代算法停止是参数改变所需要达到的精度要求;
& & & & criteria:在弃用的CvTermCriteria格式中的终止条件。
转换到弃用的CvTermCriteria格式的函数原型:TermCriteria::operator CvTermCriteria() const (在3.0版本中已经移除该函数)
&&相关文章推荐
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:91038次
积分:2190
积分:2190
排名:第15943名
原创:120篇
评论:32条
(3)(6)(2)(1)(2)(8)(6)(34)(4)(5)(8)(1)(15)(9)(11)(11)(6)(1)

我要回帖

更多关于 人教版四年级下册语文 的文章

 

随机推荐