人工智能入门


目录

1.人工智能的知识体系心得………………………………………………………………………… - 3-

1.1概述 -3-

1.2 人工智能四要素 - 4

1.3 人工智能领域划分 - 4 -

1.4 弱人工智能、强人工智能与超人工智能 - 4-

1.5 机器学习 - 4-

1.5.1监督学习 - 5-

1.5.2无监督学习 -5 -

1.5.3强化学习 - 5-

1.6 神经网络 - 5 -

2. 经典模型的实验过程…………………………………………………………………………. - 12-

2.1 水果识别(AI分类) - 13-

2.1.1 实验目的 - 13-

2.1.2 实验说明 - 14-

2.1.3 实验结果分析 - 15 -

2.2 遗传算法实验 - 15 -

2.2.1 实验目的 - 16 -

2.2.2 实验说明 - 17 -

2.2.3 实验结果 - 18 -

2.3 蚁群算法实践 - 20 -

2.3.1 实验目的 - 20 -

2.3.2实验说明 - 21 -

2.3.3 实验结果 - 21 -

2.4 【包括决策树、回归等】

2.5 BP神经网络与MNIST手写识别 - 23

2.4.1 BP神经网络简介 - 24 -

2.4.2 BP神经网络用于MNIST手写识别的实验….. - 25 -

2.4.3 Matlab代码部分 - 26-

3 课后作业****…………………………………………………………………………………….. -

3.1用自己所在省份的地区首府坐标实践一个蚁群算法或遗传算法的TSP问题…………27

3.2用MNIST数据库调试出一版识别率达到97%以上的参数…………………………………………….34

3.3思考一下车牌号识别的代码,或者尝试安装相应框架找到相应例程实践…………………38

1.人工智能的知识体系心得

1.1概述

1.APP应用,画像和偏好精准推送:抖音、头条、淘宝千人千面,滴滴打车,智能调度和路况预测分析,美颜和视频软件:人脸识别、图像识别、视频处理、手势识别,各个手机的语音助手等。

2、金融:营销和风控:客户画像精准营销,比如你的征信系统、芝麻分等,个人风险偏好。智能投资顾问,机器人电话营销、防欺诈系统、投资量化分析。

3、交通:自动驾驶,城市大脑等。

4、教育:因材施教、语音发音评测,机器阅卷等。

5、公检法:天网人脸,声纹防欺诈和抓捕,问询系统,智慧庭审,智慧卷宗等。

​ 人工智能(Artificial Intelligence)AI。它是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门新的技术科学。人工智能,它的范围很广,广义上的人工智能泛指通过计算机(机器)实现人的头脑思维,使机器像人一样去决策。是关于知识的学科――怎样表示知识以及怎样获得知识并使用知识的科学。研究使计算机来模拟人的某些思维过程和智能行为(如学习、推理、思考、规划等)的学科。它企图了解智能的实质,并生产出一种新的能以人类智能相似的方式做出反应的智能机器,不是人的智能,但能像人那样思考、也可能超过人的智能。该领域的研究包括机器人、语言识别、图像识别、自然语言处理和专家系统等。

​ 所以理解什么是人工智能,我认为最重要是记住理解,人工智能是指机器像人一样去决策。因此目前大量人工都集中在:如何为计算机提供“量”化的”经验“与”知识“。如何让机器学会“顿悟”。学会“不依赖于量变的质变”,从一种“质”直接到另一种“质”,或者从一个“概念”直接到另一个“概念”。

1.2人工智能四要素

​ 人工智能系统的四要素为:

1、大数据;人工智能的智能都蕴含在大数据中。

​ 如今这个时代,无时无刻不在产生大数据。移动设备、廉价的照相机、无处不在的传感器等等积累的数据。这些数据形式多样化,大部分都是非结构化数据。如果需要为人工智能算法所用,就需要进行大量的预处理过程。

2、算力;为人工智能提供了基本的计算能力的支撑。

​ 人工智能的发展对算力提出了更高的要求。以下是各种芯片的计算能力对比。其中GPU领先其他芯片在人工智能领域中用的最广泛。GPU和CPU都擅长浮点计算,一般来说,GPU做浮点计算的能力是CPU的10倍左右。另外深度学习加速框架通过在GPU之上进行优化,再次提升了GPU的计算性能,有利于加速神经网络的计算。如:cuDNN具有可定制的数据布局,支持四维张量的灵活维度排序,跨步和子区域,用作所有例程的输入和输出。在卷积神经网络的卷积运算中实现了矩阵运算,同时减少了内存,大大提升了神经网络的性能。

3、算法;实现人工智能的根本途径,是挖掘数据智能的有效方法。

​ 主流的算法主要分为传统的机器学习算法和神经网络算法。神经网络算法快速发展,近年来因为深度学习的发展到了高潮。

4、场景;对大量数据进行预处理。

​ 人工智能经典的应用场景包括:

(1)用户画像分析

(2)基于信用评分的风险控制

(3)欺诈检测

(4)智能投顾

(5)智能审核

(6)智能客服机器人

(7)机器翻译

(8)人脸识别

1.3人工智能领域划分

​ 从人工智能技术体系目前的研发方向来看,主要有六大研究方向,涉及到计算机视觉、自然语言处理、机器学习(深度学习)、机器人学、自动推理和知识表示。

1、人工智能的领域分类——深度学习

​ 深度学习是基于现有的数据进行学习操作,是机器学习研究中的一个新的领域,机在于建立、模拟人脑进行分析学习的神经网络,它模仿人脑的机制来解释数据,例如图像,声音和文本。深度学习是无监督学习的一种。

2、人工智能的领域分类——自然语言处理

​ 自然语言处理是用自然语言同计算机进行通讯的一种技术。人工智能的分支学科,研究用电子计算机模拟人的语言交际过程,使计算机能理解和运用人类社会的自然语言如汉语、英语等,实现人机之间的自然语言通信,以代替人的部分脑力劳动,包括查询资料、解答问题、摘录文献、汇编资料以及一切有关自然语言信息的加工处理。例如生活中的电话机器人的核心技术之一就是自然语言处理.

3、人工智能的领域分类——计算机视觉

​ 计算机视觉是指用摄影机和电脑代替人眼对目标进行识别、跟踪和测量等机器视觉,并进一步做图形处理,使电脑处理成为更适合人眼观察或传送给仪器检测的图像。

​ 计算机视觉就是用各种成象系统代替视觉器官作为输入敏感手段,由计算机来代替大脑完成处理和解释。计算机视觉的最终研究目标就是使计算机能像人那样通过视觉观察和理解世界,具有自主适应环境的能力。计算机视觉应用的实例有很多,包括用于控制过程、导航、自动检测等方面。

4、人工智能的领域分类——智能机器人

​ 如今我们的身边逐渐开始出现很多智能机器人,他们具备形形色色的内部信息传感器和外部信息传感器,如视觉、听觉、触觉、嗅觉。除具有感受器外,它还有效应器,作为作用于周围环境的手段。这些机器人都离不开人工智能的技术支持。

