OpenCV中的「SVM分类器」:基本原理、函数解析和示例代码

article/2025/10/6 8:39:14

文章目录

    • 1. 引言
    • 2. 基本原理
    • 3. 函数解析
      • 创建模型
      • 设置模型类型
      • 设置参数C
      • 设置核函数
      • 设置迭代算法的终止标准
      • 训练SVM模型
      • 预测结果
      • 误差计算
      • 保存SVM模型
      • 从文件中加载SVM
    • 4. 示例代码
      • 官方示例(python)
      • 推理阶段(C++版本)
    • 5. 小结

1. 引言

opencv中集成了基于libsvm1实现的SVM接口,便于直接进行视觉分类任务。

对于数据处理和可视化需求来说,可以用python接口opencv的SVM更加直观方便。

训练完模型后,将SVM模型保存为xml,可以在实时性应用中通过C++接口调用参数文件,进行实时推断。

在非均衡样本的分类训练中,用opencv中SVM默认的train函数,容易导致分类器偏向数量多的类别,这时可以采用trainAuto函数进行平衡。

如果你对SVM的原理有一定了解,可以直接跳转第3、4小节。

2. 基本原理

在这里插入图片描述

SVM旨在找到一个划分超平面,使得划分后的分类结果是最鲁棒的,对未见过的样本泛化性最好2

在样本空间中,划分超平面可以用这个方程进行描述: w T x + b = 0 \boldsymbol{w}^T\boldsymbol{x}+b=0 wTx+b=0,其中 w = ( w 1 ; w 2 ; . . . ; w d ) \boldsymbol{w}=(w_1;w_2;...;w_d) w=(w1;w2;...;wd)为法向量,决定超平面的方向,b为位移项,决定超平面与原点之间的距离。

对于线性可分的样本空间,需要找到具有最大间隔(maximum margin)的划分超平面,即找到能使下式最大化的参数 w \boldsymbol{w} w和b2
min ⁡ w , b 1 2 ∣ ∣ w ∣ ∣ 2 \min_{w,b}{\frac{1}{2}||\boldsymbol{w}||^2} w,bmin21w2s.t. y i ( w T x i + b ) ≥ 1 , i = 1 , 2 , . . . , m y_i(\boldsymbol{w}^T\boldsymbol{x_i}+b)≥1,i=1,2,...,m yi(wTxi+b)1,i=1,2,...,m

对于线性不可分的样本空间,可以将样本从原始空间映射到另一个高维特征空间,从而使样本在这个特征空间内线性可分。由于特征空间的维数可能很高,难以计算,所以通过引入核函数,可以将高维特征空间中的内积(dot product)转化为低维特征空间中的通过核函数计算的结果。

常用核函数2
在这里插入图片描述

为了减少过拟合,引入软间隔(soft margin)概念,允许支持向量机在一些样本上出错:
y i ( w T x i + b ) ≥ 1 y_i(\boldsymbol{w}^T\boldsymbol{x_i}+b)≥1 yi(wTxi+b)1

用参数C来约束分类出错的样本,松弛变量 ξ i ξ_i ξi表示训练样本距离对应的正确决策边界的距离,对于分类正确的样本距离即为03,所以实际累加的是出错样本的距离。

在这里插入图片描述

优化问题调整为:
m i n w , b 0 ∣ ∣ w ∣ ∣ 2 + C ∑ i ξ i min_{\boldsymbol{w},b_0}{||\boldsymbol{w}||^2+C\sum_i{ξ_i}} minw,b0w2+Ciξi

s.t. y i ( w T x i + b 0 ) ≥ 1 − ξ i , 且 ξ i ≥ 0 ∀ i y_i(\boldsymbol{w}^T\boldsymbol{x_i}+b_0)≥1-ξ_i,且ξ_i≥0 ∀i yi(wTxi+b0)1ξi,ξi0i

3. 函数解析

SVM类在opencv中的继承关系如图所示4

在这里插入图片描述
SVM继承自StatModel和Algorithm类。

