代码

过程:

  • 创建SVM,之后设置参数
  • 训练分类器:创建训练数据矩阵和响应数据矩阵
  • 预测:用图形化显示决策区域和显示训练数据
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace cv::ml;

int main()
{
    // 创建分类器并设置参数
    Ptr<SVM> model =SVM::create();
    model->setType(SVM::C_SVC);  
    model->setKernel(SVM::LINEAR);  //核函数

    //设置训练数据矩阵
	float trainingData[10][2] = { { 501, 150 }, { 255, 10 }, 
		{ 501, 255 }, { 10, 501 }, { 25, 80 },{ 150, 300 }, 
		{ 77, 200 } , { 300,300 },{ 45, 250 } , { 200, 200 } };
	Mat trainingDataMat(10, 2, CV_32FC1, trainingData);
	
	//设置响应数据矩阵
	int labels[10] = { 1, -1, 1, 1,-1,1,-1,1,-1,-1 };
	Mat labelsMat(10, 1, CV_32SC1, labels);
	
	//创建TrainData实例
	Ptr<TrainData> tData=TrainData::create(trainingDataMat, ROW_SAMPLE, labelsMat);
	//每个训练数据是训练数据矩阵的行,所以是ROW_SAMPLE

    // 训练分类器
    model->trainAuto(tData);


	//创建窗口可视化
    Mat image = Mat::zeros(512, 512, CV_8UC3);


    /*显示决策区域*/
    Vec3b red(0, 0, 255), 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); 
   	        //进行预测,返回1或-1,和响应数据的值对应
	        float response = model->predict(sampleMat);  
	
	        if (response == 1)
	            image.at<Vec3b>(i, j) = red;
	        else if (response == -1)
	            image.at<Vec3b>(i, j) = blue;
	    }
    }

	/*显示训练数据*/
    Scalar c1 = Scalar::all(0); //标记为1的显示成黑点
    Scalar c2 = Scalar::all(255); //标记成-1的显示成白点

    //绘图时,先宽后高,对应先列后行
    for (int i = 0; i < trainingDataMat.rows; i++)
    {
        const float* v = trainingDataMat.ptr<float>(i); //取出每行的头指针
        Point pt = Point((int)v[0], (int)v[1]);
        if (labels[i] == 1)
            circle(image, pt, 5, c1, -1, 8); 
        else
            circle(image, pt, 5, c2, -1, 8);
        
    }

    imshow("SVM Simple Example", image); 
    waitKey(0);
	return 0;
}

显示训练数据要放在显示决策区域之后,不是因为SVM的过程问题,而是显示图像的问题。因为显示决策区域是对整个图像操作,所以如果显示训练数据在之前就会被覆盖。

在这里插入图片描述

一、SVM创建

//创建一个分类器
Ptr<SVM> svm = SVM::create();

//设置svm类型
svm->setType(SVM::C_SVC);

//设置核函数
svm->setKernel(SVM::POLY);

svm->setDegree(0.5);

svm->setGamma(1);

//核函数中的coef0设置(针对多项式/sigmoid核函数)((默认0)
svm->setCoef0(1);

svm->setC(C);

svm->setNu(0.5);

svm->setP(0);

svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS, 1000, 0.01));

1.setType()

设置svm类型:

  • SVM::C_SVC
    C类支撑向量分类机。
    n类分组 (n≥2),容许用异常值处罚因子C进行不完全分类。

  • SVM::NU_SVC
    ν \nu ν类支撑向量分类机。
    m类似然不完全分类的分类器。 ν \nu ν参数为庖代C(其值在区间[0,1]中, ν \nu ν越大,决定计划鸿沟越腻滑)。

  • SVM::ONE_CLASS
    单分类器,所有的练习数据提取自同一个类里,然后SVM建树了一个分界线以分别该类在特点空间中所占区域和其它类在特点空间中所占区域。

  • SVM::EPS_SVR
    ϵ \epsilon ϵ类支撑向量回归机。练习集中的特点向量和拟合出来的超平面的间隔须要小于p。异常值处罚因子C被采取。

  • SVM::NU_SVR
    ν \nu ν类支撑向量回归机。 ν \nu ν庖代了 p。

2.setKernel()

设置内核:

  • SVM::LINEAR :
    线性内核,没有任何向映射至高维空间,线性区分(或回归)在原始特点空间中被完成,这是最快的选择。

  • SVM::POLY :
    多项式内核:

  • SVM::RBF :
    基于径向的函数,对于大多半景象都是一个较好的选择

  • SVM::SIGMOID :
    Sigmoid函数内核:

3.设置核参数

  • setDegree()
    内核函数(POLY)的参数degree。

  • setGamma()
    内核函数(POLY/ RBF/ SIGMOID)的参数 γ \gamma γ

  • setCoef0()
    内核函数(POLY/ SIGMOID)的参数coef0

  • setC()
    SVM类型(C_SVC/ EPS_SVR/ NU_SVR)的参数C

  • setNu()
    SVM类型(NU_SVC/ ONE_CLASS/ NU_SVR)的参数 ν \nu ν

  • setP()
    SVM类型(EPS_SVR)的参数 ϵ \epsilon ϵ

4.setTermCriteria()

SVM的迭代练习过程的中断前提,解决项目组受束缚二次最优题目。您可以指定的公差和/或最大迭代次数。

二、SVM训练

步骤:

  • 先创建TrainData实例
  • 再将TrainData传入train()函数

1.Ptr< TrainData>类型

static Ptr<TrainData> cv::ml::TrainData::create	(
	InputArray 	samples,
	int 		layout,
	InputArray 	responses,
	InputArray 	varIdx = noArray(),
	InputArray 	sampleIdx = noArray(),
	InputArray 	sampleWeights = noArray(),
	InputArray 	varType = noArray() 
)	

参数:

  • samples
    训练数据。
    必须是CV_32F
  • layout
    就是SampleTypes:
    • ROW_SAMPLE
      每个训练样本是训练数据矩阵的行

    • COL_SAMPLE
      每个训练样本是训练数据矩阵的列

  • responses
    响应数据。
    如果响应是标量,则应将它们存储为单行或单列。(在前一种情况下,响应在默认情况下被视为有序;在后一种情况下无条件)
    矩阵应该具有类型CV_32F或CV_32S

如:

//设置训练数据
float trainingData[10][2] = { { 501, 150 }, { 255, 10 }, 
	{ 501, 255 }, { 10, 501 }, { 25, 80 },{ 150, 300 }, 
	{ 77, 200 } , { 300,300 },{ 45, 250 } , { 200, 200 } };
Mat trainingDataMat(10, 2, CV_32FC1, trainingData);

//设置响应数据
int labels[10] = { 1, -1, 1, 1,-1,1,-1,1,-1,-1 };
Mat labelsMat(10, 1, CV_32SC1, labels);

//创建TrainData实例
Ptr<TrainData> tData=TrainData::create(trainingDataMat, ROW_SAMPLE, labelsMat);
//每个训练数据是训练数据矩阵的行,所以是ROW_SAMPLE

2.训练函数trainAuto()

参数是Ptr<TrainData>

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 
)	
  • data:
    Ptr<TrainData>实例

  • kFold
    交叉验证参数。训练集分为kFold子集。一个子集用于测试模型,其他子集用于训练集。因此,SVM算法执行kFold次。

  • balanced
    如果为真且问题是2类分类,则该方法创建更平衡的交叉验证子集,即子集中类之间的比例接近于整个训练数据集中的该比例。

如:

model->trainAuto(tData);

参数是Ptr<TrainData>的拆分形式

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 
)	

如:

model->train(trainingDataMat,ROW_SAMPLE,labelsMat);

三、SVM预测

使用StatModel下的predict()

virtual float cv::ml::StatModel::predict(
	InputArray 	samples,
	OutputArray results = noArray(),
	int 		flags = 0 
)const

参数:

  • samples
    猜测的输入样本。
    float浮点型矩阵,必须与训练样本同样大小。

  • results:
    可选的结果输出矩阵。
    响应的样本输出猜测的响应。
    这个函数用来猜测一个新样本的响应数据(response)。
    在分类题目中,这个函数返回类别编号;在回归题目中,返回函数值。

  • flags:
    可选标志,取决于模型。
    在这里插入图片描述

  • 返回值:
    float类型,返回1或-1(这就是你的响应数据的值)。

四、存储和载入SVM文件

1.存储

原型:

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

文件格式的后缀是.svm

比如:

string path="/home/doctor/code/svmfile.svm";
model->save(path);

在这里插入图片描述

#include <iostream>
#include <opencv2/opencv.hpp>
#include <string>
using namespace std;
using namespace cv;
using namespace cv::ml;

