opencv机器学习ml模块简介

                              本文不涉原理,只介绍如何使用!

ml模块为opencv的机器学习(machine learning,ml)代码库,包含各种机器学习算法:

0, class CvStatModel ; class CvMLData; struct CvParamGrid;

1,Normal Bayes Classifier(贝叶斯分类);

2,K-Nearest Neighbour Classifier(K-邻近算法);

3,SVM,support vector machine(支持向量机);

4,Expectation - Maximization (EM算法);

5,Decision Tree(决策树);

6,Random Trees Classifier(随机森林算法);

7, Boosted tree classifier (Boost树算法);

9,Stochastic Gradient Descent SVM classifier;

10,ANN,Artificial Neural Networks(人工神经网络);

ml模块中有一个cv::ml::TrainData类,用于生成训练数据

create函数,从内存数组创建训练数据。:

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() 
)		

参数
sample:样本矩阵样本。它应该具有CV_32F类型,原始数据一般是uchar型,所以要进行类型转化
layout:有两种取值

  1. ROW_SAMPLE   一行为一个样本
  2. COL_SAMPLE 一列为一个样本

response:响应矩阵。如果响应是标量,则将它们存储为单行或单列。 矩阵应该具有类型CV_32F或CV_32S(在前一种情况下,响应在默认情况下被视为有序;在后一种情况下 - 作为分类)
varIdx:vector,指定用于训练的变量。 它可以是包含基于0的变量索引的整数向量(CV_32S)或包含活动变量掩码的字节向量(CV_8U)。
sampleIdx:向量,指定用于训练的样本。 它可以是包含基于0的样本索引的整数向量(CV_32S)或包含训练样本掩码的字节向量(CV_8U)。
sampleWeights:权重向量,每个样本都有权重。 它应该具有CV_32F类型。

1、KNN

      OpenCV 3.4.3中给出了K-最近邻(KNN)算法的实现,即cv::ml::Knearest类,此类的声明在include/opecv2/ml.hpp文件中,实现在modules/ml/src/knearest.cpp文件中。Knearest类:继承自cv::ml::StateModel,而StateModel又继承自cv::Algorithm。

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

create函数:为静态成员函数,new一个KNearestImpl,用来创建一个KNearest对象,如下:

cv::Ptr<cv::ml::KNearest> knn = cv::ml::KNearest::create();

setDefaultK/getDefaultK函数:在预测时,设置/获取的K值;

setIsClassifier/getIsClassifier函数:设置/获取应用KNN是进行分类还是回归;

setEmax/getEmax函数:在使用KDTree算法时,设置/获取Emax参数值;

setAlgorithmType/getAlgorithmType函数:设置/获取KNN算法类型,目前支持两种:brute_force和KDTree;

findNearest函数:根据输入预测分类/回归结果

virtual float cv::ml::KNearest::findNearest	(
InputArray 	samples,
int k,
OutputArray 	results,
OutputArray 	neighborResponses = noArray(),
OutputArray 	dist = noArray() 
)		const

参数说明:

  1. samples:为 样本数*特征数 的浮点二维矩阵;
  2. k:为寻找最近点的个数;
  3. results:预测结果;
  4. neighborResponse:为样本数*k的二维矩阵,代表每个样本的K个近邻的输出值;
  5. dist:为样本数*k的二维矩阵,代表每个样本的K个近邻的距离。

实例:opencv提供了一张手写数字图片给我们,

     图片大小为1000*2000,有0-9的10个数字,每5行为一个数字,总共50行,共有5000个手写数字。我们首先要做的,就是把这5000个手写数字,一个个截取出来,每个数字块大小为20*20。直接将每个小图块进行序列化,因此最终得到一个5000*400的特征矩阵。样本数为5000,维度为400维。取其中前3000个样本进行训练。

注意:截取的时候,是按列截取。不然取前3000个样本进行训练就会出现后几个数字训练不到。