​ 科学家们认为,智能机器人的研发方向是,给机器人装上”大脑芯片”,从而使其智能性更强,在认知学习、自动组织、对模糊信息的综合处理等方面将会前进—大步。

5、人工智能的领域分类——自动程序设计

​ 自动程序设计是指根据给定问题的原始描述,自动生成满足要求的程序。它是软件工程和人工智能相结合的研究课题。自动程序设计主要包含程序综合和程序验证两方面内容。前者实现自动编程,即用户只需告知机器”做什么”,无须告诉”怎么做”,这后一步的工作由机器自动完成;后者是程序的自动验证,自动完成正确性的检查。其目的是提高软件生产率和软件产品质量。

​ 自动程序设计的任务是设计一个程序系统,接受关于所设计的程序要求实现某个目标非常高级描述作为其输入,然后自动生成一个能完成这个目标的具体程序。该研究的重大贡献之一是把程序调试的概念作为问题求解的策略来使用。

6、人工智能的领域分类——数据挖掘

​ 数据挖掘一般是指从大量的数据中通过算法搜索隐藏于其中信息的过程。它通常与计算机科学有关,并通过统计、在线分析处理、情报检索、机器学习、专家系统(依靠过去的经验法则)和模式识别等诸多方法来实现上述目标。它的分析方法包括:分类、估计、预测、相关性分组或关联规则、聚类和复杂数据类型挖掘。

1.4 弱人工智能、强人工智能、超人工智能

​ 人工智能有三种类型,分别是弱人工智能、强人工智能、超人工智能。

弱人工智能

​ 弱人工智能的英文是Artificial Narrow Intelligence,简称为ANI, 弱人工智能是擅长于单个方面的人工智能。

​ 比如有能战胜象棋世界冠军的人工智能阿尔法狗,但是它只会下象棋,如果我们问它其他的问题那么它就不知道怎么回答了。只有擅长单方面能力的人工智能就是弱人工智能。

强人工智能

​ 强人工智能的英文是Artificial General Intelligence,简称AGI,这是一种类似于人类级别的人工智能。强人工智能是指在各方面都能和人类比肩的人工智能,人类能干的脑力活它都能干。

​ 创造强人工智能比创造弱人工智能难得多,我们现在还做不到。强人工智能就是一种宽泛的心理能力,能够进行思考、计划、解决问题、抽象思维、理解复杂理念、快速学习和从经验中学习等操作。强人工智能在进行这些操作时应该和人类一样得心应手。

超人工智能

​ 超人工智能的英文是Artificial Superintelligence,简称ASI,科学家把超人工智能定义为在几乎所有领域都比最聪明的人类大脑都聪明很多,包括科学创新、通识和社交技能。

1.5机器学习

img

1.5.1监督学习

​ 给学习算法一个数据集。数据集中的每个样本都有正确答案。运用学习算法,得出更多的正确答案。在监督学习中,有别于分类问题,还有一个重要的回归问题,即通过训练数据学习一个从观测样本到连续的标签的映射,在回归问题中的标签是一系列连续的值。典型的有,如前段提到的收入预测,还有根据股票的历史价格预测未来股票的价格,房屋价格预测等等。是基于给定的训练数据集中学习出一个模型,当新的数据到来时,按照这个模型预测结果即可。这是一种比较简单的机器学习的模式,相比传统软件模式,它通过统计学、概率学、回归分析的方式让数据变得更加可靠,可以说实现了人工智能的一小步。

1.5.2无监督学习

​ 在unsupervised learning当中,其训练集只有特征,不包含标签信息。其流程较监督学习简单,分为数据获取,特征提取和无监督学习。比如有M个训练数据,首先对m个样本进行处理,得到有用信息,这个过程就成为特征提取,最后利用无监督学习算法处理这些样本。是基于数据之间的相似性进行聚类分析学习,发现相似的内容。它是有监督学习的补充,因为在现实生活中,很多数据我们是没有办法事先想到的、事先进行分类的,通过无监督学习,即使是事先不知道的数据类型,也可以通过训练挖掘它们之间的关系,辅助人类进行决策

1.5.3强化学习

​ 强化学习研究学习器在与环境的交互过程中,如何学习到一种行为策略,以最大化得到的累积奖赏。与前面我们提到的其它学习问题的不同在于,强化学习处在一个对学习器的行为进行执行和评判的环境中:环境将执行学习器的输出,发生变化,并且反馈给学习器一个奖赏值;同时学习器的目标并不在于最大化立即获得的奖赏,而是最大化长期累积的奖赏。例如在俄罗斯方块游戏中,学习器所处的环境为游戏规则,学习器根据当前游戏的状态输出动作,以游戏得分作为每一次动作的奖赏,学习器需要最大化最终的奖赏总和。

1.6神经网络

​ 人工神经网络(Artificial Neural Network,即ANN ),是20世纪80 年代以来人工智能领域兴起的研究热点。它从信息处理角度对人脑神经元网络进行抽象, 建立某种简单模型,按不同的连接方式组成不同的网络。在工程与学术界也常直接简称为神经网络或类神经网络。神经网络是一种运算模型,由大量的节点(或称神经元)之间相互联接构成。每个节点代表一种特定的输出函数,称为激励函数(activation function)。每两个节点间的连接都代表一个对于通过该连接信号的加权值,称之为权重,这相当于人工神经网络的记忆。网络的输出则依网络的连接方式,权重值和激励函数的不同而不同。而网络自身通常都是对自然界某种算法或者函数的逼近,也可能是对一种逻辑策略的表达。

​ 第一次兴起(1958年):感知机,由于没有引入非线性,不能求解异或问题。

​ 第二次兴起(1986年):Back Propagation BP神经网络的提出。

​ 第三次兴起(2012年):深度学习的兴起,一直到现在。

3 个部分组成了神经网络的的基本架构:

  • 单元/神经元
  • 连接/权重/参数
  • 偏置项

单元/神经元:

​ 作为神经网络架构三个部分中最不重要的部分,神经元是包含权重和偏置项的函数,等待数据传递给它们。接收数据后,它们执行一些计算,然后使用激活函数将数据限制在一个范围内(多数情况下)。

​ 一端接收数据,另一端输出修改后的数据。数据首先进入盒子中,将权重与数据相乘,再向相乘的数据添加偏置项。这是一个单元,也可以被认为是一个函数。该函数与下面这个直线方程类似:

img

权重/参数/连接 (weights/parameters/connection):

​ 作为神经网络最重要的部分,这些(和偏置项)是用神经网络解决问题时必须学习的数值。

偏置项 (bias)

​ 这些数字代表神经网络认为其在将权重与数据相乘之后应该添加的内容。当然,它们经常出错,但神经网络随后也学习到最佳偏置项。

​ 此外,在神经网络中扮演重要角色的还有:

超参数 (hyper parameter):

​ 超参数必须手动设置。如果将神经网络看作一台机器,那么改变机器行为的 nob 就是神经网络的超参数。

激活函数 (activation):

​ 也称为映射函数(mapping function)。它们在 x 轴上输入数据,并在有限的范围内(大部分情况下)输出一个值。大多数情况下,它们被用于将单元的较大输出转换成较小的值。你选择的激活函数可以大幅提高或降低神经网络的性能。常用的激活函数有Sigmoid函数、Tanh函数、修正线性单元函数(ReLu)、Leaky ReLU等。