int main()
{
    // 创建分类器并设置参数
    Ptr<SVM> model =SVM::create();
    model->setType(SVM::C_SVC);  
    model->setKernel(SVM::LINEAR);  //核函数

    //设置训练数据矩阵
	float trainingData[10][2] = { { 501, 150 }, { 255, 10 }, 
		{ 501, 255 }, { 10, 501 }, { 25, 80 },{ 150, 300 }, 
		{ 77, 200 } , { 300,300 },{ 45, 250 } , { 200, 200 } };
	Mat trainingDataMat(10, 2, CV_32FC1, trainingData);
	
	//设置响应数据矩阵
	int labels[10] = { 1, -1, 1, 1,-1,1,-1,1,-1,-1 };
	Mat labelsMat(10, 1, CV_32SC1, labels);
	
	//创建TrainData实例
	Ptr<TrainData> tData=TrainData::create(trainingDataMat, ROW_SAMPLE, labelsMat);
	//每个训练数据是训练数据矩阵的行,所以是ROW_SAMPLE

    // 训练分类器
    model->trainAuto(tData);


	//创建窗口可视化
    Mat image = Mat::zeros(512, 512, CV_8UC3);


    /*显示决策区域*/
    Vec3b red(0, 0, 255), 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); 
   	        //进行预测,返回1或-1,和响应数据的值对应
	        float response = model->predict(sampleMat);  
	
	        if (response == 1)
	            image.at<Vec3b>(i, j) = red;
	        else if (response == -1)
	            image.at<Vec3b>(i, j) = blue;
	    }
    }

	/*显示训练数据*/
    Scalar c1 = Scalar::all(0); //标记为1的显示成黑点
    Scalar c2 = Scalar::all(255); //标记成-1的显示成白点

    //绘图时,先宽后高,对应先列后行
    for (int i = 0; i < trainingDataMat.rows; i++)
    {
        const float* v = trainingDataMat.ptr<float>(i); //取出每行的头指针
        Point pt = Point((int)v[0], (int)v[1]);
        if (labels[i] == 1)
            circle(image, pt, 5, c1, -1, 8); 
        else
            circle(image, pt, 5, c2, -1, 8);
        
    }

	string path="/home/doctor/code/svmfile.svm";
	model->save(path);


    imshow("SVM Simple Example", image); 
    waitKey(0);
	return 0;
}

2.载入

原型:

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

比如:

string path="/home/doctor/code/svmfile.svm";
Ptr<SVM> model=SVM::load(path);

3.获得向量

(1)支持向量

原型:

virtual Mat cv::ml::SVM::getSupportVectors() const

该方法将所有支持向量作为浮点矩阵返回,其中支持向量存储为矩阵行。

Mat trainingDataMat=model->getSupportVectors();

在这里插入图片描述

(2)未压缩支持向量

Mat cv :: ml :: SVM :: getUncompressedSupportVectors()const

检索线性SVM的所有未压缩支持向量。

该方法返回线性SVM的所有未压缩支持向量,其中用于预测的压缩支持向量来自。
它们以浮点矩阵返回,其中支持向量存储为矩阵行。

在这里插入图片描述

#include <iostream>
#include <opencv2/opencv.hpp>
#include <string>
using namespace std;
using namespace cv;
using namespace cv::ml;

int main()
{
	string path="/home/doctor/code/svmfile.svm";
	Ptr<SVM> model=SVM::load(path);

	Mat trainingDataMat=model->getUncompressedSupportVectors();
	cout<<trainingDataMat.rows<<' ' <<trainingDataMat.cols<<endl;
	
	//设置响应数据矩阵
	int labels[10] = { 1, -1, 1, 1,-1,1,-1,1,-1,-1 };


	//创建窗口可视化
    Mat image = Mat::zeros(512, 512, CV_8UC3);


    /*显示决策区域*/
    Vec3b red(0, 0, 255), 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); 
   	        //进行预测,返回1或-1,和响应数据的值对应
	        float response = model->predict(sampleMat);  
	
	        if (response == 1)
	            image.at<Vec3b>(i, j) = red;
	        else if (response == -1)
	            image.at<Vec3b>(i, j) = blue;
	    }
    }

	/*显示训练数据*/
    Scalar c1 = Scalar::all(0); //标记为1的显示成黑点
    Scalar c2 = Scalar::all(255); //标记成-1的显示成白点

    //绘图时,先宽后高,对应先列后行
    for (int i = 0; i < trainingDataMat.rows; i++)
    {
        const float* v = trainingDataMat.ptr<float>(i); //取出每行的头指针
        Point pt = Point((int)v[0], (int)v[1]);
        if (labels[i] == 1)
            circle(image, pt, 5, c1, -1, 8); 
        else
            circle(image, pt, 5, c2, -1, 8);
        
    }

    imshow("SVM Simple Example", image); 
    waitKey(0);
	return 0;
}

在这里插入图片描述


参考:

OPENCV中SVM参数解析–学习1
在opencv3中实现机器学习之:利用svm(支持向量机)分类

官方文档:
cv::ml::SVM Class Reference
https://docs.opencv.org/3.4.6/d5/d33/structcv_1_1HOGDescriptor.html

官方例子:
https://docs.opencv.org/3.4.6/d0/df8/samples_2cpp_2train_HOG_8cpp-example.html#a4

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