#include "stdafx.h"
#include "opencv2\opencv.hpp"
#include <iostream>
using namespace std;
using namespace cv;
using namespace cv::ml;

int main()
{
    Mat img = imread("E:/opencv/opencv/sources/samples/data/digits.png");
    Mat gray;
    cvtColor(img, gray, CV_BGR2GRAY);
    int b = 20;
    int m = gray.rows / b;   //原图为1000*2000
    int n = gray.cols / b;   //裁剪为5000个20*20的小图块
    Mat data,labels;   //特征矩阵
    for (int i = 0; i < n; i++)
    {
        int offsetCol = i*b; //列上的偏移量
        for (int j = 0; j < m; j++)
        {
            int offsetRow = j*b;  //行上的偏移量
            //截取20*20的小块
            Mat tmp;
            gray(Range(offsetRow, offsetRow + b), Range(offsetCol, offsetCol + b)).copyTo(tmp);
            data.push_back(tmp.reshape(0,1));  //序列化后放入特征矩阵
            labels.push_back((int)j / 5);  //对应的标注
        }

    }
    data.convertTo(data, CV_32F); //uchar型转换为cv_32f
    int samplesNum = data.rows;
    int trainNum = 3000;
    Mat trainData, trainLabels;
    trainData = data(Range(0, trainNum), Range::all());   //前3000个样本为训练数据
    trainLabels = labels(Range(0, trainNum), Range::all());

    //使用KNN算法
    int K = 5;
    Ptr<TrainData> tData = TrainData::create(trainData, ROW_SAMPLE, trainLabels);//降训练数据封装成一个TrainData对象,送入train函数
    Ptr<KNearest> model = KNearest::create();
    model->setDefaultK(K);
    model->setIsClassifier(true);
    model->train(tData);

    //预测分类
    double train_hr = 0, test_hr = 0;
    Mat response;
    // compute prediction error on train and test data
    for (int i = 0; i < samplesNum; i++)
    {
        Mat sample = data.row(i);
        float r = model->predict(sample);   //对所有行进行预测
        //预测结果与原结果相比,相等为1,不等为0
        r = std::abs(r - labels.at<int>(i)) <= FLT_EPSILON ? 1.f : 0.f;          

        if (i < trainNum)
            train_hr += r;  //累积正确数
        else
            test_hr += r;
    }

    test_hr /= samplesNum - trainNum;
    train_hr = trainNum > 0 ? train_hr / trainNum : 1.;

    printf("accuracy: train = %.1f%%, test = %.1f%%\n",
        train_hr*100., test_hr*100.);
    waitKey(0);
    return 0;
}

代码来自:https://www.cnblogs.com/denny402/p/5033898.html

2、DTree

 create函数用来创建一个DTrees对象;

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

(1)、setMaxCategories/getMaxCategories函数:设置/获取最大的类别数,默认值为10;

(2)、setMaxDepth/getMaxDepth函数:设置/获取树的最大深度,默认值为INT_MAX;

(3)、setMinSampleCount/getMinSampleCount函数:设置/获取最小训练样本数,如果节点中的样本数小于此参数,则不会拆分该节点。默认值为10;

(4)、setCVFolds/getCVFolds函数:设置/获取CVFolds值,如果此值大于1,算法使用K-fold交叉验证程序修剪构建的决策树,其中K等于CVFolds。 默认值为10。

(5)、setTruncatePrunedTree/getTruncatedTree函数:设置/获取是否进行剪枝后移除操作,默认值为true;

(6)、setRegressionAccuracy/getRegressionAccuracy函数:设置/获取回归时用于终止的标准,默认值为0.01;

(7)、setPriors/getPriors函数:设置/获取先验概率数值,用于调整决策树的偏好,默认值为空的Mat;

(8)、getRoots函数:获取根节点索引;

(9)、getNodes函数:获取所有节点索引;

(10)、getSplits函数:获取所有拆分索引;