层 (layer):

​ 这是神经网络在任何问题中都可获得复杂度的原因。增加层(具备单元)可增加神经网络输出的非线性。每个层都包含一定数量的单元。大多数情况下单元的数量完全取决于创建者。但是,对于一个简单的任务而言,层数过多会增加不必要的复杂性,且在大多数情况下会降低其准确率。反之亦然。每个神经网络有一定有两个层:输入层和输出层,二者之间的层称为隐藏层

一、感知器

​ 历史上,科学家一直希望模拟人的大脑,造出可以思考的机器。人为什么能够思考?科学家发现,原因在于人体的神经网络。

img

  1. 外部刺激通过神经末梢,转化为电信号,转导到神经细胞(又叫神经元)。
  2. 无数神经元构成神经中枢。
  3. 神经中枢综合各种信号,做出判断。
  4. 人体根据神经中枢的指令,对外部刺激做出反应。

​ 既然思考的基础是神经元,如果能够”人造神经元”(artificial neuron),就能组成人工神经网络,模拟思考。上个世纪六十年代,提出了最早的”人造神经元”模型,叫做“感知器”(perceptron),直到今天还在用。

img

​ 上图的圆圈就代表一个感知器。它接受多个输入(x1,x2,x3…),产生一个输出(output),好比神经末梢感受各种外部环境的变化,最后产生电信号。

​ 为了简化模型,我们约定每种输入只有两种可能:1 或 0。如果所有输入都是1,表示各种条件都成立,输出就是1;如果所有输入都是0,表示条件都不成立,输出就是0。

​ 但是经过观察,可以发现,对于只有输入层与输出层的感知机模型, ∑ i = 1 2 ω i x i − θ \sum\limits^2_{i=1}ω_ix_i−θ i=1∑2ωixi−θ是线性的,其只能对线性数据进行划分,对于异或模型,其实无法准确划分的。

​ 但如果是两层网络(这里的两层指的是隐层与输出层,因为只有这两层中的节点是有激活函数的),在隐层有两个节点,那么此时就可以得到两条线性函数,再在输出节点汇总之后,将会得到由两条直线围成的一个面,这时就可以成功的将异或问题解决。

这里写图片描述

这里写图片描述

二、决策模型

​ 单个的感知器构成了一个简单的决策模型,已经可以拿来用了。真实世界中,实际的决策模型则要复杂得多,是由多个感知器组成的多层网络。

img

​ 上图中,底层感知器接收外部输入,做出判断以后,再发出信号,作为上层感知器的输入,直至得到最后的结果。(注意:感知器的输出依然只有一个,但是可以发送给多个目标。)

三、神经网络的运作过程

​ 一个神经网络的搭建,需要满足三个条件。

  • 输入和输出
  • 权重(w)和阈值(b)
  • 多层感知器的结构

img

​ 其中,最困难的部分就是确定权重(w)和阈值(b)。目前为止,这两个值都是主观给出的,但现实中很难估计它们的值,必需有一种方法,可以找出答案。

​ 这种方法就是试错法。其他参数都不变,w(或b)的微小变动,记作Δw(或Δb),然后观察输出有什么变化。不断重复这个过程,直至得到对应最精确输出的那组w和b,就是我们要的值。这个过程称为模型的训练。

img

​ 因此,神经网络的运作过程如下:

  1. 确定输入和输出
  2. 找到一种或多种算法,可以从输入得到输出
  3. 找到一组已知答案的数据集,用来训练模型,估算w和b
  4. 一旦新的数据产生,输入模型,就可以得到结果,同时对w和b进行校正

​ 可以看到,整个过程需要海量计算。所以,神经网络直到最近这几年才有实用价值,而且一般的 CPU 还不行,要使用专门为机器学习定制的 GPU 来计算

四、神经网络的例子

车牌自动识别

​ 所谓”车牌自动识别”,就是高速公路的探头拍下车牌照片,计算机识别出照片里的数字。

​ 车牌照片就是输入,车牌号码就是输出,照片的清晰度可以设置权重(w)。然后,找到一种或多种图像比对算法,作为感知器。算法的得到结果是一个概率,比如75%的概率可以确定是数字1。这就需要设置一个阈值(b)(比如85%的可信度),低于这个门槛结果就无效。

​ 一组已经识别好的车牌照片,作为训练集数据,输入模型。不断调整各种参数,直至找到正确率最高的参数组合。以后拿到新照片,就可以直接给出结果了。

2.经典模型的实验过程

2.1水果识别(AI分类)

2.1.1实验目的

​ 朴素贝叶斯(分类器)是一种生成模型,它会基于训练样本对每个可能的类别建模。之所以叫朴素贝叶斯,是因为采用了属性条件独立性假设,就是假设每个属性独立地对分类结果产生影响。即有下面的公式:

img

​ 后面连乘的地方要注意的是,如果有一项概率值为0会影响后面估计,所以我们对未出现的属性概率设置一个很小的值,并不为0,这就是拉普拉斯修正(Laplacian correction)。

img

​ 拉普拉斯修正实际上假设了属性值和类别的均匀分布,在学习过程中额外引入了先验识。

整个朴素贝叶斯分类分为三个阶段:

​ 准备工作阶段,这个阶段的任务是为朴素贝叶斯分类做必要的准备,主要工作是根据具体情况确定特征属性,并对每个特征属性进行适当划分,然后由人工对一部分待分类项进行分类,形成训练样本集合。这一阶段的输入是所有待分类数据,输出是特征属性和训练样本。这一阶段是整个朴素贝叶斯分类中唯一需要人工完成的阶段,其质量对整个过程将有重要影响,分类器的质量很大程度上由特征属性、特征属性划分及训练样本质量决定。

2.

​ 分类器训练阶段,这个阶段的任务就是生成分类器,主要工作是计算每个类别在训练样本中的出现频率及每个特征属性划分对每个类别的条件概率估计,并将结果记录。其输入是特征属性和训练样本,输出是分类器。这一阶段是机械性阶段,根据前面讨论的公式可以由程序自动计算完成。

3.

​ 应用阶段,这个阶段的任务是使用分类器对待分类项进行分类,其输入是分类器和待分类项,输出是待分类项与类别的映射关系。这一阶段也是机械性阶段,由程序完成。

2.1.2实验说明

​ 所需分类的水果原始图像如下:

img

​ 图像二值化后结果如下:

img

​ 分离目标后结果:

img

​ 分别对水果进行颜色和形状特征提取,结果如下:

imgimg

​ 水果分类结果如下:

img

2.1.3 实验结果分析

​ 从上面水果的贝叶斯分类可以看出朴素贝叶斯分类的优缺点

优点:

(1)朴素贝叶斯模型发源于古典数学理论,有稳定的分类效率。

(2)对小规模的数据表现很好,能个处理多分类任务,适合增量式训练,尤其是数据量超出内存时,我们可以一批批的去增量训练。

(3)对缺失数据不太敏感,算法也比较简单,常用于文本分类。