在opencv中使用SVM的一般流程如下:

训练
推理
开始
创建SVM模型
加载SVM模型
配置参数
加载训练数据
模型训练
保存模型
输入数据进行预测

创建模型

C++:

static Ptr<SVM> cv::ml::SVM::create()

Python:

cv.ml.SVM_create() -> retval

设置模型类型

C++:

enum  Types {C_SVC =100,//C-支持向量分类。n级分类(n≥ 2) 允许使用异常值的惩罚乘数 C 不完全地分离类。NU_SVC =101,//ν-支持向量分类。n级分类,可能有不完美的分离。参数ν用于代替C,参数ν在0-1范围内,值越大,决策边界越平滑。ONE_CLASS =102,//分布估计,所有的训练数据都来自同一个类,SVM 构建了一个边界,将类与特征空间的其余部分分开。EPS_SVR =103,//ε-支持向量回归。来自训练集的特征向量和拟合超平面之间的距离必须小于p。对于异常值,使用惩罚乘数 C。NU_SVR =104 // ν-支持向量回归。 ν用于代替 p。
}
virtual void cv::ml::SVM::setType(int val)

Python:

cv.ml_SVM.setType(val) ->None

设置参数C

根据"2.基本原理"中对参数C的介绍,我们应该如何设置参数C?

  • C值较大时:误分类错误较少,但余量较小。这种情况下,侧重于寻找具有很少的误分类错误的超平面。
  • C值较小时:具有更大余量和更多分类错误。在这种情况下,更侧重于寻找具有大余量的超平面。

C++:

//设置参数C
virtual void cv::ml::SVM::setC(double val)

python:

cv.ml_SVM.setC(val) -> None

设置核函数

C++:

enum KernelTypes {CUSTOM =-1,//由SVM::getKernelType返回,默认是RBFLINEAR =0,//线性内核,速度最快POLY =1,//多项式核RBF =2,//径向基函数(RBF),大多数情况下是个不错的选择SIGMOID =3,//sigmoid核CHI2 =4,//Chi2核,类似于RBF核INTER =5//直方图交叉核,速度较快
}
virtual void cv::ml::SVM::setKernel(int kernelType)    

python:

cv.ml_SVM.setKernel(kernelType) -> None

设置迭代算法的终止标准

C++:

virtual void cv::ml::SVM::setTermCriteria(const cv::TermCriteria &val)    // cv::TermCriteria
cv::TermCriteria::TermCriteria (int type,int maxCount,double epsilon)// Type 
enum  cv::TermCriteria::Type {COUNT =1,MAX_ITER =COUNT,//最大迭代次数EPS =2 //迭代算法停止时所需的精度或参数变化
}

python:

cv.ml_SVM.setTermCriteria(val) ->None

训练SVM模型

trainAuto方法通过选择最佳参数 C、gamma、p、nu、coef0、degree 来自动训练 SVM 模型。当测试集误差的交叉验证估计最小时,参数被认为是最佳的。此函数仅使用SVM::getDefaultGrid进行参数优化,因此仅提供基本的参数选项。

trainAuto函数适用于分类(SVM::C_SVC或SVM::NU_SVC)以及回归(SVM::EPS_SVR或SVM::NU_SVR)。如果是SVM::ONE_CLASS,则不进行优化,并执行带有 params 中指定参数的常用 SVM。

C++:

//输入由TrainData::create或TrainData::loadFromCSV构造的训练数据
virtual bool cv::ml::SVM::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 
)    //输入训练样本
bool cv::ml::SVM::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 
) 

Python:

cv.ml_SVM.trainAuto(samples, layout, responses[, kFold[, Cgrid[, gammaGrid[, pGrid[, nuGrid[, coeffGrid[, degreeGrid[, balanced]]]]]]]]) -> retval