(11)、getSubsets函数:获取分类拆分的所有bitsets;

(12)、load函数:load已序列化的model文件。

static Ptr<DTrees> cv::ml::DTrees::load	(const String & filepath,const String & nodeName = String() )	

使用方法与KNN基本一致:

cv::Ptr<cv::ml::DTrees> dtree = cv::ml::DTrees::create();
	dtree->setMaxCategories(10);//设置分类数为10,0-9
	dtree->setMaxDepth(10);
	dtree->setMinSampleCount(10);
	dtree->setCVFolds(0);
	dtree->setUseSurrogates(false);
	dtree->setUse1SERule(false);
	dtree->setTruncatePrunedTree(false);
	dtree->setRegressionAccuracy(0);
	dtree->setPriors(cv::Mat()); 
	dtree->train(train_data, cv::ml::ROW_SAMPLE, train_labels);
//在这里我们没有使用Ptr<TrainData>创建训练对象,而是直接将“train_data, cv::ml::ROW_SAMPLE, train_labels”送入train函数,这两种方式都是可行的

const std::string save_file{ "E:/GitCode/NN_Test/data/decision_tree_model.xml" }; // .xml, .yaml, .jsons
	dtree->save(save_file);

3、逻辑回归

     逻辑回归(logistic regression)的实现,即cv::ml::LogisticRegression类,类的声明在include/opencv2/ml.hpp文件中,实现在modules/ml/src/lr.cpp文件中,它既支持两分类,也支持多分类,其中:

(2)、setLearningRate/getLearningRate函数用来设置获取学习率;

(3)、setIterations/getIterations函数用来设置/获取迭代次数;

(4)、setRegularization函数用来设置采用哪种正则化方法,目前支持两种L1 norm和L2 norm,正则化方法主要用来防止过拟合;

(5)、setTrainMethod函数用来设置采用哪种训练方法,目前支持两种Batch和Mini-Batch,使用Mini-Batch方法时,将MiniBatchSize设置一个正整数。

(6)、setMiniBatchSize函数用来设置在Mini-Batch梯度下降训练方法中每一个step采集的训练样本数,getMiniBatchSize函数用来获取每一个step采集的训练样本数;

(7)、setTermCriteria/getTermCriteria函数用来设置/获取终止训练的条件,包括迭代次数和期望的精度;

(8)、get_learnt_thetas函数用来获取训练参数;

(9)、train函数(使用基类StatModel中的)进行训练;

(10)、predict函数用于预测;

(11)、save函数(使用基类Algorithm中的)保存已训练好的model,支持xml,yaml,json格式;

(12)、load函数用来load已训练好的model;
 

cv::Ptr<cv::ml::LogisticRegression> lr = cv::ml::LogisticRegression::create();
	lr->setLearningRate(0.00001);
	lr->setIterations(100);
	lr->setRegularization(cv::ml::LogisticRegression::REG_DISABLE);
	lr->setTrainMethod(cv::ml::LogisticRegression::MINI_BATCH);
	lr->setMiniBatchSize(1);
 
	lr->train(data, cv::ml::ROW_SAMPLE, labels);
    const std::string save_file{ "E:/GitCode/NN_Test/data/logistic_regression_model.xml" }; // .xml, .yaml, .jsons
	lr->save(save_file);

cv::Ptr<cv::ml::LogisticRegression> lr = cv::ml::LogisticRegression::load(model_file);
     lr->predict(data, result);

转自:https://blog.csdn.net/fengbingchun/article/details/78221693

4、SVM

     支持向量机(Support Vector Machines)的实现,即cv::ml::SVM类,它既支持两分类,也支持多分类,还支持回归等,OpenCV中SVM的实现源自libsvm库。

