OpenCV 之 支持向量机 (一)

统计学习方法是由 模型 + 策略 + 算法 构成的,构建一种统计学习方法 (例如,支持向量机),实际上就是具体去确定这三个要素。

1  支持向量机

支持向量机,简称 SVM (Support Vector Machine),是一种二分分类模型。

1) 基本模型 (model)

定义在特征空间上的,一种间隔 (margin) 最大的,线性分类器 (linear classifier)

2) 学习策略 (strategy)

使间隔最大化,可转化为求解凸二次规划的问题。

3) 学习算法 (algorithm)

求解凸二次规划的最优化算法。

供训练的样本数据可分为三类:第一类是线性可分的,第二类是近似线性可分的,第三类是线性不可分的。

三种样本数据对应的 SVM 分别为:线性可分 (硬间隔最大化),线性 (软间隔最大化),非线性 (核技巧 + 软间隔最大化)。

本篇主要介绍的是,线性可分支持向量机。为了方便起见,下面提到的向量机 或 SVM,都是指线性可分支持向量机。

2  基本概念

2.1  超平面 (hyperplane)

n 维欧式空间中,余维度等于 1 (也即 n-1 维) 的线性子空间,称为超平面。

超平面在二维空间中是直线,在三维空间中是平面,可用来分隔数据。如下图所示,超平面 (直线) 能将两类不同的数据 (圆点和方点) 分隔开来。

如果将数据点记为 x (n 维向量),则超平面的方程为 $\ f(x) = \beta_{0} + \beta^{T} x = 0\; $,其中,$\beta $ 为权重向量 (有的书称为 “法向量”)

             

解释:右图中 $\beta^{*}$ 为超平面 (绿色直线) 的单位法向量 $\ \beta^{*} = \dfrac{\beta}{||\beta||}$,平面中任意点 x 到超平面的距离为 $\ r = \dfrac{|\beta_{0} + \beta^{T} x|} {||\beta||}$

又附: 平面坐标中,一个点 $\;(x_{0}, y_{0})\;$到直线$\;(Ax + By + C = 0)\;$ 的距离为 $\; d = \dfrac{Ax_{0} + By_{0} + C}{\sqrt{A^{2} + B^{2}}} $

2.2  支持向量 (support vector)

如果取输出 y 分别为 +1 和 -1,代表两种不同类别,则对于 x,其对应的 f(x) 有三种可能取值:

1) 当位于超平面上时 (也即图中的直线上),$ f(x) = \beta_{0} + \beta^{T} x = 0 $

2) 当位于超平面左边时, $f(x) = \beta_{0} + \beta^{T} x \leq -1$

3) 当位于超平面右边时, $f(x) = \beta_{0} + \beta^{T} x \geq +1$

假设存在一个超平面,能将 n 个样本数据正确的分类,则对于任意一个样本数据$\;(x_{i}, y_{i})$,满足如下约束条件

$\quad y_{i}(\beta^{T} x_{i} + \beta_{0}) \geq 1 , i = 1, 2, ..., n $

如上图所示,距离超平面最近的三个样本点,使得 2) 和 3) 中的等号成立,它们称为 “支持向量”。

2.3  几何间隔 (geometric margin)

因为支持向量使得 2) 和 3) 的等号成立,所以它们到超平面的距离:

$\quad r = \dfrac{|\beta_{0} + \beta^{T} x|} {||\beta||} = \dfrac{1}{||\beta||}$

两个不同种类的支持向量 (分别取值为 +1 和 -1),到超平面的距离之和为:

$\quad r^{‘} = \dfrac{2}{||\beta||}\;$,$r^{‘}\;$称为 “几何间隔” (geometric margin)

一个点距离超平面的远近,可用来表示分类结果的正确性和确信度。

直观上看,超平面越是靠近两类样本数据的正中间 (也即两类数据点到超平面的距离越远),则分类结果的正确性和确信度就越高。

2.4  学习算法

SVM 的学习算法 (或称最大间隔法),就是基于所给的样本数据,去寻找到具有 “最大间隔” 的超平面,将不同种类的样本分隔开来。

也即,在满足 “约束条件” 的前提下,使得 $r^{‘}$ 的值最大:

$\quad \max \limits_{\beta,\; \beta_{0}} \dfrac{2}{||\beta||} \quad subject\;to \quad y_{i}(\beta^{T} x_{i} + \beta_{0}) \geq 1 , i = 1, 2, ..., n $

再或者,最大化 $r^{‘}$,等价于最小化 $||\beta||^{2}$,如下所示:

$\quad \min \limits_{\beta,\;\beta_{0}} \dfrac{1}{2} ||\beta||^{2} \quad subject \; to \quad y_{i} (\beta^{T} x_{i} + \beta_{0}) \geq 1 , i = 1, 2, ..., n $

3  OpenCV 函数

OpenCV 中 SVM 的实现是基于 libsvm 的,其基本的过程为:创建 SVM 模型 --> 设置相关参数 --> 样本数据训练 --> 预测

1) 创建模型

