(48)Air Band OpenCV2.4.13_非线性离散数据的支持向量机

本文是对OpenCV2.4.13文档的部分翻译,作个人学习之用,并不完整。


计算机视觉中SVM的大多数应用都需要比一个简单的线性分类器更有用的工具。这就导致了这些任务不能简单地用一个超平面来分离。

例如面部检测,训练数据是由一组脸的图像和另一组非脸的图像组成的。这种训练数据太复杂以至于不能找到可以将整个脸部集合与非脸部集合线性分割的每个示例的表示方法(特征向量)。


优化问题的扩展:

使用SVM可以获得一个分离超平面。因此,既然训练数据是非线性离散的,我们必须承认找到的超平面会对某些示例分类错误。这种错误分类是优化中必须考虑的一个新变量。新的模型必须包括了旧的找到最大margin的超平面的需求和新的不允许过多分类错误来正确生成训练数据的需求。我们从找到margin最大的超平面的优化问题的公式开始:


有很多方法来修改这个模型来加入分类错误的考虑。例如可以最小化同样的数量并加上一个表示分类错误数量的常量:


但是这不是一个很好的办法,因为还有很多原因使得我们并不能区分示例是否因为距离分离域很小而错误分类。所以更好的方式是考虑错误分类示例到他们的正确分离域的距离:


对于每个训练数据的示例定义一个新的参数,每个参数都包含了从对应训练示例到他们正确分离域之间的距离。下面一幅图显示了两类非线性离散训练数据、一个分离超平面和分类错误的示例到他们正确区域的距离。



注意:只有分类错误的示例才显示在图像中,其余的示例因为已经在正确的分离域中故距离是0。红色和蓝色的线是到每个分离域的margin。每个伴随着一个从分类错误的训练示例到它的正确区域的margin。

参数C的选择取决于训练数据的分布情况,尽管没有确切的答案,可以考虑这些规则:

  • C值很大可以处理更少的分类错误和更小的margin。这对于分类错误有很大的花费,因为优化的目标就是将参数最小化,只允许很少的分类错误。
  • C值很小可以处理更大的margin和更多的分类错误。最小化并不太考虑总数,所以更专注于找到有大margin的超平面。

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

#define	NTRAINING_SAMPLES	100			// 每类训练示例的数量
#define FRAC_LINEAR_SEP		0.9f	    // 组成线性离散部分示例的比例

using namespace cv;
using namespace std;

static void help()
{
    cout<< "\n--------------------------------------------------------------------------" << endl
        << "This program shows Support Vector Machines for Non-Linearly Separable Data. " << endl
        << "Usage:"                                                               << endl
        << "./non_linear_svms" << endl
        << "--------------------------------------------------------------------------"   << endl
        << endl;
}