参数:

  • samples:训练样本
  • layout:参考 ml::SampleTypes,如cv.ml.ROW_SAMPLE表示每个训练样本是行向量,cv.ml.COL_SAMPLE表示每个训练样本是列向量
  • responses:与训练样本有关的响应向量
  • kFold:k交叉验证,训练集会分成k个子集,从中选取一个用来测试,剩余k-1个用来训练
  • balanced:如果设为True且是2-class分类问题,方法会自动创建更平衡的交叉验证子集,即子集中的类之间比例接近整个训练数据集中的比例

预测结果

C++:

// 预测输入样本的响应结果
virtual float predict(InputArray  samples,                  // input samples, float matrixOutputArray results = cv::noArray(),  // optional output results matrixint         flags   = 0               // (model-dependent)
) const = 0;

python:

cv.ml_StatModel.predict(samples[, results[, flags]]) ->retval, results

误差计算

对于回归模型,误差计算为 RMS;对于分类器,误差计算为错误分类样本的百分比 (0%-100%)。
C++:

// 在训练集或测试集上计算误差
virtual float calcError(const Ptr<TrainData>& data, // training samplesbool test, // true: compute over test set// false: compute over training setcv::OutputArray resp  // the optional output responses
) const;

python:

cv.ml_StatModel.calcError(data, test[, resp]) ->retval, resp

保存SVM模型

C++:

void cv::Algorithm::save(const String &filename)  const

Python:

cv.Algorithm.save(filename) ->None

从文件中加载SVM

C++:

static Ptr<SVM> cv::ml::SVM::load(const String &filepath)

Python:

cv.ml.SVM_load(filepath) ->retval

4. 示例代码

官方示例(python)

在这里插入图片描述
构造数据,用来模拟训练集中的两个类别:

from __future__ import print_function
import cv2 as cv
import numpy as np
import random as rng
import time
from matplotlib import pyplot as pltNTRAINING_SAMPLES = 100 # 每个类别的训练样本数
FRAC_LINEAR_SEP = 0.9   # 线性可分的样本比例# 准备用于数据可视化
WIDTH = 512
HEIGHT = 512
I = np.zeros((HEIGHT, WIDTH, 3), dtype=np.uint8)# 设置训练样本
trainData = np.empty((2*NTRAINING_SAMPLES, 2), dtype=np.float32)
labels = np.empty((2*NTRAINING_SAMPLES, 1), dtype=np.int32)rng.seed(100) # Random value generation class# 线性可分的训练样本数量
nLinearSamples = int(FRAC_LINEAR_SEP * NTRAINING_SAMPLES)## [setup1]
# 生成class 1的随机点,随机点的x坐标在[0, 0.4),y坐标在 [0, 1)
trainClass = trainData[0:nLinearSamples,:]
# The x coordinate of the points is in [0, 0.4)
c = trainClass[:,0:1]
c[:] = np.random.uniform(0.0, 0.4 * WIDTH, c.shape)
# The y coordinate of the points is in [0, 1)
c = trainClass[:,1:2]
c[:] = np.random.uniform(0.0, HEIGHT, c.shape)# 生成class 2的随机点,随机点的x坐标在[0.6, 1],y坐标在 [0, 1)
trainClass = trainData[2*NTRAINING_SAMPLES-nLinearSamples:2*NTRAINING_SAMPLES,:]
# The x coordinate of the points is in [0.6, 1]
c = trainClass[:,0:1]
c[:] = np.random.uniform(0.6*WIDTH, WIDTH, c.shape)
# The y coordinate of the points is in [0, 1)
c = trainClass[:,1:2]
c[:] = np.random.uniform(0.0, HEIGHT, c.shape)# 设置线性不可分的训练样本 
# Generate random points for the classes 1 and 2
trainClass = trainData[nLinearSamples:2*NTRAINING_SAMPLES-nLinearSamples,:]
# x坐标在 [0.4, 0.6),y坐标在[0, 1)
c = trainClass[:,0:1]
c[:] = np.random.uniform(0.4*WIDTH, 0.6*WIDTH, c.shape)
c = trainClass[:,1:2]
c[:] = np.random.uniform(0.0, HEIGHT, c.shape)# 设置两个类别的label
labels[0:NTRAINING_SAMPLES,:] = 1                   # Class 1
labels[NTRAINING_SAMPLES:2*NTRAINING_SAMPLES,:] = 2 # Class 2