缺点:

(1)理论上,朴素贝叶斯模型与其他分类方法相比具有最小的误差率。但是实际上并非总是如此,这是因为朴素贝叶斯模型给定输出类别的情况下,假设属性之间相互独立,这个假设在实际应用中往往是不成立的,在属性个数比较多或者属性之间相关性较大时,分类效果不好。而在属性相关性较小时,朴素贝叶斯性能最为良好。对于这一点,有半朴素贝叶斯之类的算法通过考虑部分关联性适度改进。

(2)需要知道先验概率,且先验概率很多时候取决于假设,假设的模型可以有很多种,因此在某些时候会由于假设的先验模型的原因导致预测效果不佳。

(3)由于我们是通过先验和数据来决定后验的概率从而决定分类,所以分类决策存在一定的错误率。

2.2 遗传算法实验

2.2.1 实验目的

​ 遗传算法的一般步骤:

1.开始循环直至找到满意的解。

2.评估每条染色体所对应个体的适应度。

3.遵照适应度越高,选择概率越大的原则,从种群中选择两个个体作为父方和母方。

4.抽取父母双方的染色体,进行交叉,产生子代。

5.对子代的染色体进行变异。

6.重复2,3,4步骤,直到新种群的产生。

7.结束循环。

​ 具体问题:求解函数f(x)=10sin(5x)+7cos(4x) ,0<=x<=10的最大值。

3.3 调试结论

​ 通过上述几十次实验,很容易得到结论:对于遗传算法而言,无论参数如何设置都无法避免陷入局部最优解。

​ 通过改变种群规模的实验组,不难看出种群大小过于低会严重影响成功率,但是过大的种群成功率也没有显著提高,一般种群大小在30-50之间即可。

​ 通过改变交叉概率的实验组,可以看到交叉概率在0.8附近即可,不必过于大。

​ 通过改变变异概率的实验组,可以看到变异概率在0.004-0.01附近即可.

遗传算法的优点总结如下:

一、对可行解表示的广泛性。由于遗传算法的处理对象并不是参数本身,而是那些通过参数集进行编码得到的基因个体,因而该算法可以直接对结构对象(如集合、序列、矩阵、树、链和表等)进行操作。

1、通过对连接矩阵的操作,可用来对神经网络或自动机的结构或参数加以优化。

2、通过对集合的操作,可实现对规则集合和知识库的精练而达到高质量的机器学习目的。

3、通过对树结构的操作,可得到用于分类的最佳决策树。(可以用于对含能化合物进行分类)

4、通过对人物序列的操作,可用于任务规划;通过对操作序列的处理,可自动构造顺序控制系统。

二、群体搜索特性。遗传算法同时处理群体中多个个体,即同时对搜索空间中的多个解进行评估。使其具有较好的全局搜索性能,并易于并行化。

三、不需要辅助信息。仅用适应度函数来评估基因个体,并在此基础上进行遗传操作。

四、内在启发式随机搜索特性。遗传算法不采用确定性规则,而是采用概率的变迁规则来指导搜索方向。

五、在搜索过程中不易陷入局部最优。即使在所定义的适应度函数是不连续的、非规则的或有噪声的情况下。

六、采用自然进化机制来表现复杂的现象。能够快速准确的解决求解非常困难的问题。

七、具有固有的并行性和并行计算能力。

八、具有可扩展性。易于同别的技术混合使用。

缺点:

1、编码不规范及编码存在表示的不准确性。

2、单一的遗传算法编码不能全面的将优化问题的约束表示出来。

3、效率通常比较低。

4、容易出现过早收敛。

5、对算法的精度、可信度、计算复杂性等方面,还没有有效的定量分析方法。

2.2.2实验说明

​ 程序初始设置参数:popsize=100(群体大小)、chromlength=10(个体长度)、pc=0.7(交叉概率)、pm=0.008(变异概率)、迭代次数为20.(注明:相同参数情况下每次运行结果也会出现差异,所以不采用比较最大值的方法,这里采用比较求10次运算找到最大值波峰的概率P)

​ 运行后得到下图结果:

img

​ 概率P=0.9

1.改变群体大小

​ 令popsize分别为200、150、50、10,再与popsize=100的结果形成对照实验,结果依次如下:

imgimg

​ 概率P=1 概率P=0.9

imgimg

​ 概率P=0.8 概率P=0.1

2.改变交叉概率

​ 令pc分别为0.5、0.9,再与开始的0.7形成对照实验,结果如下:

​ 概率P=0.8 概率P=0.9

3.改变变异概率

​ 令pm=0.01、0.006,再与开始的0.008形成对照实验,结果如下:

​ 概率P=0.9 概率P=0.7

2.2.3实验结果分析

​ 通过上述几十次实验,很容易得到结论:对于遗传算法而言,无论参数如何设置都无法避免陷入局部最优解。

​ 通过改变种群规模的实验组,不难看出种群大小过于低会严重影响成功率,但是过大的种群成功率也没有显著提高。

​ 通过改变交叉概率的实验组,可以看到交叉概率在0.8附近即可,不必过于大。

​ 通过改变变异概率的实验组,可以看到变异概率在0.007-0.01附近即可.

遗传算法的优点总结如下:

一、对可行解表示的广泛性。

​ 由于遗传算法的处理对象并不是参数本身,而是那些通过参数集进行编码得到的基因个体,因而该算法可以直接对结构对象(如集合、序列、矩阵、树、链和表等)进行操作。

1、通过对连接矩阵的操作,可用来对神经网络或自动机的结构或参数加以优化。

2、通过对集合的操作,可实现对规则集合和知识库的精练而达到高质量的机器学习目的。

3、通过对树结构的操作,可得到用于分类的最佳决策树。(可以用于对含能化合物进行分类)

4、通过对人物序列的操作,可用于任务规划;通过对操作序列的处理,可自动构造顺序控制系统。

二、群体搜索特性。

​ 遗传算法同时处理群体中多个个体,即同时对搜索空间中的多个解进行评估。使其具有较好的全局搜索性能,并易于并行化。

二、不需要辅助信息。

​ 仅用适应度函数来评估基因个体,并在此基础上进行遗传操作。

三、内在启发式随机搜索特性。

​ 遗传算法不采用确定性规则,而是采用概率的变迁规则来指导搜索方向。

四、在搜索过程中不易陷入局部最优。

​ 即使在所定义的适应度函数是不连续的、非规则的或有噪声的情况下。

五、采用自然进化机制来表现复杂的现象。

​ 能够快速准确的解决求解非常困难的问题。

六、具有固有的并行性和并行计算能力。

七、具有可扩展性。易于同别的技术混合使用。

缺点:

1、编码不规范及编码存在表示的不准确性。

2、单一的遗传算法编码不能全面的将优化问题的约束表示出来。

3、效率通常比较低。

4、容易出现过早收敛。

5、对算法的精度、可信度、计算复杂性等方面,还没有有效的定量分析方法。

2.3蚁群算法实践

2.3.1 实验目的