(3)、setType/getType函数:设置/获取SVM公式类型,包括C_SVC、NU_SVC、ONE_CLASS、EPS_SVR、NU_SVR,用于指定分类、回归等,默认为C_SVC;

  1. C_SVC:C-支持向量分类。 n级分类(n≥2),允许类别的不完美分离与罚分乘数C的异常值。
  2. NU_SVC:ν-支持向量分类。 n级分类,可能存在不完美的分离。 使用参数ν(在0..1范围内,值越大,决策边界越平滑)代替C.
  3. ONE_CLASS:分布估计(一类SVM)。 所有训练数据都来自同一个类,SVM构建一个边界,将类与特征空间的其余部分分开。
  4. EPS_SVR:ε-支持向量回归。 来自训练集和拟合超平面的特征向量之间的距离必须小于p。 对于异常值,使用罚分乘数C.
  5. NU_SVR:ν-支持向量回归。 用ν代替p。 

(4)、setGamma/getGamma函数:设置/获取核函数的γ参数,默认值为1;

(5)、setCoef0/getCoef0函数:设置/获取核函数的coef0参数,默认值为0;

(6)、setDegree/getDegree函数:设置/获取多项式核函数的degreee参数(阶数),默认值为0;

(7)、setC/getC函数:设置/获取SVM优化问题的C参数,默认值为0;

(8)、setNu/getNu函数:设置/获取SVM优化问题的υ参数,默认值为0;

(9)、setP/getP函数:设置/获取SVM优化问题的ε参数,默认值为0;

(10)、setClassWeights/getClassWeights函数:应用在C_SVC,设置/获取weights,默认值是空cv::Mat;

(11)、setTermCriteria/getTermCriteria函数:设置/获取SVM训练时迭代终止条件,默认值是cv::TermCriteria(cv::TermCriteria::MAX_ITER + TermCriteria::EPS,1000, FLT_EPSILON);

(12)、setKernel/getKernelType函数:设置/获取SVM核函数类型,包括CUSTOM、LINEAR、POLY、RBF、SIGMOID、CHI2、INTER,默认值为RBF;

(13)、setCustomKernel函数:初始化CUSTOM核函数;

(14)、trainAuto函数:用最优参数训练SVM;会相当耗时。

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 
)	

(15)、getSupportVectors/getUncompressedSupportVectors函数:获取所有的支持向量;

(16)、getDecisionFunction函数:决策函数;

(17)、getDefaultGrid/getDefaultGridPtr函数:生成SVM参数网格;

static Ptr<ParamGrid> cv::ml::SVM::getDefaultGridPtr(int param_id)	

 param_id:  C ,   GAMMA ,   P ,   NU,    COEF ,   DEGREE 
(19)、train/predict函数:用于训练/预测,均使用基类StatModel中的。(18)、save/load函数:保存/载入已训练好的model,支持xml,yaml,json格式;

cv::Ptr<cv::ml::SVM> svm = cv::ml::SVM::create();
	svm->setType(cv::ml::SVM::C_SVC);
	svm->setKernel(cv::ml::SVM::LINEAR);
	svm->setTermCriteria(cv::TermCriteria(cv::TermCriteria::MAX_ITER, 100, 1e-6));
 
	CHECK(svm->train(trainingDataMat, cv::ml::ROW_SAMPLE, labelsMat));
 
	const std::string save_file{ "E:/GitCode/NN_Test/data/svm_model.xml" }; // .xml, .yaml, .jsons
	svm->save(save_file);

具体应用实例可参见:https://blog.csdn.net/qq_30815237/article/details/94546773 

5、SVMSGD 随机梯度下降SVM分类器。

参数w更新公式为:

                          

w_{t}:是步骤t 中决策函数的权重向量 w

γ(t) :是迭代t时,模型参数的步长,每次迭代步长减小公式: 

Qi :是总数为i个样本的SVM的目标函数,该样本在算法的每个步骤上随机选择。

ASGD是平均随机梯度下降SVM分类器。 ASGD分类器通过公式对算法的每个步骤的权重向量进行平均:

                

分类器具有以下参数:

setMarginType()/getMarginType():边界类型分为软边界和硬边界,SOFT_MARGIN,HARD_MARGIN

setSvmsgdType()/getSvmsgdType():SGD和ASGD

SGD 

Stochastic Gradient Descent.

ASGD 

Average Stochastic Gradient Descent.

边界正则化参数(λ):正则化参数负责每一步的权重减少以及对异常值的限制强度(参数越小,异常值不容易被忽略)。 SGD模型的推荐值为0.0001,ASGD模型的推荐值为0.00001。

初始步长(γ0):初始步长参数是步长γ(t)的初始值。

逐步降低功率(c):是γ(t)的功率参数,通过上述公式减小。 SGD模型的推荐值为1,ASGD模型的推荐值为0.75。

终止标准:终止标准可以是TermCriteria :: COUNT,TermCriteria :: EPS或TermCriteria :: COUNT + TermCriteria :: EPS。

// Create empty object
cv::Ptr<SVMSGD> svmsgd = SVMSGD::create();
// Train the Stochastic Gradient Descent SVM
svmsgd->train(trainData);
// Predict labels for the new samples
svmsgd->predict(samples, responses);

6、ANN_MLP

     人工神经网络——多层感知器。与许多其他模型毫升构造和训练,在模型这些步骤是分开的。首先,创建一个与指定的网络拓扑结构使用非默认的构造函数或方法ANN_MLP::创建。所有的权重都设置为0。然后,网络训练使用一组输入和输出向量。训练过程可以重复不止一次,也就是说,权重可以基于新的训练数据,进行调整。

1、setLayerSizes():整数向量,指定每层中神经元的数量,包括输入和输出层。 第一个元素指定输入图层中的元素数。 最后一个元素 - 输出图层中的元素数。 默认值为空Mat。

virtual void cv::ml::ANN_MLP::setLayerSizes(InputArray _layer_sizes)	

2、setActivationFunction():设置激活函数

virtual void cv::ml::ANN_MLP::setActivationFunction(int type,double param1 = 0,double param2 = 0 )	

type:

param1: activation function的第一个参数 α. Default value is 0.
param2: activation function的第二个参数β. Default value is 0.

3、setTrainMethod()函数

virtual void cv::ml::ANN_MLP::setTrainMethod(int method,double 	param1 = 0,double param2 = 0 )

method:backprop:反向传播;rprop:弹性反向传播;anneal :模拟退火算法;

//创建ANN
Ptr<ANN_MLP> bp = ANN_MLP::create();

设置层数时,要注意:例子的数量要和标签的数量相同。第一项为图片的像素数,最后一项为训练的种类数

//设置层数
 Mat layerSizes = (Mat_<int>(1, 4) << image_rows*image_cols, int(image_rows*image_cols / 2), int(image_rows*image_cols / 2), class_num);
 bp->setLayerSizes(layerSizes);
bp->setActivationFunction(ANN_MLP::SIGMOID_SYM, 1, 1);

//void setActivationFunction(int _activ_func, double _f_param1, double _f_param2 );

 bp->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 300, FLT_EPSILON));
 bp->setTrainMethod(ANN_MLP::BACKPROP, 0.001);
 Ptr<TrainData> tData = TrainData::create(DataMat, ROW_SAMPLE, labelsMat);
 bp->train(tData);
float response = ann->predict(testMat,outputMat);

//加载分类器时,使用以下任意一个即可 

Ptr<ANN_MLP> bp = StatModel::load<ANN_MLP>("*.xml");
Ptr<ANN_MLP> bp = ANN_MLP::load<ANN_MLP>("*.xml");
Ptr<ANN_MLP> bp = Algorithm::load<ANN_MLP>("*.xml");

 predict 函数原型:
virtual float predict( InputArray samples, OutputArray results=noArray(), int flags=0 );

最终的预测结果应该是第二个参数OutputArray results,不是那个 response

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值