设置SVM参数,初始化模型:

print('Starting training process')
svm = cv.ml.SVM_create()
svm.setType(cv.ml.SVM_C_SVC)
svm.setC(0.1)
svm.setKernel(cv.ml.SVM_LINEAR)
svm.setTermCriteria((cv.TERM_CRITERIA_MAX_ITER, int(1e7), 1e-6))

训练SVM:

## 训练
svm.train(trainData, cv.ml.ROW_SAMPLE, labels)
print('Finished training process')## 显示决策区域
green = (0,100,0)
blue = (100,0,0)
for i in range(I.shape[0]):for j in range(I.shape[1]):sampleMat = np.matrix([[j,i]], dtype=np.float32)response = svm.predict(sampleMat)[1]if response == 1:I[i,j] = greenelif response == 2:I[i,j] = blue

对训练集中两个类别的样本进行可视化:

## 用两种颜色圆圈表示class 1和class 2的训练数据
thick = -1
# Class 1
for i in range(NTRAINING_SAMPLES):px = trainData[i,0]py = trainData[i,1]cv.circle(I, (px, py), 3, (0, 255, 0), thick)# Class 2
for i in range(NTRAINING_SAMPLES, 2*NTRAINING_SAMPLES):px = trainData[i,0]py = trainData[i,1]cv.circle(I, (px, py), 3, (255, 0, 0), thick)# 显示支持向量(
## [show_vectors]
thick = 2
sv = svm.getUncompressedSupportVectors()for i in range(sv.shape[0]):cv.circle(I, (sv[i,0], sv[i,1]), 6, (128, 128, 128), thick)
## [show_vectors]#cv.imwrite('result.png', I)                      # save the Image
#cv.imshow('SVM for Non-Linear Training Data', I) # show it to the user
plt.imshow(I)

推理阶段(C++版本)

void test_svm(std::string videopath, std::string svm_file = "svm.mat")
{/// 加载svm模型参数cv::Ptr<cv::ml::SVM> svm = cv::ml::SVM::load(svm_file);/// 初始化特征提取器// 此处省略……cv::VideoCapture cap(videopath);if (cap.isOpened()){cv::Mat src;//imgint sleep_interval = 1;//每隔多少ms取帧int frameIdx = 0;while (true){if (!cap.read(src)){break;}frameIdx++;double start = static_cast<double>(cv::getTickCount());cv::Mat flowFeat;//提取运动特征m_featureExtactor.ProcessFlow(src, flowFeat);flowFeat.convertTo(flowFeat, CV_32FC1);//获取分类结果int response = (int)svm->predict(flowFeat);cv::putText(src, cv::String(std::to_string(response)), cv::Point(20,20), cv::FONT_HERSHEY_PLAIN, 1, cv::Scalar(0, 255, 0));  //计算耗时float times = ((float)cv::getTickCount() - start) / cv::getTickFrequency();std::cout << "time cost: " << times << " s." << std::endl;cv::imshow("img", src);if (cv::waitKey(1) == 27) {break;}}}
}

5. 小结

本文整理了Opencv中SVM支持向量机的原理、函数和代码示例。

如果对你有帮助的话,欢迎一键三连支持下博主~


  1. Chih-Chung Chang and Chih-Jen Lin. Libsvm: a library for support vector machines. ACM Transactions on Intelligent Systems and Technology (TIST), 2(3):27, 2011. ↩︎

  2. 《机器学习》周志华 ↩︎ ↩︎ ↩︎

  3. https://docs.opencv.org/4.5.3/d4/db1/tutorial_py_svm_basics.html ↩︎

  4. https://docs.opencv.org/4.5.3/d1/d2d/classcv_1_1ml_1_1SVM.html ↩︎


http://chatgpt.dhexx.cn/article/bugRYAGL.shtml