​ 假设有一个旅行商人要拜访n个城市,他必须选择所要走的路径,路径的限制是每个城市只能拜访一次,而且最后要回到原来出发的城市。路径的选择目标是要求得的路径路程为所有路径之中的最小值。

2.3.2 实验说明

​ 将坐标改为山西省相对坐标

1
2
3
        x=[25.3,26.5,33,35.7,30.8,28.3,15,9.7];

​ y=[28.7,30.5,51.2,28.5,11.8,5.2,10.8,0.3];

img

2.3.3 实验结果分析

​ 最终得出的旅行商人的最佳路径如上图的运行结果所示,线条连接的即为最优路径。

蚁群算法在解决TSP问题时效率还是很高的。

2.4 决策树

2.4.1实验目的

​ 通过简单的决策树问题的代码调试过程,体会信息增益、熵对决策树建立的影响以及一般问题中信息增益和熵的计算公式,除此之外,也可以了解如何解决决策树过拟合问题以及我们该如何选择合适的精度既能否则具体问题又不会产生过拟合。

2.4.2 实验说明

​ 决策树是在已知各项真实数据的基础上,通过构成决策树来建立决策过程。

​ 首先,原程序是对于三个品种(lable1、2、3)的酒建立决策树,建立的依据为已知的数据,其中有59组第一种酒的数据,71组第二种酒的数据,48组第三种酒的数据。每组酒的数据中分别包含13个参数(attribute),每个参数通过计算信息熵设置阈值,从而设置分支点。

​ 分别改变考虑的属性个数: 7个、9个、11个、13个。

​ 建立的决策树分别如下所示:

img

img

img

2.4.3 实验结果分析

​ 参考七个属性时:测试集准确率为89~91%

​ 参考九个属性时:测试集准确率为95~97%

​ 参考十一个属性时:测试集准确率为95~97%

​ 参考十三个属性时:测试集准确率为95~97%

​ 由此可见,对于参考属性的增加,决策树的准确率有所提升,但是当参考属性到达一定数量时,测试集准确率提升幅度较小,有时,准确率会下降。对于每一个参考属性,所得的信息增益各有不同,部分属性信息增益较大,有效,部分属性信息的属性增益可忽略。

​ 对于决策树而言,增加参考的属性有利于决策树的简化,可以获得更简单有效的决策树模型。

2.5 BP神经网络与MINIST手写识别

2.5.1实验目的

​ 了解手写体数字识别原理,熟悉程序内容

2.5.2 实验说明

​ 对于MNIST训练集中,各手写体字的图像均是28*28的灰度图像,通过对每个像素点展开成为一位向量,使其能够成为训练数据。

​ 因此在该多层感知器中,需要28*28即784个输入神经元,每个神经元的值为0255的图像灰度值。而输出层包含10个神经元,分别对应数字09。

​ 主要参数有隐含层结点个数,训练迭代次数,学习率。

​ 利用程序测试100组已给数据:

​ 隐含层结点个数:100训练迭代次数:100学习率:0.3

img

​ 隐含层结点个数:100训练迭代次数:100学习率:0.8

img

​ 隐含层结点个数:100训练迭代次数:10学习率:0.3

img

​ 隐含层结点个数:100训练迭代次数:10学习率:0.8

img

​ 隐含层结点个数:10训练迭代次数:100学习率:0.3

img

​ 隐含层结点个数:10训练迭代次数:100学习率:0.8

img

2.5.3实验结果分析

​ 由上述程序运行结果可知,对于检测的正确率,训练的迭代次数越高,检测的正确率越高,正确率的提升效果显著。隐含层数量越多,对于检测的正确率提升也越大。不过相对而言,越多的隐含层以及越多的迭代次数会使程序运行的速度减慢。

​ 由此可见,当训练样本数量提升时,对于测试集合的检测准确率将不断上升。

​ 基于多层感知器(BP神经网络)的手写体数字识别程序中,影响检测精度的因素主要有训练样本数量、训练迭代次数、隐含层数量,训练样本越充足、迭代次数越大、隐含层越多,检测精度就越高,相应的程序运行速率会显著下降。当训练样本、迭代次数以及隐含层到达一定数量后,检测精度提升有限,相反,运行速率下降显著。

3. 课后作业

3.1用自己所在省份的地区首府坐标实践一个蚁群算法或遗传算法的TSP问题

img img

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
\include <iostream>

\#include <algorithm>

\#include <cstring>

\#include <windows.h>

\#include <stdio.h>

\#include <stdlib.h>

\#include <math.h>

\#include <time.h>

using namespace std;

/*

int CityPos[8][2]={{25,29},{27,31},{33,51},{36,29},{31,12},{28,5},{15,11},{10,0}}

}; //10个城市的坐标*/

unsigned seed=(unsigned)time(0);//原型:void srand(unsigned seed);

//30个城市的坐标



int CityPos[8][2]={{25,29},{27,31},{33,51},{36,29},{31,12},{28,5},{15,11},{10,0}};



\#define CITY_NUM 8 //城市数量

\#define ANT_NUM 30 //蚁群数量

\#define TMAC 1000 //迭代最大次数

\#define ROU 0.5 //误差大小

\#define ALPHA 1 // 信息素重要程度的参数

\#define BETA 4 // 启发式因子重要程度的参数

\#define Q 100 //信息素残留参数

const int maxn = 100;

double dis[maxn][maxn]; //距离

double info[maxn][maxn]; //信息素矩阵

double E[CITY_NUM][CITY_NUM]; //启发因子矩阵

int vis[CITY_NUM][CITY_NUM];

double Bestlength;

double ans[CITY_NUM];

const double mmax = 10e9;



//返回指定范围内的随机整数

int rnd(int nLow,int nUpper)

{

return nLow+(nUpper-nLow)*rand()/(RAND_MAX+1);

}



//返回指定范围内的随机浮点数

double rnd(double dbLow,double dbUpper)

{

double dbTemp=rand()/((double)RAND_MAX+1.0);

return dbLow+dbTemp*(dbUpper-dbLow);

}

//返回浮点数四舍五入取整后的浮点数

double ROUND(double dbA)

{

return (double)((int)(dbA+0.5));

}



struct Ant

