SiriBlog

siriyang的个人博客


  • 首页

  • 排行榜

  • 标签115

  • 分类37

  • 归档321

  • 关于

  • 搜索

OpenCV3中SVM的使用

发表于 2020-03-03 更新于 2021-10-29 分类于 计算机 , 技术 , C/C++ 阅读次数: Valine:
本文字数: 6.3k 阅读时长 ≈ 6 分钟

SVM介绍

  这部分的理论知识参考之前写的文章:“吴恩达机器学习”学习笔记

OpenCV3.x下SVM接口介绍

  官方文档

  OpenCV3.x与OpenCV2.x中SVM的接口有了很大变化,在接口上使用了虚函数取代以前的定义。
  下面介绍几个常用的接口,及其参数意义。

初始化函数

  定义如下:

1
CV_WRAP static Ptr<SVM> create();

参数设置函数

  然后是一些设置SVM参数的函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
CV_WRAP virtual int getType() const = 0;
CV_WRAP virtual void setType(int val) = 0;

CV_WRAP virtual double getGamma() const = 0;
CV_WRAP virtual void setGamma(double val) = 0;

CV_WRAP virtual double getDegree() const = 0;
CV_WRAP virtual void setDegree(double val) = 0;

CV_WRAP virtual double getC() const = 0;
CV_WRAP virtual void setC(double val) = 0;

CV_WRAP virtual double getNu() const = 0;
CV_WRAP virtual void setNu(double val) = 0;

CV_WRAP virtual double getP() const = 0;
CV_WRAP virtual void setP(double val) = 0;

CV_WRAP virtual cv::Mat getClassWeights() const = 0;
CV_WRAP virtual void setClassWeights(const cv::Mat &val) = 0;

CV_WRAP virtual cv::TermCriteria getTermCriteria() const = 0;
CV_WRAP virtual void setTermCriteria(const cv::TermCriteria &val) = 0;

CV_WRAP virtual int getKernelType() const = 0;
CV_WRAP virtual void setKernel(int kernelType) = 0;

  具体的作用可以参考OpenCV文档,这里只介绍两个常用的函数:

1
2
//设置SVM类型
CV_WRAP virtual int getType() const = 0;

  这个函数用于设置SVM类型,OpenCV提供了五种类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Types { 
//C类支持向量分类机。 n类分组 (n≥2),容许用异常值处罚因子C进行不完全分类。
C_SVC =100,

//NU类支持向量机
NU_SVC =101,

//分布估计(单分类器),所有的练习数据提取自同一个类里,
//然后SVM建树了一个分界线以分别该类在特征空间中所占区域和其它类在特征空间中所占区域。
ONE_CLASS =102,

EPS_SVR =103,

NU_SVR =104
}

  注解:NU即$\nu$,EPS即$\epsilon$。SVC为分类模型,SVR为回归模型。

  一般我们使用SVM进行二分类或者多分类任务,选择第一种SVM::C_SVC即可。
  还有一个函数就是:

1
CV_WRAP virtual void setKernel(int kernelType) = 0;

  这个函数用于设置SVM的核函数类型,我们知道,通过选择SVM的核函数可以使SVM处理高阶、非线性问题。OpenCV提供几种核函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
enum KernelTypes {
/** Returned by SVM::getKernelType in case when custom kernel has been set */
CUSTOM=-1,

//线性核
LINEAR=0,

//多项式核
POLY=1,

//径向基核(高斯核)
RBF=2,

//sigmoid核
SIGMOID=3,

//指数核,与高斯核类似
CHI2=4,

//直方图核
INTER=5
};

  一般情况下使用高斯核函数可以很好处理大部分情况。

训练函数

  OpenCV3.x中SVM的提供了训练函数也与2.x不同,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
virtual bool trainAuto( const Ptr<TrainData>& data, int kFold = 10,
ParamGrid Cgrid = getDefaultGrid(C),
ParamGrid gammaGrid = getDefaultGrid(GAMMA),
ParamGrid pGrid = getDefaultGrid(P),
ParamGrid nuGrid = getDefaultGrid(NU),
ParamGrid coeffGrid = getDefaultGrid(COEF),
ParamGrid degreeGrid = getDefaultGrid(DEGREE),
bool balanced=false) = 0;

bool trainAuto (InputArray samples, int layout, InputArray responses,
int kFold=10, Ptr< ParamGrid > Cgrid=SVM::getDefaultGridPtr(SVM::C),
Ptr< ParamGrid > gammaGrid=SVM::getDefaultGridPtr(SVM::GAMMA),
Ptr< ParamGrid > pGrid=SVM::getDefaultGridPtr(SVM::P),
Ptr< ParamGrid > nuGrid=SVM::getDefaultGridPtr(SVM::NU),
Ptr< ParamGrid > coeffGrid=SVM::getDefaultGridPtr(SVM::COEF),
Ptr< ParamGrid > degreeGrid=SVM::getDefaultGridPtr(SVM::DEGREE),
bool balanced=false)

  trainAuto可以在训练过程中自动优化SVM中的那些参数,而使用train函数时,参数被固定,所以推荐使用trainAuto函数。
  在准备训练数据的时候,有下面几点需要注意,否则函数会报错

  1. SVM的训练函数是ROW_SAMPLE类型的,也就是说,送入SVM训练的特征需要reshape成一个行向量,所有训练数据全部保存在一个Mat中,一个训练样本就是Mat中的一行,最后还要讲这个Mat转换成CV_32F类型,例如,如果有k个样本,每个样本原本维度是$(h,w)$,则转换后Mat的维度为$(k,h∗w)$
  2. 对于多分类问题,label矩阵的行数要与样本数量一致,也就是每个样本要在label矩阵中有一个对应的标签,label的列数为1,因为对于一个样本,SVM输出一个值,我们在训练前需要做的就是设计这个值与样本的对应关系。对于有k个样本的情况,label的维度是$(k,1)$

