首先,我们应该知道在OpenCV中已经有了很多的分类和回归算法。其中,在ml模块中我们可以使用OpenCV自带的神经网络算法CvANN_MLP。神经网络的具体实现我就不详细介绍了,在这里我们主要是介绍CvANN_MLP的定义及如何调用。
原文参考:http://blog.csdn.net/qq_15947787/article/category/6115133/2 、http://blog.csdn.net/xiaowei_cqu/article/details/9027617 和 http://www.cnblogs.com/farewell-farewell/p/6027888.html
ANN – Artificial Neural Networks 人工神经网络 MLP – Multi-layer perceptrons 多重感知器
其实,CvANN_MLP的最重要三个调用函数是 creat()、train() 和 predict();
在这里,我们可以很清楚地了解到OpenCV实现神经网络主要使用两种训练方法: BACKPROP 与 RPROP
layerSizes设置了有5层的网络结构:输入层,三个隐含层,输出层。输入层和输出层节点数均为5,中间隐含层每层有两个节点。
create第二个参数可以设置每个神经节点的激活函数,默认为CvANN_MLP::SIGMOID_SYM,即Sigmoid函数,同时提供的其他激活函数有Gauss和阶跃函数。
int CvANN_MLP::train(constMat& inputs, constMat& outputs,
constMat& sampleWeights, constMat& sampleIdx=Mat(),
CvANN_MLP_TrainParams params=CvANN_MLP_TrainParams(), intflags=0 );
1) inputs:输入矩阵。它存储了所有训练样本的特征。假设所有样本总数为nSamples,而我们提取的特征维数为ndims,
则inputs是一个nSamples∗ndims的矩阵,每个样本的特征占一行。
2) outputs:输出矩阵。我们实际在训练中,我们知道每个样本所属的种类,假设一共有nClass类。那么我们将outputs设置为
一个nSample*nClass列的矩阵,每一行表示一个样本的预期输出结果,该样本所属的那类对应的列设置为1,其他都为0。
比如我们需要识别0-9这10个数字,则总的类数为10类,那么样本数字“3”的预期输出为[0,0,1,0,0,0,0,0,0,0];
3) sampleWeights:一个在使用RPROP方法训练时才需要的数据,所以这里我们不设置,直接设置为Mat()即可。
4) sampleIdx:相当于一个遮罩,它指定哪些行的数据参与训练。如果设置为Mat(),则所有行都参与。
5) params:这个在刚才已经说过了,是训练相关的参数。
float CvANN_MLP::predict(constMat&inputs,Mat&outputs)
图像进行特征提取,把它保存在inputs里,通过调用predict函数,我们得到一个输出向量,它是一个1*nClass的行向量,
其中每一列说明它与该类的相似程度(0-1之间),也可以说是置信度。我们只用对output求一个最大值,就可得到结果。
这个函数的返回值是一个无用的float值,可以忽略。
完整代码样例二:
/* //CvANN 神经网络初试 测试数据集是特征维为9的癌症数据集 数据来源:E:\实验\大三\大三上\人工智能\实验五之DT&LR\数据集 //二元分类 //网址参考: http://blog.csdn.net/qq_15947787/article/details/51360287 #include "stdafx.h" #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/ml/ml.hpp> #include <iostream> #include <string> #include <time.h> #include <fstream> #include <opencv2/opencv.hpp> using namespace std; using namespace cv; const int COUNT_TRAIN = 500; //读入train数据的个数 const int COUNT_TEST = 100; const int DIM = 9; //输入向量的特征维数 int main() { //train float data[COUNT_TRAIN][DIM] = { 0 }; ifstream in("train_data.txt"); for (int i = 0; i < COUNT_TRAIN; i++) { for (int j = 0; j < DIM; j++) in >> data[i][j]; } in.close(); //for (int i = 0; i < COUNT; i++) // cout << data[i][0] << " " << data[i][1] << endl; float label[COUNT_TRAIN]; ifstream in2("train_label.txt"); for (int i = 0; i < COUNT_TRAIN; i++) in2 >> label[i]; in2.close(); //for (int i = 0; i < COUNT; i++) // cout << label[i] << endl; Mat trainData(COUNT_TRAIN, DIM, CV_32FC1, data); Mat trainLabel(COUNT_TRAIN, 1, CV_32FC1, label); //for (int i = 0; i < trainData.rows; i++) //{ // for (int j = 0; j < trainData.cols; j++) // cout << trainData.at<float>(i, j) << " "; // cout << endl; //} CvANN_MLP bp; CvANN_MLP_TrainParams param; param.term_crit = cvTermCriteria(CV_TERMCRIT_ITER + CV_TERMCRIT_EPS, 10000, 0.001); // 设置终止条件: 迭代次数和误差阈值 param.train_method = CvANN_MLP_TrainParams::BACKPROP; //反向传播 BackProgation param.bp_dw_scale = 0.1; // 与反向传播方法相关的系数 param.bp_moment_scale = 0.1; // 与反向传播方法相关的系数 Mat layerSizes = (Mat_<int>(1, 4) << DIM, 8, 5, 1); // 设置网络层: 9->8->5->1 ,最终得到的是与标签该类的相似度(0-1之间) //create第二个参数可以设置每个神经节点的激活函数,默认为CvANN_MLP::SIGMOID_SYM,即Sigmoid函数 //同时提供的其他激活函数有Gauss(CvANN_mlp::GAUSSIAN)和阶跃函数(CvANN_MLP::IDENTITY)。 bp.create(layerSizes, CvANN_MLP::SIGMOID_SYM); //bp.create(laySizes, CvANN_MLP::GAUSSIAN); //bp.create(layerSizes, CvANN_MLP::IDENTITY); bp.train(trainData, trainLabel, Mat(), Mat(), param); bp.save("bp.xml"); //test float testData[COUNT_TEST][DIM] = { 0 }; ifstream in3("test_data.txt"); for (int i = 0; i < COUNT_TEST; i++) { for (int j = 0; j < DIM; j++) in3 >> testData[i][j]; } in3.close(); float testLabel[COUNT_TEST] = { 0 }; ifstream in4("test_label.txt"); for (int i = 0; i < COUNT_TEST; i++) in4 >> testLabel[i]; in4.close(); Mat testDataMat(COUNT_TEST, DIM, CV_32FC1, testData); Mat testLabelMat(COUNT_TEST, 1, CV_32FC1, testLabel); //for (int i = 0; i < testDataMat.rows; i++) //{ // for (int j = 0; j < testDataMat.cols; j++) // cout << testDataMat.at<float>(i, j) << " "; // cout << endl; //} int testResult[COUNT_TEST] = { 0 }; for (int i = 0; i < COUNT_TEST; i++) { Mat responseMat; //Mat sampleMat = (Mat_<float>(1, 9) << 4, 2, 1, 1, 2, 1, 2, 1, 1); //正确标签为0 //Mat sampleMat = (Mat_<float>(1, 9) << 7, 4, 6, 4, 6, 1, 4, 3, 1); //正确标签为1 float sz[DIM] = { 0 }; for (int j = 0; j < DIM;j++) sz[j] = testDataMat.at<float>(i, j); //for (int j = 0; j < DIM; j++) // cout << sz[j] << " "; //cout << endl; Mat sampleMat(1, DIM, CV_32FC1,sz); bp.predict(sampleMat, responseMat); float result = responseMat.at<float>(0,0); if (result > 0.5) testResult[i] = 1; else testResult[i] = 0; //cout << responseMat.rows << " " << responseMat.cols << endl; for (int i = 0; i < responseMat.rows; i++) { for (int j = 0; j < responseMat.cols; j++) cout << responseMat.at<float>(i, j) << " "; cout << endl; } } int CorrectionCount = 0; for (int i = 0; i < COUNT_TEST; i++) { if (testResult[i] == testLabel[i]) CorrectionCount++; } cout << "Correction = " << CorrectionCount << endl; return 0; } */