{



int Path[CITY_NUM]; //蚂蚁走的路径

double length; //路径总长度

int vis[CITY_NUM]; //走过城市标记

int cur_cityno; //当前城市

int moved_cnt; //已走的数量

//初始化

void Init()

{

​ memset(vis, 0, sizeof(vis));

​ length = 0;

​ cur_cityno = rnd(0, CITY_NUM);//随机选择一个出发城市

​ Path[0] = cur_cityno;

​ vis[cur_cityno] = 1;

​ moved_cnt = 1;

​ //printf("Init %d \n", cur_cityno);

}

//选择下一个城市

//返回值 为城市编号

int chooseNextCity()

{

​ int nSelectedCity=-1; //返回结果,先暂时把其设置为-1

​ //计算当前城市和没去过的城市之间的信息素总和

​ double dbTotal=0.0;

​ double prob[CITY_NUM]; //保存各个城市被选中的概率

​ for(int i = 0; i < CITY_NUM; i++)

​ {

​ if (!vis[i])

​ {

​ prob[i]=pow(info[cur_cityno][i],ALPHA)

​ *pow(1.0/dis[cur_cityno][i], BETA);

​ dbTotal += prob[i];

​ }

​ else

​ {

​ prob[i] = 0;

​ }

​ }

​ //进行轮盘选择

​ double dbTemp=0.0;

​ if (dbTotal > 0.0) //总的信息素值大于0

​ {

​ dbTemp = rnd(0.0, dbTotal);

​ for (int i = 0; i < CITY_NUM; i++)

​ {

​ if (!vis[i])

​ {

​ dbTemp -= prob[i];

​ if (dbTemp < 0.0)

​ {

​ nSelectedCity = i;

​ break;

​ }

​ }

​ }

​ }

​ //如果城市间的信息素非常小 ( 小到比double能够表示的最小的数字还要小 )

​ //出现这种情况,就把第一个没去过的城市作为返回结果



​ if (nSelectedCity == -1)

​ {

​ for (int i=0; i<CITY_NUM; i++)

​ {

​ if (!vis[i]) //城市没去过

​ {

​ nSelectedCity=i;

​ break;

​ }

​ }

​ }

​ return nSelectedCity;

}



//蚂蚁在城市间移动

void Move()

{

​ int nCityno = chooseNextCity();//选择下一个城市

​ Path[moved_cnt] = nCityno;//保存蚂蚁走的路径

​ vis[nCityno] = 1;//把这个城市设置成已经去过

​ cur_cityno = nCityno;

​ //更新已走路径长度

​ length += dis[Path[moved_cnt-1]][Path[moved_cnt]];

​ moved_cnt++;



}

//蚂蚁进行搜索一次

void Search()

{

​ Init();

​ //如果蚂蚁去过的城市数量小于城市数量,就继续移动

​ while(moved_cnt < CITY_NUM)

​ {

​ Move();

​ }

​ length += dis[Path[CITY_NUM-1]][Path[0]];

}



};





struct TSP

{

Ant ants[ANT_NUM]; //定义一群蚂蚁

Ant ant_best; //保存最好结果的蚂蚁



void Init()

{

​ //初始化为最大值

​ ant_best.length = mmax;

​ puts("cal dis");

​ //计算两两城市间距离

​ for (int i = 0; i < CITY_NUM; i++)

​ {

​ for (int j = 0; j < CITY_NUM; j++)

​ {

​ double temp1=CityPos[j][0]-CityPos[i][0];

​ double temp2=CityPos[j][1]-CityPos[i][1];

​ dis[i][j] = sqrt(temp1*temp1+temp2*temp2);

​ }

​ }

​ //初始化环境信息素

​ puts("init info");

​ for (int i=0; i<CITY_NUM; i++)

​ {

​ for (int j=0; j<CITY_NUM; j++)

​ {

​ info[i][j]=1.0;

​ }

​ }

}

//更新信息素,当前每条路上的信息素等于过去保留的信息素

//加上每个蚂蚁这次走过去剩下的信息素

void Updateinfo()

{

​ //puts("update info");

​ double tmpinfo[CITY_NUM][CITY_NUM];

​ memset(tmpinfo, 0, sizeof(tmpinfo));

​ int m = 0;

​ int n = 0;

​ //遍历每只蚂蚁

​ for (int i = 0; i < ANT_NUM; i++) {

​ //puts("****");

// for (int j = 0; j < CITY_NUM; j++) {

// printf("%d ", ants[i].Path[j]);

// }

​ //puts("");

​ for (int j = 1; j < CITY_NUM; j++)

​ {

​ m = ants[i].Path[j];

​ n = ants[i].Path[j-1];

​ //printf("%d %d\n", m, n);

​ tmpinfo[n][m] = tmpinfo[n][m]+Q/ants[i].length;

​ tmpinfo[m][n] = tmpinfo[n][m];

​ }

​ //最后城市和开始城市之间的信息素

​ n = ants[i].Path[0];

​ tmpinfo[n][m] = tmpinfo[n][m]+Q/ants[i].length;

​ tmpinfo[m][n] = tmpinfo[n][m];

​ }



​ //更新环境信息素

​ for (int i = 0; i < CITY_NUM; i++)

​ {

​ for (int j = 0; j < CITY_NUM; j++) {

​ //最新的环境信息素 = 留存的信息素 + 新留下的信息素

​ info[i][j] = info[i][j]*ROU + tmpinfo[i][j];



​ }

​ }

}

//寻找路径,迭代TMAC次

void Search()

{



​ for (int i = 0; i < TMAC; i++) {

​ printf("current iteration times %d\n", i);

​ for (int j = 0; j < ANT_NUM; j++) {

​ ants[j].Search();

​ }

​ //保存最佳结果

​ for (int j = 0; j < ANT_NUM; j++) {

​ if (ant_best.length > ants[j].length) {

​ ant_best = ants[j];

​ }

​ }



​ //更新环境信息素

​ Updateinfo();



​ printf("current minimum length %lf\n", ant_best.length);

​ }

}



};







int main()

{

//freopen("output.txt", "w", stdout);

srand(seed);

TSP tsp;

//初始化蚁群

tsp.Init();

//开始查找

tsp.Search();

puts("The Minimum length route is :\n");

for (int i = 0; i < CITY_NUM; i++) {

​ if (i != 0 && i % 20 == 0) {

​ puts("");

​ }

​ printf("%d ", tsp.ant_best.Path[i]);

}



return 0;

}

img

​ 最后得出的路径顺序为阳泉、长治、晋城、运城、临汾、太原、阳曲、大同。

3.2用MNIST数据库调试出一版识别率达到97%以上的参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
//ifndef BMP_H

\#define BMP_H

\#include <stdio.h>

\#include <stdlib.h>

\#pragma pack(1)

typedef struct tagBITMAPFILEHEADER

{

unsigned char bfType[2];//文件格式

unsigned long bfSize;//文件大小

unsigned short bfReserved1;//保留

unsigned short bfReserved2;

unsigned long bfOffBits; //DIB数据在文件中的偏移量

}fileHeader;

\#pragma pack()

/*

位图数据信息结构

*/

\#pragma pack(1)

typedef struct tagBITMAPINFOHEADER

{

unsigned long biSize;//该结构的大小

long biWidth;//文件宽度

long biHeight;//文件高度

unsigned short biPlanes;//平面数

unsigned short biBitCount;//颜色位数

unsigned long biCompression;//压缩类型

unsigned long biSizeImage;//DIB数据区大小

long biXPixPerMeter;

long biYPixPerMeter;

unsigned long biClrUsed;//多少颜色索引表

unsigned long biClrImporant;//多少重要颜色

}fileInfo;

\#pragma pack()

/*

调色板结构

*/

\#pragma pack(1)

typedef struct tagRGBQUAD

{

unsigned char rgbBlue; //蓝色分量亮度

unsigned char rgbGreen;//绿色分量亮度

unsigned char rgbRed;//红色分量亮度

unsigned char rgbReserved;

}rgbq;

\#pragma pack()



//#endif

//#include

//#include

//#include

//#include "bmp.h"



using namespace std;