预测函数

  函数定义如下:

1
float predict(cv::InputArrat samples, cv::OutputArray results = noArray(), int flags = 0) const;

  其中samples就是需要预测的样本,这里样本同样要转换成ROW_SAMPLE和CV_32F格式,对于单个测试样本的情况,预测结果直接通过函数返回值返回,而如果samples中有多个样本,就需要传进result参数,预测结果以列向量的方式保存在result数组中。假如有k个样本,每个样本原本的维度为$(h,w)$,则samples的维度为$(k,h∗w)$,最终预测结果result维度为$(k,1)$

样例程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/ml/ml.hpp"

#include <iostream>

using namespace std;
using namespace cv;
using namespace cv::ml;

struct ppt
{
float x;
float y;
char label;
};

int main()
{
//训练一个简单的svm模型
// step 1: 标记分类
int labels[14] = { 'A','A','A','A','A','A','A','B','B','B','B','B','B','B' };
//CvMat labelsMat = cvMat(14, 1, CV_32FC1, labels);
Mat labelsMat(14, 1, CV_32SC1);
for (int i = 0; i < labelsMat.rows; i++)
{
labelsMat.at<int>(i, 0) = labels[i];
}

//训练数据
int trainingData[14][2] = { { 110,204 },{ 105,306 },{ 102,410 },{ 99,511 },{ 93,610 },{ 89,713 },
{ 89,817 },{ 173,208 },{ 175,313 },{ 167,415 },{ 163,514 },{ 160,612 },{ 156,716 },{ 152,819 } };

Mat trainingDataMat(14, 2, CV_32FC1);
for (int i = 0; i < trainingDataMat.rows; i++)
{
for (int j = 0; j < trainingDataMat.cols; j++)
{
trainingDataMat.at<float>(i, j) = trainingData[i][j];
}
}

//查看训练数据分布
Mat plot(900, 900, CV_8U);
vector<Point> myPoint(14);//14个点
for (int i = 0; i < myPoint.size(); i++)
{
myPoint[i].x = trainingData[i][0];
myPoint[i].y = trainingData[i][1];
circle(plot, myPoint[i], 15, Scalar(255), -1);
}
namedWindow("坐标点", 0);
imshow("坐标点", plot);

//step 2:设定训练参数
Ptr<SVM> svm = SVM::create();
svm->setType(SVM::C_SVC);
svm->setKernel(SVM::LINEAR);
//迭代训练过程的中止条件,解决部分受约束二次最优问题。您可以指定的公差和或最大迭代次数。
svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 100, FLT_EPSILON));

//step 3:训练
Ptr<TrainData> tData = TrainData::create(trainingDataMat, ROW_SAMPLE, labelsMat);
svm->train(tData);
svm->save("svmData.xml");

// step 4: 利用训练好的模型进行预测
ppt a;
a.x = 163;
a.y = 600;
float data[2] = { a.x,a.y };
Mat tmp(1, 2, CV_32FC1);
for (int j = 0; j < tmp.cols; j++)
{
tmp.at<float>(0, j) = data[j];
}

a.label = (char)svm->predict(tmp);
cout << a.label << endl;

}
参考资料
  • [OpenCV随笔]-OpenCV3.x中SVM多分类使用(代码篇)
  • 【OpenCV】OpenCV3.2使用svm训练Demo
-------- 本文结束 感谢阅读 --------
相关文章
  • OpenCV3使用中遇到的一些问题
  • 中医药天池大数据竞赛--中药说明书实体识别挑战
  • NLP综合实践(三)
  • NLP综合实践(二)
  • NLP综合实践(一)
觉得文章写的不错的话,请我喝瓶怡宝吧!😀
SiriYang 微信支付

微信支付

SiriYang 支付宝

支付宝

  • 本文标题: OpenCV3中SVM的使用
  • 本文作者: SiriYang
  • 创建时间: 2020年03月03日 - 16时03分
  • 修改时间: 2021年10月29日 - 18时10分
  • 本文链接: https://blog.siriyang.cn/posts/20200303165233id.html
  • 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!
学习笔记 机器学习 OpenCV
2020重庆邮电大学计算机专硕考研经验总结
C语言基础编程练习题
  • 文章目录
  • 站点概览
SiriYang

SiriYang

努力搬砖攒钱买镜头的摄影迷
321 日志
33 分类
88 标签
RSS
GitHub E-Mail
Creative Commons
Links
  • 友情链接
  • 作品商铺

  1. SVM介绍
  2. OpenCV3.x下SVM接口介绍
    1. 初始化函数
    2. 参数设置函数
    3. 训练函数
    4. 预测函数
  3. 样例程序
蜀ICP备19008337号 © 2019 – 2025 SiriYang | 1.7m | 25:48
0%