热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

OpenCV之神经网络(一)

人工神经网络(ANN)简称神经网络(NN),能模拟生物神经系统对物体所作出的交互反应,是由具有适应性的简单单元(称为神经元)组成的广泛并行互连网络。1神

  人工神经网络(ANN) 简称神经网络(NN),能模拟生物神经系统对物体所作出的交互反应,是由具有适应性简单单元(称为神经元)组成的广泛并行互连网络

1  神经元

1.1  M-P 神经元

  如下图所示,来自其它神经元的信号,$x_1, x_2, ... , x_n $,传递过来作为输入信号,并通过带权重 ($w_1, w_2, ... , w_n$) 的连接 (connection) 继续传递,

  然后神经元的总输入值 $\sum w_i x_i$ 与阈值 $\theta$ 作比较,最后经过激活函数$\,f\,$产生神经元的输出: $y = f\left(\,\sum \limits_{i=1}^n {w_i x_i} - \theta \right)$

  

1.2  激活函数 (activation function)

  理想中,阶跃函数可作为激活函数,将输入值映射为输出值 “0” 和 “1;实际中,常用 Sigmoid 函数作激活函数, $f(x)=\,\dfrac{1}{1+e^{-x}}$,如下图所示:

 

  OpenCV 中使用的激活函数是另一种形式,$f(x)=\beta \,\dfrac{1-e^{-\alpha x}}{1+e^{-\alpha x}}$

  当 α = β = 1 时,$f(x)=\dfrac{1-e^{-x}}{1+e^{x}}$,该函数把可能在较大范围内变化的输入值,“挤压” 到 (-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 &#61; (Mat_<int>(1,3) <<4,6,4);// (b) 4层&#xff0c;输入层神经元个数为 4&#xff0c;第一个隐层的为 6&#xff0c;第二个隐层的为 5&#xff0c;输出层的为 4
Mat layers_size &#61; (Mat_<int>(1,4) <<4,6,5,4);

   如何设置隐层神经元的个数仍是个未决的问题&#xff0c;实际中多采用“试错法”来调整

 

3  OpenCV 函数

1)  创建

static Ptr cv::ml::ANN_MLP::create(); // 创建空模型

2) 设置参数