相关文章

2.1.SVM线性分类器

文章目录 1.笔记总结1.1.Small Questions1.1.1.图像xi的定义&#xff0c;行列的问题1.1.2.np.hstack函数1.1.3.np.random.randn(&#xff09;正态分布随机数函数 1.2.最优化损失函数1.2.1.寻找更好的W的方法 1.2.2梯度下降1.2.2.1.数值梯度1.2.2.2.实际应用中的梯度下降 2.SVM的…

svm多分类器详解

项目github地址&#xff1a;bitcarmanlee easy-algorithm-interview-and-practice 欢迎大家star&#xff0c;留言&#xff0c;一起学习进步 SVM是一种典型的两类分类器&#xff0c;即它只回答属于正类还是负类的问题。而现实中要解决的问题&#xff0c;往往是多类的问题&#…

SVM学习(六):将SVM用于多类分类

从 SVM的那几张图可以看出来&#xff0c;SVM是一种典型的两类分类器&#xff0c;即它只回答属于正类还是负类的问题。而现实中要解决的问题&#xff0c;往往是多类的问题&#xff08;少部分例外&#xff0c;例如垃圾邮件过滤&#xff0c;就只需要确定“是”还是“不是”垃圾邮件…

分类算法SVM(支持向量机)

支持向量机&#xff08;Support Vector Machine ,SVM&#xff09;的主要思想是&#xff1a;建立一个最优决策超平面&#xff0c;使得该平面两侧距离该平面最近的两类样本之间的距离最大化&#xff0c;从而对分类问题提供良好的泛化能力。对于一个多维的样本集&#xff0c;系统随…

SVM分类算法

1.基本概念 支持向量机&#xff08;SVM&#xff09;的基本模型是在特征空间上找到最佳的分离超平面使得训练集上正负样本间隔最大。SVM是用来解决二分类问题的有监督学习算法&#xff0c;在引入了核方法之后SVM也可以用来解决非线性问题。 实际应用中一般要解决觉得是多分类问…

SVM分类器详解

SVM入门&#xff08;一&#xff09;至&#xff08;三&#xff09;Refresh 按:之前的文章重新汇编一下,修改了一些错误和不当的说法&#xff0c;一起复习,然后继续SVM之旅. &#xff08;一&#xff09;SVM的八股简介 支持向量机(Support Vector Machine)是Cortes和Vapnik于1995…

Svm实现多分类

机器学习---Svm实现多分类详解 Svm实现多类分类原理代码实现训练的图片 Svm实现多类分类原理 1.支持向量机分类算法最初只用于解决二分类问题&#xff0c;缺乏处理多分类问题的能力。后来随着需求的变化&#xff0c;需要svm处理多分类分为。目前构造多分类支持向 量机分类器的…

SVM学习(二):线性分类器

1.线性分类器概念 线性分类器(一定意义上,也可以叫做感知机) 是最简单也很有效的分类器形式.在一个线性分类器中,可以看到SVM形成的思路,并接触很多SVM的核心概念。用一个二维空间里仅有两类样本的分类问题来举个小例子。如图所示&#xff1a; C1和C2是要区分的两个类别&#x…

机器学习笔记之(5)——SVM分类器

本博客为SVM分类器的学习笔记~由于仅仅是自学的笔记&#xff0c;大部分内容来自参考书籍以及个人理解&#xff0c;还请广大读者多多赐教 主要参考资料如下&#xff1a; 《机器学习实战》《Python机器学习》《机器学习Python实践》《Python机器学习算法》《Python大战机器学习》…

机器学习之SVM分类器介绍——核函数、SVM分类器的使用

系类文章目录 机器学习算法——KD树算法介绍以及案例介绍 机器学习的一些常见算法介绍【线性回归&#xff0c;岭回归&#xff0c;套索回归&#xff0c;弹性网络】 文章目录 一、SVM支持向量机介绍 1.1、SVM介绍 1.2、几种核函数简介 a、sigmoid核函数 b、非线性SVM与核函…