static Ptr<SVM> cv::ml::SVM::create ( );  // 创建一个空模型

2) 设置参数

virtual void cv::ml::SVM::setType (int val);  // 设置 SVM 的类型,默认为 SVM::C_SVC
virtual void cv::ml::SVM::setKernel (int kernelType); // 设置核函数类型,本文为线性核函数,设为 SVM::LINEAR

virtual void cv::ml::SVM::setTermCriteria (const cv::TermCriteria & val); // 设置迭代终止准则

cv::TermCriteria::TermCriteria (  int type,      // 准则类型  int maxCount,   // 最大迭代次数  double epsilon  // 目标精度);       

3) 训练 (train)

virtual bool cv::ml::StatModel::train (
   InputArray  samples,   // 训练样本
    int        layout,   // 训练样本为 “行样本” ROW_SAMPLE 或 “列样本” COL_SAMPLE
    InputArray    responses // 对应样本数据的分类结果
)     

4) 预测 (predict)

predict 函数可用来预测一个新样本的响应,其各个参数如下:

virtual float cv::ml::StatModel::predict (   InputArray  samples,        // 输入的样本数据,浮点型矩阵  OutputArray  results = noArray(), // 输出矩阵,默认不输出  int flags = 0             // 标示,默认为 0)  const

4  代码示例

下面是 OpenCV 3.0 中的官方例程,稍作修改,更改了训练样本数据,删除了获取支持向量的函数。

#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/ml.hpp>

using namespace cv;
using namespace cv::ml;

int main()
{
    // 512 x 512 零矩阵
    int width = 512, height = 512;
    Mat image = Mat::zeros(height, width, CV_8UC3);

    // 训练样本
    float trainingData[6][2] = { { 500, 60 },{ 245, 40 },{ 480, 250 },{ 160, 380 },{400, 25},{55, 400} };
    int labels[6] = {-1, 1, 1, 1,-1,1};  // 每个样本数据对应的输出,因为是二分模型,所以输出为 +1 或者 -1
    Mat trainingDataMat(6, 2, CV_32FC1, trainingData);
    Mat labelsMat(6, 1, CV_32SC1, labels);

    // 训练 SVM
    Ptr<SVM> svm = SVM::create();
    svm->setType(SVM::C_SVC);
    svm->setKernel(SVM::LINEAR);
    svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 100, 1e-6));
    svm->train(trainingDataMat, ROW_SAMPLE, labelsMat);

    // 显示二分类的结果
    Vec3b green(0, 255, 0), blue(255, 0, 0);
    for (int i = 0; i < image.rows; ++i)
        for (int j = 0; j < image.cols; ++j)
        {
            Mat sampleMat = (Mat_<float>(1, 2) << j, i);
            float response = svm->predict(sampleMat);
            if (response == 1)
                image.at<Vec3b>(i, j) = blue;
            else if (response == -1)
                image.at<Vec3b>(i, j) = green;
        }
    // 画出训练样本数据
    int thickness = -1;
    int lineType = 8;
    circle(image, Point(500, 60), 5, Scalar(0, 0, 0), thickness, lineType);
    circle(image, Point(245, 40), 5, Scalar(255, 255, 255), thickness, lineType);
    circle(image, Point(480, 250), 5, Scalar(255, 255, 255), thickness, lineType);
    circle(image, Point(160, 380), 5, Scalar(0, 0, 255), thickness, lineType);
    circle(image, Point(400, 25), 5, Scalar(255, 255, 255), thickness, lineType);
    circle(image, Point(55, 400), 5, Scalar(0, 0, 255), thickness, lineType);

    imwrite("result.png", image);        // 保存训练的结果
    imshow("SVM Simple Example", image);
    waitKey(0);
}

OpenCV 3.0 中,获取支持向量的函数为 getSupportVectors(),实际上,当内核函数设为 SVM::LINEAR 时,该函数并不能得到支持向量,这是 3.0 版本的缺陷。

对此,3.1 版本中使用了一个新的函数,来获取支持向量,即 getUncompressedSupportVectors()

int  thickness = 2;
int  lineType  = 8;
Mat sv = svm->getUncompressedSupportVectors();
for (int i = 0; i < sv.rows; ++i)
{
    const float* v = sv.ptr<float>(i);
    circle( image,  Point( (int) v[0], (int) v[1]),   6,  Scalar(128, 128, 128), thickness, lineType);
}

实际的运行结果如下图所示,根据经验,超平面附近的三个白色圆点,便是所谓的 “支持向量”。

参考资料:

<机器学习> 周志军  第6章

<统计学习方法> 李航  第7章

<The Elements of Statistical Learning_2nd>  ch 4.5 , ch 12

"支持向量机系列“  pluskid

OpenCV 3.0.0 tutorials

“LIBSVM -- A Library for Support Vector Machines”

时间: 2024-08-07 16:41:57

OpenCV 之 支持向量机 (一)的相关文章

OpenCV支持向量机(SVM)介绍