// 设置神经网络的层数和神经元数量
virtual void cv::ml::ANN_MLP::setLayerSizes(InputArray _layer_sizes);// 设置激活函数&#xff0c;目前只支持 ANN_MLP::SIGMOID_SYM
virtual void cv::ml::ANN_MLP::setActivationFunction(int type, double param1 &#61; 0, double param2 &#61; 0); // 设置训练方法&#xff0c;默认为 ANN_MLP::RPROP&#xff0c;较常用的是 ANN_MLP::BACKPROP
// 若设为 ANN_MLP::BACKPROP&#xff0c;则 param1 对应 setBackpropWeightScale()中的参数,param2 对应 setBackpropMomentumScale() 中的参数
virtual void cv::ml::ANN_MLP::setTrainMethod(int method, double param1 &#61; 0, double param2 &#61; 0);
virtual void cv::ml::ANN_MLP::setBackpropWeightScale(double val); // 默认值为 0.1
virtual void cv::ml::ANN_MLP::setBackpropMomentumScale(double val); // 默认值为 0.1// 设置迭代终止准则&#xff0c;默认为 TermCriteria(TermCriteria::MAX_ITER &#43; 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&#xff0c;输入的样本书数据&#xff1b;results&#xff0c;输出矩阵&#xff0c;默认不输出&#xff1b;flags&#xff0c;标识&#xff0c;默认为 0
virtual
float cv::ml::StatModel::predict(InputArray samples, OutputArray results&#61;noArray(),int flags&#61;0) const;      

 

4 代码示例

  下面是 OpenCV 3.3 中&#xff0c;在“支持向量机”的例程上做的修改&#xff0c;使用 BP 神经网络&#xff0c;实现了和 SVM 相同的分类功能。

   OpenCV 中的 支持向量机 (Support Vector Machine)&#xff0c;可参见另一篇博文 OpenCV 之 支持向量机 (一)

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 &#61; 512, height &#61; 512;
13 Mat img &#61; Mat::zeros(height, width, CV_8UC3);
14
15 // 训练样本
16 float train_data[6][2] &#61; { { 500, 60 },{ 245, 40 },{ 480, 250 },{ 160, 380 },{400, 25},{55, 400} };
17 float labels[6] &#61; {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 bp &#61; ml::ANN_MLP::create();
23
24 Mat layers_size &#61; (Mat_<int>(1,3) <<2,6,1); // 2维点&#xff0c;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 &#61; bp->train(train_data_mat,ml::ROW_SAMPLE,labels_mat);
33 if (trained) {
34 bp->save("bp_param");
35 }
36
37 // 创建训练好的神经网络
38 // Ptr bp &#61; ml::ANN_MLP::load("bp_param");
39
40 // 显示分类的结果
41 Vec3b green(0, 255, 0), blue(255, 0, 0);
42 for (auto i&#61;0; ii) {
43 for (auto j&#61;0; jj) {
44 Mat sample_mat &#61; (Mat_<float>(1, 2) << j, i);
45 Mat response_mat;
46 bp->predict(sample_mat,response_mat);
47 float response &#61; response_mat.ptr<float>(0)[0];
48 if (response > 0.5) {
49 img.at(i, j) &#61; green;
50 } else if (response <0.5) {
51 img.at(i, j) &#61; blue;
52 }
53 }
54 }
55
56 // 画出训练样本数据
57 int thickness &#61; -1;
58 int lineType &#61; 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 }

   运行结果如下所示:

   

注意&#xff1a;OpenCV 3.0 以上版本&#xff0c;相较之前的版本&#xff0c;其中有关机器学习的部分做了较大改动&#xff0c;本人也是踩了一些坑才得到预期的效果。

 1)  代码 #25&#xff0c;必须在 setActivationFunction() 之前&#xff0c;否则训练后的结果多为 nan

 2)  代码 #46&#xff0c;response_mat 为预测的结果。若输出向量为 1 列&#xff0c;则如 #47 所示&#xff0c;可直接取出预测结果&#xff1b;若输出向量为 n 列&#xff0c;则可取平均值或者最大值。

      同时&#xff0c;根据平均值或最大值&#xff0c;代码 #48 处的阈值也要相应的改变。

float response &#61; 0;for (auto i&#61;0;ii) {response &#43;&#61; response_mat.ptr<float>(0)[i];}

 3)  代码 #39&#xff0c;若已经训练好神经网络的参数&#xff0c;并将其保存到文件 bp_param 中。

      则可将 #22 ~ #35 全部注释掉&#xff0c;再反注释掉 #38&#xff0c;这样&#xff0c;直接加载训练好的神经网络&#xff0c;便可以使用了。

 

参考资料

  <机器学习> 周志华  第5章

  <统计学习方法> 李航  第1章

  OpenCV 3.0  Tutorials  -- Neural Networks

  OpenCV进阶之路&#xff1a;神经网络识别车牌字符       ☆Ronny丶

 【模式识别】OpenCV中使用神经网络 CvANN_MLP       xiaowei_cqu

 

转:https://www.cnblogs.com/xinxue/p/5789421.html



推荐阅读
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 本文介绍了UVALive6575题目Odd and Even Zeroes的解法,使用了数位dp和找规律的方法。阶乘的定义和性质被介绍,并给出了一些例子。其中,部分阶乘的尾零个数为奇数,部分为偶数。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • HDFS2.x新特性
    一、集群间数据拷贝scp实现两个远程主机之间的文件复制scp-rhello.txtroothadoop103:useratguiguhello.txt推pushscp-rr ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • 本文介绍了一个题目的解法,通过二分答案来解决问题,但困难在于如何进行检查。文章提供了一种逃逸方式,通过移动最慢的宿管来锁门时跑到更居中的位置,从而使所有合格的寝室都居中。文章还提到可以分开判断两边的情况,并使用前缀和的方式来求出在任意时刻能够到达宿管即将锁门的寝室的人数。最后,文章提到可以改成O(n)的直接枚举来解决问题。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • 本文介绍了如何使用Express App提供静态文件,同时提到了一些不需要使用的文件,如package.json和/.ssh/known_hosts,并解释了为什么app.get('*')无法捕获所有请求以及为什么app.use(express.static(__dirname))可能会提供不需要的文件。 ... [详细]
author-avatar
mobiledu2502852643
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有