SVM分类器(matlab)

源自&#xff1a;https://blog.csdn.net/lwwangfang/article/details/52351715 支持向量机&#xff08;Support Vector Machine&#xff0c;SVM)&#xff0c;可以完成对数据的分类&#xff0c;包括线性可分情况和线性不可分情况。1、线性可分 首先&#xff0c;对于SVM来说&…

线性分类器(SVM,softmax)

目录 导包和处理数据 数据预处理--减平均值和把偏置并入权重 SVM naive版 向量版 Softmax navie版 向量版 线性分类器--采用SGD算法 SVM版线性分类 Softmax版线性分类 使用验证集调试学习率和正则化系数 画出结果 测试准确率 可视化权重 值得注意的地方 赋值 ran…

SVM多分类的两种方式

以下内容参考&#xff1a;https://www.cnblogs.com/CheeseZH/p/5265959.html http://blog.csdn.net/rainylove1/article/details/32101113 王正海《基于决策树多分类支持向量机岩性波谱分类》 SVM本身是一个二值分类器&#xff0c;SVM算法最初是为二值分类问题设计的&#xff0…

使用SVM分类器进行图像多分类

ResNet backbone SVM分类器 对于样本较为均衡小型数据集&#xff0c;SVM作为分类器的效果与MLP的效果相近。 从经验上看&#xff0c;对于样本不均衡的大型数据集&#xff0c;MLP的效果强于SVM。 本博客在自己的小型数据集上进行实验&#xff0c;本来使用MLP已经达到很好的效果…

SVM分类器原理详解

第一层、了解SVM 支持向量机&#xff0c;因其英文名为support vector machine&#xff0c;故一般简称SVM&#xff0c;通俗来讲&#xff0c;它是一种二类分类模型&#xff0c;其基本模型定义为特征空间上的间隔最大的线性分类器&#xff0c;其学习策略便是间隔最大化&#xff0c…

【CV-Learning】线性分类器(SVM基础)

数据集介绍&#xff08;本文所用&#xff09; CIFAR10数据集 包含5w张训练样本、1w张测试样本&#xff0c;分为飞机、汽车、鸟、猫、鹿、狗、蛙、马、船、卡车十个类别&#xff0c;图像均为彩色图像&#xff0c;其大小为32*32。 图像类型&#xff08;像素表示&#xff09; 二…

支持向量机通俗导论(理解SVM的三层境界)

支持向量机通俗导论(理解SVM的三层境界) 作者:July 。致谢:pluskid、白石、JerryLead。说明:本文最初写于2012年6月,而后不断反反复复修改&优化,修改次数达上百次,最后修改于2016年1月。 前言 动笔写这个支持向量机(support vector machine)是费了不少劲和…

[机器学习] 支持向量机通俗导论节选(一)

本文转载自&#xff1a;http://blog.csdn.net/v_july_v/article/details/7624837 支持向量机通俗导论&#xff08;理解SVM的三层境界&#xff09; 作者&#xff1a; July、pluskid &#xff1b; 致谢&#xff1a;白石、J erryLead 出处&#xff1a;结构之法算法之道 blog …

机器学习之旅---SVM分类器

本次内容主要讲解什么是支持向量&#xff0c;SVM分类是如何推导的&#xff0c;最小序列SMO算法部分推导。 最后给出线性和非线性2分类问题的smo算法matlab实现代码。 一、什么是支持向量机(Support Vector Machine) 本节内容部分翻译Opencv教程&#xff1a; http://docs.open…

人工智能学习笔记 实验五 python 实现 SVM 分类器的设计与应用

学习来源 【机器学习】基于SVM人脸识别算法的一些对比探究&#xff08;先降维好还是先标准化好等对比分析&#xff09;_○( &#xff3e;皿&#xff3e;)っHiahiahia…的博客-CSDN博客 实验原理 有关svm原理 请移步该篇通俗易懂的博客 机器学习算法&#xff08;一&#xff0…