\#define SUM 10000



int main()

{

int a, num, size1, size2;

//用于存储一张手写体图片的位图信息

char image[28 * 28];

//用于存储产生的图片的名字

char name[100];

//10000张测试集

FILE *fp1 = fopen("D:\学习\课程\人工智能\train-images-idx3-ubyte", "rb+");

if (fp1 == NULL)

{

​ //cout << "unable open file1" << endl;

​ //exit(1);

​ printf("unable open file2");

}





//测试集的label

FILE *fp11 = fopen("D:\学习\课程\人工智能\t10k-images-idx3-ubyte", "rb+");

if (fp1 == NULL)

{

​ printf("unable open t10k-labels.idx1-ubyte");

}

else

{

​ //读取t10k-labels.idx1-ubyte的幻数、数量

​ fread(&a, sizeof(int), 1, fp11);

​ fread(&num, sizeof(int), 1, fp11);

​ //读取t10k-labels.idx1-ubyte的前28×28个label

​ fread(image, sizeof(char), 28 * 28, fp11);

​ printf("------------------label--------------------------------");

​ printf("a=%0x\n", a);

​ printf("num=%0x\n", num);

​ for (int i = 0; i < 28 * 28; i++)

​ {

​ printf("%d\t", image[i]);

​ }

​ printf("------------------label--------------------------------");

}





//读取字符集的幻数、数量、宽、高

fread(&a, sizeof(int), 1, fp1);

fread(&num, sizeof(int), 1, fp1);

fread(&size1, sizeof(int), 1, fp1);

fread(&size2, sizeof(int), 1, fp1);





//打印字符集的幻数、数量、宽、高

printf("a=%0x\n", a);

printf("num=%0x\n", num);

printf("size1=%0x\n", size1);

printf("size2=%0x\n", size2);



for (int i = 0; i < 28 * 28; i++)

{

​ printf("%d\t", image[i]);

}





fileHeader fh;

fileInfo fi;

//编写信息头fi

fi.biSize = 40;

fi.biWidth = 28;

fi.biHeight = 28;

fi.biPlanes = 1;

fi.biBitCount = 8;

fi.biCompression = 0;

fi.biSizeImage = 28 * 28;

fi.biXPixPerMeter = 0;

fi.biYPixPerMeter = 0;

fi.biClrUsed = 0;

fi.biClrImporant = 0;



//编写文件头fh

fh.bfType[0] = 0x42;

fh.bfType[1] = 0x4D;

fh.bfOffBits = sizeof(fileHeader) + sizeof(fileInfo) + 256 * sizeof(rgbq);

fh.bfSize = fh.bfOffBits + fi.biSizeImage;

fh.bfReserved1 = 0;

fh.bfReserved2 = 0;



//创建调色板

rgbq *fq = (rgbq *)malloc(256 * sizeof(rgbq));

for (int i = 0; i<256; i++)

{

​ fq[i].rgbBlue = fq[i].rgbGreen = fq[i].rgbRed = i;

}



//创建要生成的数字图片

FILE *fp2 = fopen("C:\\Users\\RickyLove\\Desktop\\numbers", "wb");

if (fp2 == NULL)

{

​ printf("unable open file2");

}



for (int i = 1; i <= SUM; i++)

{

​ //创建一个BMP图片

​ sprintf(name, "C:\\Users\\RickyLove\\Desktop\\image\\%05d.bmp", i);

​ FILE *ftmp = fopen(name, "wb");

​ if (ftmp == NULL)

​ printf("Create %05d.bmp failure\n", i);

​ else

​ {

​ //读取一张图片的位图信息

​ fread(image, sizeof(char), 28 * 28, fp1);

​ //写文件头

​ fwrite(&fh, sizeof(fileHeader), 1, ftmp);

​ //写信息头

​ fwrite(&fi, sizeof(fileInfo), 1, ftmp);

​ //写调色板

​ fwrite(fq, sizeof(rgbq), 256, ftmp);

​ //写位图信息

​ fwrite(image, fi.biSizeImage, 1, ftmp);

​ fclose(ftmp);

​ }

}

fclose(fp1);

printf("------------------------------\n");



return 0;

}

​ 结果

img

3.3思考一下车牌号识别的代码,或者尝试安装相应框架找到相应例程实践

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
I=imread('C:\Users\yunshuni\Desktop\新建文件夹\0.jpg');  

figure(1),imshow(I);title('原始车牌');%将车牌的原图显示出来

I1=rgb2gray(I);%将彩图转换为灰度图



figure(2),subplot(1,2,1),imshow(I1);title('原始车牌'); 

figure(2),subplot(1,2,2),imhist(I1);title('灰度图直方图'); 

I2=edge(I1,'roberts',0.18,'both');%选择阈值0.18,用roberts算子进行边缘检测

figure(3),imshow(I2);title('边缘检测图像'); 

se=[1;1;1]; 

I3=imerode(I2,se);%对图像实施腐蚀操作,即膨胀的反操作

figure(4),imshow(I3);title('腐蚀后图像'); 

se=strel('rectangle',[25,25]);%构造结构元素以正方形构造一个

seI4=imclose(I3,se);% 图像聚类、填充图像

figure(5),imshow(I4);title('闭运算后图像');  

I5=bwareaopen(I4,2000);% 去除聚团灰度值小于2000的部分

figure(6),imshow(I5);title('去除后图像'); 

[y,x,z]=size(I5);%返回I5各维的尺寸,存储在x,y,z中

myI=double(I5);%将I5转换成双精度

tic      %tic表示计时的开始,

toc  %toc表示计时的结束

Blue_y=zeros(y,1);%产生一个y*1的零阵

for i=1:y 

    for j=1:x 

             if(myI(i,j,1)==1)    %如果myI(i,j,1)即myI的图像中坐标为(i,j)的点值为1,即该点为车牌背景颜色蓝色 %则Blue_y(i,1)的值加1 

      Blue_y(i,1)= Blue_y(i,1)+1;%蓝色像素点统计

            end   

     end        

 end 

 [temp MaxY]=max(Blue_y);%Y方向车牌区域确定%temp为向量yellow_y的元素中的最大值,MaxY为该值的索引

 PY1=MaxY; 

 while ((Blue_y(PY1,1)>=5)&&(PY1>1)) 

        PY1=PY1-1; 

 end     

 PY2=MaxY; 

 while ((Blue_y(PY2,1)>=5)&&(PY2<y)) 

        PY2=PY2+1; 

 end 

 IY=I(PY1:PY2,:,:); %行方向车牌区域确定

 Blue_x=zeros(1,x);%进一步确定x方向的车牌区域

 for j=1:x 

     for i=PY1:PY2 

            if(myI(i,j,1)==1) 

                Blue_x(1,j)= Blue_x(1,j)+1;                

            end   

     end        

 end 

 PX1=1; 

 while ((Blue_x(1,PX1)<3)&&(PX1<x)) 

       PX1=PX1+1; 

 end     

 PX2=x; 

 while ((Blue_x(1,PX2)<3)&&(PX2>PX1)) 

        PX2=PX2-1; 

 end 

