OpenCV——神经网络
人工神经网络(ANN) 简称神经网络(NN),能模拟生物神经系统对物体所作出的交互反应,是由具有适应性的简单单元(称为神经元)组成的广泛并行互连网络。
1 神经元
1.1 M-P 神经元
如下图所示,来自其它神经元的信号,x1,x2,...,xnx1,x2,...,xn,传递过来作为输入信号,并通过带权重 (w1,w2,...,wnw1,w2,...,wn) 的连接 (connection) 继续传递,
然后神经元的总输入值 ∑wixi∑wixi 与阈值 θ 作比较,最后经过激活函数ff产生神经元的输出: y=f(∑i=1nwixi−θ)y=f(∑i=1nwixi−θ)

1.2 激活函数 (activation function)
理想中,阶跃函数可作为激活函数,将输入值映射为输出值 “0” 和 “1;实际中,常用 Sigmoid 函数作激活函数, f(x)=11+e−xf(x)=11+e−x,如下图所示:

OpenCV 中使用的激活函数是另一种形式,f(x)=β1−e−αx1+e−αxf(x)=β1−e−αx1+e−αx
当 α = β = 1 时,f(x)=1−e−x1+exf(x)=1−e−x1+ex,该函数把可能在较大范围内变化的输入值,“挤压” 到 (-1, 1) 的输出范围内
具体的设置函数如下,param1 --> α,param2 --> β
// 设置激活函数,目前只支持 ANN_MLP::SIGMOID_SYM virtual void cv::ml::ANN_MLP::setActivationFunction(int type, double param1 = 0, double param2 = 0);
2 神经网络
2.1 感知机 (perceptron)
感知机由两层神经元组成,输入层接收外界输入信号,而输出层则是一个 M-P 神经元。
实际上,感知机可视为一个最简单的“神经网络”,用它可很容易的实现逻辑与、或、非等简单运算。

2.2 层级结构
常见的神经网络,可分为三层:输入层、隐含层、输出层。输入层接收外界输入,隐层和输出层负责对信号进行加工,输出层输出最终的结果。
以下图为例:每层神经元与下一层神经元全互连,而同层神经元之间不连接,也不存在跨层连接,这样的结构称为“多层前馈神经网络”(multi-layer feedforward neural networks)