int main()
{
    help();

    // 可视化显示的数据
    const int WIDTH = 512, HEIGHT = 512;
    Mat I = Mat::zeros(HEIGHT, WIDTH, CV_8UC3);

    //--------------------- 1. 随机建立训练数据 ---------------------------------------
	// 训练数据由一组属于两个类别的标记了的二维点组成,由一个正态概率密度分布函数生成。首先生成每类中线性离散的数据
    Mat trainData(2*NTRAINING_SAMPLES, 2, CV_32FC1);
    Mat labels   (2*NTRAINING_SAMPLES, 1, CV_32FC1);

    RNG rng(100); // 随机值生成类

    // 建立训练数据中的线性离散部分
    int nLinearSamples = (int) (FRAC_LINEAR_SEP * NTRAINING_SAMPLES);

    // 生成类1的随机点
    Mat trainClass = trainData.rowRange(0, nLinearSamples);
    // 在[0,0.4)的点的x坐标
    Mat c = trainClass.colRange(0, 1);
    rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(0.4 * WIDTH));
    // 在[0,1)的店的y坐标
    c = trainClass.colRange(1,2);
    rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(HEIGHT));

    // 生成类2的随即点
    trainClass = trainData.rowRange(2*NTRAINING_SAMPLES-nLinearSamples, 2*NTRAINING_SAMPLES);
    // 在[0.6,1)的点的x坐标
    c = trainClass.colRange(0 , 1);
    rng.fill(c, RNG::UNIFORM, Scalar(0.6*WIDTH), Scalar(WIDTH));
    // 在[0,1)的点的y坐标
    c = trainClass.colRange(1,2);
    rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(HEIGHT));

    //------------------ 建立训练数据中的非线性离散部分 ---------------

    // 生成类1和类2的随机点,相互覆盖
    trainClass = trainData.rowRange(  nLinearSamples, 2*NTRAINING_SAMPLES-nLinearSamples);
    // 在[0.4,0.6)的点的x坐标
    c = trainClass.colRange(0,1);
    rng.fill(c, RNG::UNIFORM, Scalar(0.4*WIDTH), Scalar(0.6*WIDTH));
    // 在[0,1)的点的y坐标
    c = trainClass.colRange(1,2);
    rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(HEIGHT));

    //------------------------- 为各类建立标记 ---------------------------------
    labels.rowRange(                0,   NTRAINING_SAMPLES).setTo(1);  // 类1
    labels.rowRange(NTRAINING_SAMPLES, 2*NTRAINING_SAMPLES).setTo(2);  // 类2

    //------------------------ 2. 建立支持向量机的参数 --------------------
    CvSVMParams params;
    params.svm_type    = SVM::C_SVC;
    params.C 		   = 0.1;//选择一个小的值以便不对分类错误过度惩罚,在这里只有很少的点处于各类相互覆盖的区域中,给定FRAC_LINEAR_SEP一个更小的值,点的密度就会增大并且参数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);//调用train来构建SVM模型,训练过程可能会花很长时间。
    cout << "Finished training process" << endl;

    //------------------------ 4. 显示分离域 ----------------------------------------
	//predict用于将输入的示例用训练过的SVM分类。这里用来将基于SVM预计的区域填色。
	//换句话说就是将图像像素理解为Cartesian平面中的点来穿透图像。深绿色的点表示标记为1的类,深蓝色的点表示标记为2的类
    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);

            if      (response == 1)    I.at<Vec3b>(j, i)  = green;
            else if (response == 2)    I.at<Vec3b>(j, i)  = blue;
        }

    //----------------------- 5. 显示训练数据 --------------------------------------------
	//circle函数用于显示组成训练数据的示例,浅绿色的点表示标记为1的示例,浅蓝色的点表示标记为2的示例
    int thick = -1;
    int lineType = 8;
    float px, py;
    // 类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);
    }
    // 类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. 显示支持向量 --------------------------------------------
	// 这里使用了一对方法来获取支持向量的信息
	// get_support_vector_count输出在问题中使用的支持向量的总数
	// get_support_vector用下标获取每一个支持向量
	// 这里使用这些方法来找到是支持向量的训练示例并将他们高亮显示
    thick = 2;
    lineType  = 8;
    int x     = 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);	                   // 保存图像
    imshow("SVM for Non-Linear Training Data", I); // 显示给用户
    waitKey(0);
}
结果:



代码打开一个图像并显示了对两个类的训练示例。一个类中点表示为浅绿色,另一个类中的点表示为浅蓝色。两个区域的编辑就是分离超平面。因为训练数据是非线性离散的,可以看到两个类中有一些示例被错误分类。最终支持向量用灰色的圆圈显示出来(有点问题)。



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: OpenCV是一个开放源代码的图像处理库,也支持机器学习和模式识别等领域的算法。其中包括支持向量机(Support Vector Machine, SVM)算法,可以用于非线性回归任务。 支持向量机是一种常见的机器学习算法,可以用于分类和回归问题。在回归任务中,支持向量机可以用于建立非线性回归模型。 OpenCV中的支持向量机非线性回归主要基于核函数方法。核函数可以将非线性问题转化为高维空间中的线性问题,这样就可以使用线性回归模型进行建模。OpenCV提供了多种核函数供选择,如线性核函数、多项式核函数和径向基函数(Radial Basis Function, RBF)核函数等。 使用OpenCV进行支持向量机非线性回归的步骤大致如下: 1. 收集回归数据集,并根据需求进行预处理,如数据归一化。 2. 创建一个支持向量机模型对象,通过设置相关参数,如核函数类型、惩罚因子等,来进行模型配置。 3. 使用训练数据集训练支持向量机模型。 4. 使用训练好的模型进行预测,得到回归结果。 5. 根据需要,可以对模型进行进一步优化、调参等。 通过OpenCV支持向量机非线性回归功能,我们可以在处理非线性回归问题时,利用支持向量机算法建立准确性较高的模型。这样可以对各种复杂的非线性数据进行准确的回归预测,并能适应不同的核函数和其它参数配置的需求。 ### 回答2: OpenCV库是一种广泛使用的开源计算机视觉和机器学习库,其中包括了支持向量机(SVM)算法,可以用于非线性回归。 支持向量机是一种监督学习模型,用于分类和回归问题。在线性回归问题中,我们试图找到最佳的直线或平面来拟合数据。然而,在某些情况下,数据可能无法线性分割,这就需要使用非线性回归算法,如支持向量机OpenCV中的支持向量机实现的一个关键概念是核函数。核函数可以将数据从输入空间(原始特征空间)映射到一个更高维的特征空间,这样可以使数据在更高维度的空间中变得线性可分。OpenCV提供了多个核函数选项,如径向基函数(RBF)核、多项式核等,这些核函数可以根据问题的要求进行选择。 在使用OpenCV进行非线性回归时,我们首先需要准备训练数据和测试数据。然后,我们可以选择适当的核函数,并通过调整一些参数(如核函数的参数、惩罚因子等)来训练支持向量机模型。训练完成后,我们可以使用模型来预测新的数据样本。 总之,OpenCV库提供了支持向量机算法的实现,以解决非线性回归问题。通过选择适当的核函数和调整参数,可以构建一个准确的非线性回归模型,从而在计算机视觉和机器学习任务中提供更好的性能和结果。 ### 回答3: OpenCV是一个广泛应用于计算机视觉和图像处理领域的开源库。它不仅支持常见的图像处理功能,还包括机器学习算法。其中,OpenCV也提供了对支持向量机(Support Vector Machine,SVM)的支持,包括非线性回归。 支持向量机是一种常用的机器学习算法,旨在通过寻找最优的超平面,将数据点划分成不同的类别。在线性回归中,SVM可以用于从给定的数据集中预测一个连续性的输出变量。然而,有时候数据集并不是线性可分的,这时就需要通过非线性回归来解决这个问题。 在OpenCV中,支持向量机非线性回归通过使用内核函数来实现。内核函数的作用是将训练数据从原始特征空间映射到更高维的特征空间,使得数据在新的空间中能够线性可分。常见的内核函数包括多项式函数、径向基函数和Sigmoid函数等。 使用OpenCV进行支持向量机非线性回归的步骤主要有以下几个: 1. 准备训练数据集,包括输入变量X和输出变量y。 2. 创建一个SVM对象,并设置相关参数,如内核函数和惩罚参数等。 3. 调用SVM对象的训练方法,输入训练数据集,训练出一个SVM模型。 4. 对新的输入数据进行预测,可以使用SVM对象的predict方法,得到相应的输出结果。 总之,OpenCV支持向量机非线性回归提供了一种有效的工具来处理非线性可分的数据集。通过选择合适的内核函数和参数设置,可以在计算机视觉和图像处理等领域中应用SVM算法,实现准确的预测和分类任务。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值