PX1=PX1-1;%对车牌区域的校正

 PX2=PX2+1; 

  dw=I(PY1:PY2-8,PX1:PX2,:); 

 t=toc;  

figure(7),subplot(1,2,1),imshow(IY),title('车牌行方向');%行方向车牌区域确定

figure(7),subplot(1,2,2),imshow(dw),title('车牌区域');%定位后的车牌区域如下所示:

imwrite(dw,'dw.jpg');%将彩色车牌写入dw文件中

a=imread('dw.jpg');%读取车牌文件中的数据

b=rgb2gray(a);%将车牌图像转换为灰度图

figure(8);subplot(3,2,1),imshow(b),title('车牌灰度图像') 

g_max=double(max(max(b))); 

g_min=double(min(min(b))); 

T=round(g_max-(g_max-g_min)/3); % T 为二值化的阈值

[m,n]=size(b); 

d=(double(b)>=T);  % d:二值图像

subplot(3,2,2),imshow(d),title('二值化图像') %均值滤波前%滤波

h=fspecial('average',3);  %建立预定义的滤波算子,

average为均值滤波,模板的尺寸为3*3 

d=im2bw(round(filter2(h,d)));%使用指定的滤波器h对h进行d即均值滤波

subplot(3,2,3),imshow(d),title('滤波后图像') 

se=eye(2); % eye(n) returns the n-by-n identity matrix 单位矩阵

[m,n]=size(d);%返回矩阵b的尺寸信息,并存储在m,n中

if bwarea(d)/m/n>=0.365 %计算二值图像中对象的总面积与整个面积的比是否大于0.365 

    d=imerode(d,se);%如果大于0.365则图像进行腐蚀

elseif bwarea(d)/m/n<=0.235 %计算二值图像中对象的总面积与整个面积的比是否小于0.235 

    d=imdilate(d,se);%如果小于则实现膨胀操作

end 

subplot(3,2,4),imshow(d),title('膨胀或腐蚀图像'); 

d=qiege(d); 

[m,n]=size(d); 

subplot(3,2,5),imshow(d),title(n) 

k1=1;k2=1;s=sum(d);j=1; 

while j~=n 

    while s(j)==0 

        j=j+1; 

    end 

    k1=j; 

    while s(j)~=0 && j<=n-1 

        j=j+1; 

    end 

    k2=j-1; 

    if k2-k1>=round(n/6.5) 

        [val,num]=min(sum(d(:,[k1+5:k2-5]))); 

        d(:,k1+num+5)=0;  % 分割

    end 

end  % 再切割

d=qiege(d);  % 切割出 7 个字符

y1=10;y2=0.25;flag=0;word1=[]; 

while flag==0 

    [m,n]=size(d); 

    left=1;wide=0; 

    while sum(d(:,wide+1))~=0 

        wide=wide+1; 

    end 

    if wide<y1   % 认为是左侧干扰

        d(:,[1:wide])=0; 

        d=qiege(d); 

    else 

        temp=qiege(imcrop(d,[1 1 wide m])); 

        [m,n]=size(temp); 

        all=sum(sum(temp)); 

        two_thirds=sum(sum(temp([round(m/3):2*round(m/3)],:))); 

        if two_thirds/all>y2 

            flag=1;word1=temp;   % WORD 1 

        end 

        d(:,[1:wide])=0;d=qiege(d); 

    end 

end  % 分割出第二个字符

[word2,d]=getword(d); %分割出第三个字符

[word3,d]=getword(d); % 分割出第四个字符

[word4,d]=getword(d); % 分割出第五个字符

[word5,d]=getword(d); % 分割出第六个字符

[word6,d]=getword(d); % 分割出第七个字符

[word7,d]=getword(d); 

figure(9); 

subplot(2,7,1),imshow(word1),title('1'); 

subplot(2,7,2),imshow(word2),title('2'); 

subplot(2,7,3),imshow(word3),title('3'); 

subplot(2,7,4),imshow(word4),title('4'); 

subplot(2,7,5),imshow(word5),title('5'); 

subplot(2,7,6),imshow(word6),title('6'); 

subplot(2,7,7),imshow(word7),title('7'); 

[m,n]=size(word1); 

word1=imresize(word1,[40 20]); 

word2=imresize(word2,[40 20]); 

word3=imresize(word3,[40 20]); 

word4=imresize(word4,[40 20]); 

word5=imresize(word5,[40 20]); 

word6=imresize(word6,[40 20]); 

word7=imresize(word7,[40 20]); 

subplot(2,7,8),imshow(word1),title('1'); 

subplot(2,7,9),imshow(word2),title('2'); 

subplot(2,7,10),imshow(word3),title('3'); 

subplot(2,7,11),imshow(word4),title('4'); 

subplot(2,7,12),imshow(word5),title('5'); 

subplot(2,7,13),imshow(word6),title('6'); 

subplot(2,7,14),imshow(word7),title('7'); 

imwrite(word1,'1.jpg'); 

imwrite(word2,'2.jpg'); 

imwrite(word3,'3.jpg'); 

imwrite(word4,'4.jpg'); 

imwrite(word5,'5.jpg'); 

imwrite(word6,'6.jpg'); 

imwrite(word7,'7.jpg'); 

liccode=char(['0':'9' 'A':'Z' '豫渝京津冀泸']);  %建立自动识别字符代码表

SubBw2=zeros(40,20); 

l=1; 

for I=1:7 

      ii=int2str(I); 

     t=imread([ii,'.jpg']); 

      SegBw2=imresize(t,[40 20],'nearest'); 

       SegBw2=double(SegBw2)>20; 

        if l==1                 %第一位汉字识别



            kmin=37; 

            kmax=42; 

        elseif l==2             %第二位A~Z字母识别



            kmin=11; 

            kmax=36; 

        else l>=3               %第三位以后是字母或数字识别



            kmin=1; 

            kmax=36; 



        end 



        for k2=kmin:kmax 

            fname=strcat('C:\Users\yunshuni\Desktop\新建文件夹\字符模板\',liccode(k2),'.jpg'); 

            SamBw2 = imread(fname); 

            SamBw2=double(SamBw2)>1; 

            SamBw2=imresize(SamBw2,[40,20]); 

            for  i=1:40 

                for j=1:20 

                    SubBw2(i,j)=SegBw2(i,j)-SamBw2(i,j); 

                end 

            end 

           % 以上相当于两幅图相减得到第三幅图

            Dmax=0; 

            for k1=1:40 

                for l1=1:20 

                    if  ( SubBw2(k1,l1) > 0 | SubBw2(k1,l1) <0 ) 

                        Dmax=Dmax+1; 

                    end 

                end 

            end 

            Error(k2)=Dmax; 

        end 

        Error1=Error(kmin:kmax); 

        MinError=min(Error1); 

        findc=find(Error1==MinError); 

        Code(l*2-1)=liccode(findc(1)+kmin-1); 

        Code(l*2)=' '; 

        l=l+1; 

end 

figure(10),imshow(dw),title (['车牌号码:', Code],'Color','b'); 

imgimgimgimgimgimgimgimg


文章作者: RickyLove
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 RickyLove !
  目录