2.3 层数设置
OpenCV 中,设置神经网络层数和神经元个数的函数为 setLayerSizes(InputArray _layer_sizes),则上图对应的 InputArray 可由如下代码来构成
// (a) 3层,输入层神经元个数为 4,隐层的为 6,输出层的为 4 Mat layers_size = (Mat_<int>(1,3) << 4,6,4); // (b) 4层,输入层神经元个数为 4,第一个隐层的为 6,第二个隐层的为 5,输出层的为 4 Mat layers_size = (Mat_<int>(1,4) << 4,6,5,4);
如何设置隐层神经元的个数仍是个未决的问题,实际中多采用“试错法”来调整
3 OpenCV 函数
1) 创建
static Ptr<ANN_MLP> cv::ml::ANN_MLP::create(); // 创建空模型
2) 设置参数
// 设置神经网络的层数和神经元数量 virtual void cv::ml::ANN_MLP::setLayerSizes(InputArray _layer_sizes); // 设置激活函数,目前只支持 ANN_MLP::SIGMOID_SYM virtual void cv::ml::ANN_MLP::setActivationFunction(int type, double param1 = 0, double param2 = 0); // 设置训练方法,默认为 ANN_MLP::RPROP,较常用的是 ANN_MLP::BACKPROP // 若设为 ANN_MLP::BACKPROP,则 param1 对应 setBackpropWeightScale()中的参数,param2 对应 setBackpropMomentumScale() 中的参数 virtual void cv::ml::ANN_MLP::setTrainMethod(int method, double param1 = 0, double param2 = 0); virtual void cv::ml::ANN_MLP::setBackpropWeightScale(double val); // 默认值为 0.1 virtual void cv::ml::ANN_MLP::setBackpropMomentumScale(double val); // 默认值为 0.1 // 设置迭代终止准则,默认为 TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 1000, 0.01) virtual void cv::ml::ANN_MLP::setTermCriteria(TermCriteria val);
3) 训练
// samples - 训练样本; layout - 训练样本为 “行样本” ROW_SAMPLE 或 “列样本” COL_SAMPLE; response - 对应样本数据的分类结果
virtual bool cv::ml::StatModel::train(InputArray samples,int layout,InputArray responses);
4) 预测
// samples,输入的样本书数据;results,输出矩阵,默认不输出;flags,标识,默认为 0
virtual float cv::ml::StatModel::predict(InputArray samples, OutputArray results=noArray(),int flags=0) const;
4 代码示例
下面是 OpenCV 3.3 中,在“支持向量机”的例程上做的修改,使用 BP 神经网络,实现了和 SVM 相同的分类功能。
1 #include "opencv2/core/core.hpp"
2 #include "opencv2/imgproc/imgproc.hpp"
3 #include "opencv2/imgcodecs/imgcodecs.hpp"
4 #include "opencv2/highgui/highgui.hpp"
5 #include "opencv2/ml/ml.hpp"
6
7 using namespace cv;
8
9 int main()
10 {
11 // 512 x 512 零矩阵
12 int width = 512, height = 512;
13 Mat img = Mat::zeros(height, width, CV_8UC3);
14
15 // 训练样本
16 float train_data[6][2] = { { 500, 60 },{ 245, 40 },{ 480, 250 },{ 160, 380 },{400, 25},{55, 400} };
17 float labels[6] = {0,0,0,1,0,1}; // 每个样本数据对应的输出
18 Mat train_data_mat(6, 2, CV_32FC1, train_data);
19 Mat labels_mat(6, 1, CV_32FC1, labels);
20
21 // BP 模型创建和参数设置
22 Ptr<ml::ANN_MLP> bp = ml::ANN_MLP::create();
23
24 Mat layers_size = (Mat_<int>(1,3) << 2,6,1); // 2维点,1维输出
25 bp->setLayerSizes(layers_size);
26
27 bp->setTrainMethod(ml::ANN_MLP::BACKPROP,0.1,0.1);
28 bp->setActivationFunction(ml::ANN_MLP::SIGMOID_SYM);
29 bp->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 10000, /*FLT_EPSILON*/1e-6));
30
31 // 保存训练好的神经网络参数
32 bool trained = bp->train(train_data_mat,ml::ROW_SAMPLE,labels_mat);
33 if (trained) {
34 bp->save("bp_param");
35 }
36
37 // 创建训练好的神经网络
38 // Ptr<ml::ANN_MLP> bp = ml::ANN_MLP::load("bp_param");
39
40 // 显示分类的结果
41 Vec3b green(0, 255, 0), blue(255, 0, 0);
42 for (auto i=0; i<img.rows; ++i) {
43 for (auto j=0; j<img.cols; ++j) {
44 Mat sample_mat = (Mat_<float>(1, 2) << j, i);
45 Mat response_mat;
46 bp->predict(sample_mat,response_mat);
47 float response = response_mat.ptr<float>(0)[0];
48 if (response > 0.5) {
49 img.at<Vec3b>(i, j) = green;
50 } else if (response < 0.5) {
51 img.at<Vec3b>(i, j) = blue;
52 }
53 }
54 }
55
56 // 画出训练样本数据
57 int thickness = -1;
58 int lineType = 8;
59 circle(img, Point(500, 60), 5, Scalar(255, 255, 255), thickness, lineType);
60 circle(img, Point(245, 40), 5, Scalar(255, 255, 255), thickness, lineType);
61 circle(img, Point(480, 250), 5, Scalar(255, 255, 255), thickness, lineType);
62 circle(img, Point(160, 380), 5, Scalar(0, 0, 255), thickness, lineType);
63 circle(img, Point(400, 25), 5, Scalar(255, 255, 255), thickness, lineType);
64 circle(img, Point(55, 400), 5, Scalar(0, 0, 255), thickness, lineType);
65
66 imwrite("result.png", img); // 保存训练的结果
67 imshow("BP Simple Example", img);
68
69 waitKey(0);
70 }

浙公网安备 33010602011771号