支持向量机(SVM)介绍 目标 本文档尝试解答如下问题: 如何使用OpenCV函数 CvSVM::train 训练一个SVM分类器, 以及用 CvSVM::predict 测试训练结果. 什么是支持向量机(SVM)? 支持向量机 (SVM) 是一个类分类器,正式的定义是一个能够将不同类样本在样本空间分隔的超平面. 换句话说,给定一些标记(label)好的训练样本 (监督式学习), SVM算法输出一个最优化的分隔超平面. 如何来界定一个超平面是不是最优的呢? 考虑如下问题: 假设给定一些分属于两类

OpenCV 机器学习之 支持向量机的使用方法实例

用支持向量机进行文理科生的分类,根据的特征主要是 数学成绩与语文成绩,这两个特征都服从高斯分布 程序代码例如以下: 分类结果: OpenCV 机器学习之 支持向量机的使用方法实例

opencv 支持向量机SVM分类器

支持向量机SVM是从线性可分情况下的最优分类面提出的.所谓最优分类,就是要求分类线不但能够将两类无错误的分开,而且两类之间的分类间隔最大,前者是保证经验风险最小(为0),而通过后面的讨论我们看到,使分类间隔最大实际上就是使得推广性中的置信范围最小.推广到高维空间,最优分类线就成为最优分类面. 支持向量机是利用分类间隔的思想进行训练的,它依赖于对数据的预处理,即,在更高维的空间表达原始模式.通过适当的到一个足够高维的非线性映射,分别属于两类的原始数据就能够被一个超平面来分隔.如下图所示: 空心点和

《Master Opencv...读书笔记》非刚性人脸跟踪 III

上篇文章中,我们获得了人脸的各种表情模式,也就是一堆标注点的形变参数.这次我们需要训练一中人脸特征(团块模型),它能够对人脸的不同部位(即"标注点")分别进行描述,作为后面人脸跟踪.表情识别的区分依据.本次博文的主要内容: a.      介绍下人脸特征检测器大概有哪些类别 b.      详细介绍随机梯度法,并介绍在人脸团块特征提取时的应用 c.      为了提高训练/跟踪的健壮性,利用上一讲对输入的图像进行大小.角度的约束 人脸特征检测器综述 人脸特征检测与普通的物体检测非常相似

OpenCV 2.4.8组件结构全解析

转自: http://blog.csdn.net/huang9012/article/details/21811271 之前啃了不少OpenCV的官方文档,发现如果了解了一些OpenCV整体的模块架构后,再重点学习自己感兴趣的部分的话,就会有一览众山小的感觉,于是,就决定写出这篇文章,作为启程OpenCV系列博文的第二篇. 至于OpenCV组件结构的研究方法,我们不妨管中窥豹,通过opencv安装路径下include目录里面头文件的分类存放,来一窥OpenCV这些年迅猛发展起来的庞杂组件架构.

opencv头文件

转载自:http://blog.csdn.net/aaron121211/article/details/51526901 1. .hpp文件是.h和.cpp文件在一起的2. #include <opencv2/opencv.hpp> 就包含了opencv库所有头文件,所以很多时候都是直接include 3.一些用到的库介绍 [highgui] --也就是high gui,高层GUI图形用户界面,包含媒体的I / O输入输出, 视频捕捉.图像和视频的编码解码.图形交互界面的接口等内容 [cal

实验报告: 人脸识别方法回顾与实验分析 【OpenCV测试方法源码】

趁着还未工作,先把过去做的东西整理下出来~   Github源码:https://github.com/Blz-Galaxy/OpenCV-Face-Recognition (涉及个人隐私,源码不包含测试样本,请谅解~) 对实验结果更感兴趣的朋友请直接看 第5章 [摘要]这是一篇关于人脸识别方法的实验报告.报告首先回顾了人脸识别研究的发展历程及基本分类:随后对人脸识别技术方法发展过程中一些经典的流行的方法进行了详细的阐述:最后作者通过设计实验对比了三种方法的识别效果并总结了人脸识别所面临的困难与

OpenCV学习-b

OpenCV是开源计算机视觉和机器学习库.包含成千上万优化过的算法.项目地址:http://opencv.org/about.html.官方文档:http://docs.opencv.org/modules/core/doc/intro.html.OpenCV已支持OpenCL OpenGL,也支持iOS和Android.OpenCV的API是C++的,所以在iOS中最佳实践是将用到OpenCV功能写一层Objective-C++封装.这些封装把OpenCV的C++API转化为安全的Object

【OpenCV入门教程之二】 一览众山小:OpenCV 2.4.8 or OpenCV 2.4.9组件结构全解析

之前啃了不少OpenCV的官方文档,发现如果了解了一些OpenCV整体的模块架构后,再重点学习自己感兴趣的部分的话,就会有一览众山小的感觉,于是,就决定写出这篇文章,作为启程OpenCV系列博文的第二篇. 至于OpenCV组件结构的研究方法,我们不妨管中窥豹,通过opencv安装路径下include目录里面头文件的分类存放,来一窥OpenCV这些年迅猛发展起来的庞杂组件架构. 我们进入到D:\ProgramFiles\opencv\build\include目录,可以看到有opencv和open