基于Python构建神经网络识别图片中的文字

资源下载地址:https://download.csdn.net/download/sheziqiong/88444261
资源下载地址:https://download.csdn.net/download/sheziqiong/88444261

版本说明
  • python:3.5
  • tensorflow:1.4.1
模块介绍
  • gen_captcha.py:生成图片验证码
  • word_vec.py:词向量处理
  • config.py:配置信息
  • cnn_train.py:神经网络模型训练
  • cnn_test.py:验证测试
命令
  • 训练模型

python3 cnn_train.py

  • 验证测试

python3 cnn_test.py

1. 引言

最近,社区已经看到神经网络的强大复兴,这主要受到深度神经网络模型,特别是深度卷积神经网络(DCNN)在各种视觉任务中的巨大成功的推动。然而,最近大多数与深度神经网络相关的工作主要致力于检测或分类对象类别。在本文中,我们关注计算机视觉中的一个经典问题:基于图像的序列识别。在现实世界中,稳定的视觉对象,如场景文字,手写字符和乐谱,往往以序列的形式出现,而不是孤立地出现。与一般的对象识别不同,识别这样的类序列对象通常需要系统预测一系列对象标签,而不是单个标签。因此,可以自然地将这样的对象的识别作为序列识别问题。类序列对象的另一个独特之处在于它们的长度可能会有很大变化。例如,英文单词可以由 2 个字符组成,如“OK”,或由 15 个字符组成,如“congratulations”。因此,最流行的深度模型像 DCNN 不能直接应用于序列预测,因为 DCNN 模型通常对具有固定维度的输入和输出进行操作,因此不能产生可变长度的标签序列。

已经针对特定的类似序列的对象(例如场景文本)进行了一些尝试来解决该问题。。这些方法通常需要训练强字符检测器,以便从原始单词图像中准确地检测和裁剪每个字符。一些其他方法将场景文本识别视为图像分类问题,并为每个英文单词(总共 9 万个词)分配一个类标签。结果是一个大的训练模型中有很多类,这很难泛化到其它类型的类序列对象,如中文文本,音乐配乐等,因为这种序列的基本组合数目可能大于 100 万。总之,目前基于 DCNN 的系统不能直接用于基于图像的序列识别。

循环神经网络(RNN)模型是深度神经网络家族中的另一个重要分支,主要是设计来处理序列。RNN 的优点之一是在训练和测试中不需要序列目标图像中每个元素的位置。然而,将输入目标图像转换成图像特征序列的预处理步骤通常是必需的。例如,Graves 等从手写文本中提取一系列几何或图像特征,而 Su 和 Lu 将字符图像转换为序列 HOG 特征。预处理步骤独立于流程中的后续组件,因此基于 RNN 的现有系统不能以端到端的方式进行训练和优化。

一些不是基于神经网络的传统场景文本识别方法也为这一领域带来了有见地的想法和新颖的表现。例如,Almaza`n 等人和 Rodriguez-Serrano 等人提出将单词图像和文本字符串嵌入到公共向量子空间中,并将词识别转换为检索问题。Yao 等人和 Gordo 等人使用中层特征进行场景文本识别。虽然在标准基准数据集上取得了有效的性能,但是前面的基于神经网络的算法以及本文提出的方法通常都优于这些方法。

本文的主要贡献是一种新颖的神经网络模型,其网络架构设计专门用于识别图像中的类序列对象。所提出的神经网络模型被称为卷积循环神经网络(CRNN),因为它是 DCNN 和 RNN 的组合。对于类序列对象,CRNN 与传统神经网络模型相比具有一些独特的优点:

  • 可以直接从序列标签(例如单词)学习,不需要详细的标注(例如字符);
  • 直接从图像数据学习信息表示时具有与 DCNN 相同的性质,既不需要手工特征也不需要预处理步骤,包括二值化/分割,组件定位等;
  • 具有与 RNN 相同的性质,能够产生一系列标签;
  • 对类序列对象的长度无约束,只需要在训练阶段和测试阶段对高度进行归一化;
  • 与现有技术相比,它在场景文本(字识别)上获得更好或更具竞争力的表现。
  • 它比标准 DCNN 模型包含的参数要少得多,占用更少的存储空间。

2. 提出的网络架构

如图 1 所示,CRNN 的网络架构由三部分组成,包括卷积层,循环层和转录层,从底向上。

Figure 1

图 1。网络架构。架构包括三部分:1) 卷积层,从输入图像中提取特征序列;2) 循环层,预测每一帧的标签分布;3) 转录层,将每一帧的预测变为最终的标签序列。

在 CRNN 的底部,卷积层自动从每个输入图像中提取特征序列。在卷积网络之上,构建了一个循环网络,用于对卷积层输出的特征序列的每一帧进行预测。采用 CRNN 顶部的转录层将循环层的每帧预测转化为标签序列。虽然 CRNN 由不同类型的网络架构(如 CNN 和 RNN)组成,但可以通过一个损失函数进行联合训练。

2.1. 特征序列提取

在 CRNN 模型中,通过采用标准 CNN 模型(去除全连接层)中的卷积层和最大池化层来构造卷积层的组件。这样的组件用于从输入图像中提取序列特征表示。在进入网络之前,所有的图像需要缩放到相同的高度。然后从卷积层组件产生的特征图中提取特征向量序列,这些特征向量序列作为循环层的输入。具体地,特征序列的每一个特征向量在特征图上按列从左到右生成。这意味着第 i 个特征向量是所有特征图第 i 列的连接。在我们的设置中每列的宽度固定为单个像素。

由于卷积层,最大池化层和元素激活函数在局部区域上执行,因此它们是平移不变的。因此,特征图的每列对应于原始图像的一个矩形区域(称为感受野),并且这些矩形区域与特征图上从左到右的相应列具有相同的顺序。如图 2 所示,特征序列中的每个向量关联一个感受野,并且可以被认为是该区域的图像描述符。

Figure 2

图 2。感受野。提取的特征序列中的每一个向量关联输入图像的一个感受野,可认为是该区域的特征向量。

2.2. 序列标注

一个深度双向循环神经网络是建立在卷积层的顶部,作为循环层。循环层预测特征序列 x = x 1 , . . . , x T x = x_1,...,x_T x=x1,...,xT中每一帧 x t x_t xt的标签分布 y t y_t yt。循环层的优点是三重的。首先,RNN 具有很强的捕获序列内上下文信息的能力。对于基于图像的序列识别使用上下文提示比独立处理每个符号更稳定且更有帮助。以场景文本识别为例,宽字符可能需要一些连续的帧来完全描述(参见图 2)。此外,一些模糊的字符在观察其上下文时更容易区分,例如,通过对比字符高度更容易识别“il”而不是分别识别它们中的每一个。其次,RNN 可以将误差差值反向传播到其输入,即卷积层,从而允许我们在统一的网络中共同训练循环层和卷积层。第三,RNN 能够从头到尾对任意长度的序列进行操作。

传统的 RNN 单元在其输入和输出层之间具有自连接的隐藏层。每次接收到序列中的帧 x t x_t xt时,它将使用非线性函数来更新其内部状态 h t h_t ht,该非线性函数同时接收当前输入 x t x_t xt和过去状态 h t 1 h_{t1} ht1作为其输入: h t = g ( x t , h t 1 ) h_t = g(x_t, h_{t1}) ht=g(xt,ht1)。那么预测 y t y_t yt是基于 h t h_t ht的。以这种方式,过去的上下文{ { x t ′ } t ′ < t \lbrace x_{t\prime} \rbrace _{t \prime < t} {xt}t<t被捕获并用于预测。然而,传统的 RNN 单元有梯度消失的问题[7],这限制了其可以存储的上下文范围,并给训练过程增加了负担。长短时记忆[18,11](LSTM)是一种专门设计用于解决这个问题的 RNN 单元。LSTM(图 3 所示)由一个存储单元和三个多重门组成,即输入,输出和遗忘门。在概念上,存储单元存储过去的上下文,并且输入和输出门允许单元长时间地存储上下文。同时,单元中的存储可以被遗忘门清除。LSTM 的特殊设计允许它捕获长距离依赖,这经常发生在基于图像的序列中。

Figure 3

图 3。(a) 基本的 LSTM 单元的结构。LSTM 包括单元模块和三个门,即输入门,输出门和遗忘门。(b)我们论文中使用的深度双向 LSTM 结构。合并前向(从左到右)和后向(从右到左)LSTM 的结果到双向 LSTM 中。在深度双向 LSTM 中堆叠多个双向 LSTM 结果。

LSTM 是定向的,它只使用过去的上下文。然而,在基于图像的序列中,两个方向的上下文是相互有用且互补的。因此,我们遵循[17],将两个 LSTM,一个向前和一个向后组合到一个双向 LSTM 中。此外,可以堆叠多个双向 LSTM,得到如图 3.b 所示的深双向 LSTM。深层结构允许比浅层抽象更高层次的抽象,并且在语音识别任务中取得了显著的性能改进[17]。

在循环层中,误差在图 3.b 所示箭头的相反方向传播,即反向传播时间(BPTT)。在循环层的底部,传播差异的序列被连接成映射,将特征映射转换为特征序列的操作进行反转并反馈到卷积层。实际上,我们创建一个称为“Map-to-Sequence”的自定义网络层,作为卷积层和循环层之间的桥梁。

2.3. 转录

转录是将 RNN 所做的每帧预测转换成标签序列的过程。数学上,转录是根据每帧预测找到具有最高概率的标签序列。在实践中,存在两种转录模式,即无词典转录和基于词典的转录。词典是一组标签序列,预测受拼写检查字典约束。在无词典模式中,预测时没有任何词典。在基于词典的模式中,通过选择具有最高概率的标签序列进行预测。

2.3.1 标签序列的概率

我们采用 Graves 等人[15]提出的联接时间分类(CTC)层中定义的条件概率。按照每帧预测 y = y 1 , . . . , y T y=y_1,...,y_T y=y1,...,yT对标签序列 l l l定义概率,并忽略 l l l中每个标签所在的位置。因此,当我们使用这种概率的负对数似然作为训练网络的目标函数时,我们只需要图像及其相应的标签序列,避免了标注单个字符位置的劳动。

条件概率的公式简要描述如下:输入是序列 y = y 1 , . . . , y T y = y_1,...,y_T y=y1,...,yT,其中 T T T是序列长度。这里,每个 y t ∈ ℜ ∣ L ′ ∣ y_t \in\Re^{|{\cal L}'|} ytL是在集合 L ′ = L ∪ {\cal L}' = {\cal L} \cup L=L上的概率分布,其中 L {\cal L} L包含了任务中的所有标签(例如,所有英文字符),以及由 - 表示的“空白”标签。序列到序列的映射函数 B {\cal B} B定义在序列 π ∈ L ′ T \boldsymbol{\pi}\in{\cal L}'^{T} πLT上,其中 T T T是长度。 B {\cal B} B π \boldsymbol{\pi} π映射到 l \mathbf{l} l上,首先删除重复的标签,然后删除 blank。例如, B {\cal B} B将“–hh-e-l-ll-oo–”(- 表示 blank)映射到“hello”。然后,条件概率被定义为由 B {\cal B} B映射到 l \mathbf{l} l上的所有 π \boldsymbol{\pi} π的概率之和:

p ( l ∣ y ) = ∑ π : B ( π ) = l p ( π ∣ y ) , \begin{equation} p(\mathbf{l}|\mathbf{y})=\sum_{\boldsymbol{\pi}:{\cal B}(\boldsymbol{\pi})=\mathbf{l}}p(\boldsymbol{\pi}|\mathbf{y}),\tag{1} \end{equation} p(ly)=π:B(π)=lp(πy),(1)

π \boldsymbol{\pi} π的概率定义为 p ( π ∣ y ) = ∏ t = 1 T y π t t p(\boldsymbol{\pi}|\mathbf{y})=\prod_{t=1}{T}y_{\pi_{t}}{t} p(πy)=t=1Tyπtt y π t t y_{\pi_{t}}^{t} yπtt是时刻 t t t时有标签 π t \pi_{t} πt的概率。由于存在指数级数量的求和项,直接计算方程 1 在计算上是不可行的。然而,使用[15]中描述的前向算法可以有效计算方程 1。

2.3.2 无字典转录

在这种模式下,将具有方程 1 中定义的最高概率的序列 l ∗ \mathbf{l}{*} l作为预测。由于不存在用于精确找到解的可行方法,我们采用[15]中的策略。序列 l ∗ \mathbf{l}{*} l通过 l ∗ ≈ B ( arg ⁡ max ⁡ π p ( π ∣ y ) ) \mathbf{l}^{*}\approx{\cal B}(\arg\max_{\boldsymbol{\pi}}p(\boldsymbol{\pi}|\mathbf{y})) lB(argmaxπp(πy))近似发现,即在每个时间戳 t t t采用最大概率的标签 π t \pi_{t} πt,并将结果序列映射到 l ∗ \mathbf{l}^{*} l

2.3.3 基于词典的转录

在基于字典的模式中,每个测试采样与词典 D {\cal D} D相关联。基本上,通过选择词典中具有方程 1 中定义的最高条件概率的序列来识别标签序列,即 l ∗ = arg ⁡ max ⁡ l ∈ D p ( l ∣ y ) \mathbf{l}^{*}=\arg\max_{\mathbf{l}\in{\cal D}}p(\mathbf{l}|\mathbf{y}) l=argmaxlDp(ly)。然而,对于大型词典,例如 5 万个词的 Hunspell 拼写检查词典[1],对词典进行详尽的搜索是非常耗时的,即对词典中的所有序列计算方程 1,并选择概率最高的一个。为了解决这个问题,我们观察到,2.3.2 中描述的通过无词典转录预测的标签序列通常在编辑距离度量下接近于实际结果。这表示我们可以将搜索限制在最近邻候选目标 N δ ( l ′ ) {\cal N}_{\delta}(\mathbf{l}') Nδ(l),其中 δ \delta δ是最大编辑距离, l ′ \mathbf{l}' l是在无词典模式下从 y \mathbf{y} y转录的序列:

l ∗ = arg ⁡ max ⁡ l ∈ N δ ( l ′ ) p ( l ∣ y ) . \begin{equation} \mathbf{l}^{*}=\arg\max_{\mathbf{l}\in{\cal N}_{\delta}(\mathbf{l}')}p(\mathbf{l}|\mathbf{y}).\tag{2} \end{equation} l=arglNδ(l)maxp(ly).(2)

可以使用 BK 树数据结构[9]有效地找到候选目标 N δ ( l ′ ) {\cal N}_{\delta}(\mathbf{l}') Nδ(l),这是一种专门适用于离散度量空间的度量树。BK 树的搜索时间复杂度为 O ( log ⁡ ∣ D ∣ ) O(\log|{\cal D}|) O(logD),其中 ∣ D ∣ |{\cal D}| D是词典大小。因此,这个方案很容易扩展到非常大的词典。在我们的方法中,一个词典离线构造一个 BK 树。然后,我们使用树执行快速在线搜索,通过查找具有小于或等于 δ \delta δ编辑距离来查询序列。

2.4. 网络训练

${\cal X}= \lbrace I_i,\mathbf{l}i \rbrace i 表示训练集, 表示训练集, 表示训练集,I{i} 是训练图像, 是训练图像, 是训练图像,\mathbf{l}{i}$是真实的标签序列。目标是最小化真实条件概率的负对数似然:

O = − ∑ I i , l i ∈ X log ⁡ p ( l i ∣ y i ) , \begin{equation} {\cal O}=-\sum_{I_{i},\mathbf{l}_{i}\in{\cal X}}\log p(\mathbf{l}_{i}|\mathbf{y}_{i}),\tag{3} \end{equation} O=Ii,liXlogp(liyi),(3)

y i \mathbf{y}_{i} yi是循环层和卷积层从 I i I_{i} Ii生成的序列。目标函数直接从图像和它的真实标签序列计算代价值。因此,网络可以在成对的图像和序列上进行端对端训练,去除了在训练图像中手动标记所有单独组件的过程。

网络使用随机梯度下降(SGD)进行训练。梯度由反向传播算法计算。特别地,在转录层中,如[15]所述,误差使用前向算法进行反向传播。在循环层中,应用随时间反向传播(BPTT)来计算误差。

为了优化,我们使用 ADADELTA[37]自动计算每维的学习率。与传统的动量[31]方法相比,ADADELTA 不需要手动设置学习率。更重要的是,我们发现使用 ADADELTA 的优化收敛速度比动量方法快。

3. 实验

为了评估提出的 CRNN 模型的有效性,我们在场景文本识别和乐谱识别的标准基准数据集上进行了实验,这些都是具有挑战性的视觉任务。数据集和训练测试的设置见 3.1 小节,场景文本图像中 CRNN 的详细设置见 3.2 小节,综合比较的结果在 3.3 小节报告。为了进一步证明 CRNN 的泛化性,在 3.4 小节我们在乐谱识别任务上验证了提出的算法。

3.1. 数据集

对于场景文本识别的所有实验,我们使用 Jaderberg 等人[20]发布的合成数据集(Synth)作为训练数据。数据集包含 8 百万训练图像及其对应的实际单词。这样的图像由合成文本引擎生成并且是非常现实的。我们的网络在合成数据上进行了一次训练,并在所有其它现实世界的测试数据集上进行了测试,而没有在其训练数据上进行任何微调。即使 CRNN 模型是在纯合成文本数据上训练,但它在标准文本识别基准数据集的真实图像上工作良好。

有四个流行的基准数据集用于场景文本识别的性能评估,即 ICDAR 2003(IC03),ICDAR 2013(IC13),IIIT 5k-word(IIIT5k)和 Street View Text (SVT)。

IC03[27]测试数据集包含 251 个具有标记文本边界框的场景图像。王等人[34],我们忽略包含非字母数字字符或少于三个字符的图像,并获得具有 860 个裁剪的文本图像的测试集。每张测试图像与由 Wang 等人[34]定义的 50 词的词典相关联。通过组合所有的每张图像词汇构建完整的词典。此外,我们使用由 Hunspell 拼写检查字典[1]中的单词组成的 5 万个词的词典。

IC13[24]测试数据集继承了 IC03 中的大部分数据。它包含 1015 个实际的裁剪单词图像。

IIIT5k[28]包含从互联网收集的 3000 张裁剪的词测试图像。每张图像关联一个 50 词的词典和一个 1000 词的词典。

SVT[34]测试数据集由从 Google 街景视图收集的 249 张街景图像组成。从它们中裁剪出了 647 张词图像。每张单词图像都有一个由 Wang 等人[34]定义的 50 个词的词典。

3.2. 实现细节

在实验中我们使用的网络配置总结在表 1 中。卷积层的架构是基于 VGG-VeryDeep 的架构[32]。为了使其适用于识别英文文本,对其进行了调整。在第 3 和第 4 个最大池化层中,我们采用 1×2 大小的矩形池化窗口而不是传统的平方形。这种调整产生宽度较大的特征图,因此具有更长的特征序列。例如,包含 10 个字符的图像通常为大小为 100×32,可以从其生成 25 帧的特征序列。这个长度超过了大多数英文单词的长度。最重要的是,矩形池窗口产生矩形感受野(如图 2 所示),这有助于识别一些具有窄形状的字符,例如 il

表 1。网络配置总结。第一行是顶层。ksp 分别表示核大小,步长和填充大小。

Table 1

网络不仅有深度卷积层,而且还有循环层。众所周知两者都难以训练。我们发现批归一化[19]技术对于训练这种深度网络非常有用。分别在第 5 和第 6 卷积层之后插入两个批归一化层。使用批归一化层训练过程大大加快。

我们在 Torch7[10]框架内实现了网络,使用定制实现的 LSTM 单元(Torch7/CUDA),转录层(C++)和 BK 树数据结构(C++)。实验在具有 2.50 GHz Intel(R)Xeon E5-2609 CPU,64GB RAM 和 NVIDIA(R)Tesla™ K40 GPU 的工作站上进行。网络用 ADADELTA 训练,将参数 ρ 设置为 0.9。在训练期间,所有图像都被缩放为 100×32,以加快训练过程。训练过程大约需要 50 个小时才能达到收敛。测试图像缩放的高度为 32。宽度与高度成比例地缩放,但至少为 100 像素。平均测试时间为 0.16s/样本,在 IC03 上测得的,没有词典。近似词典搜索应用于 IC03 的 50k 词典,参数 δ 设置为 3。测试每个样本平均花费 0.53s。

3.3. 比较评估

提出的 CRNN 模型在上述四个公共数据集上获得的所有识别精度以及最近的最新技术,包括基于深度模型[23,22,21]的方法如表 2 所示。

表 2。四个数据集上识别准确率(%)。在第二行,“50”,“1k”,“50k”和“Full”表示使用的字典,“None”表示识别没有字典。*[22]严格意义上讲不是无字典的,因为它的输出限制在 90K 的字典。

Table 2

在有约束词典的情况中,我们的方法始终优于大多数最新的方法,并且平均打败了[22]中提出的最佳文本阅读器。具体来说,与[22]相比,我们在 IIIT5k 和 SVT 上获得了卓越的性能,仅在 IC03 上通过“Full”词典实现了较低性能。请注意,[22]中的模型是在特定字典上训练的,即每个单词都与一个类标签相关联。与[22]不同,CRNN 不限于识别已知字典中的单词,并且能够处理随机字符串(例如电话号码),句子或其他诸如中文单词的脚本。 因此,CRNN 的结果在所有测试数据集上都具有竞争力。

在无约束词典的情况下,我们的方法在 SVT 上仍取得了最佳性能,但在 IC03 和 IC13 上仍然落后于一些方法[8,22]。注意,表 2 的“none”列中的空白表示这种方法不能应用于没有词典的识别,或者在无约束的情况下不能报告识别精度。我们的方法只使用具有单词级标签的合成文本作为训练数据,与 PhotoOCR[8]非常不同,后者使用 790 万个具有字符级标注的真实单词图像进行训练。[22]中报告的最佳性能是在无约束词典的情况下,受益于它的大字典,然而,它不是前面提到的严格的无约束词典模型。在这个意义上,我们在无限制词典表中的结果仍然是有前途的。

为了进一步了解与其它文本识别方法相比,所提出算法的优点,我们提供了在一些特性上的综合比较,这些特性名称为 E2E Train,Conv Ftrs,CharGT-Free,Unconstrained 和 Model Size,如表 3 所示。

表 3。各种方法的对比。比较的属性包括:1)端到端训练(E2E Train);2)从图像中直接学习卷积特征而不是使用手动设计的特征(Conv Ftrs);3)训练期间不需要字符的实际边界框(CharGT-Free);4)不受限于预定义字典(Unconstrained);5)模型大小(如果使用端到端模型),通过模型参数数量来衡量(Model Size, M 表示百万)。

Table 3

E2E Train:这一列是为了显示某种文字阅读模型是否可以进行端到端的训练,无需任何预处理或经过几个分离的步骤,这表明这种方法对于训练是优雅且干净的。从表 3 可以看出,只有基于深度神经网络的模型,包括[22,21]以及 CRNN 具有这种性质。

Conv Ftrs:这一列表明一个方法是否使用从训练图像直接学习到的卷积特征或手动特征作为基本的表示。

CharGT-Free:这一列用来表明字符级标注对于训练模型是否是必要的。由于 CRNN 的输入和输出标签是序列,因此字符级标注是不必要的。

Unconstrained:这一列用来表明训练模型是否受限于一个特定的字典,是否不能处理字典之外的单词或随机序列。注意尽管最近通过标签嵌入[5, 14]和增强学习[22]学习到的模型取得了非常有竞争力的性能,但它们受限于一个特定的字典。

Model Size:这一列报告了学习模型的存储空间。在 CRNN 中,所有的层有权重共享连接,不需要全连接层。因此,CRNN 的参数数量远小于 CNN 变体[22,21]所得到的模型,导致与[22,21]相比,模型要小得多。我们的模型有 830 万个参数,只有 33MB RAM(每个参数使用 4 字节单精度浮点数),因此可以轻松地移植到移动设备上。

表 3 详细列出了不同方法之间的差异,充分展示了 CRNN 与其它竞争方法的优势。

另外,为了测试参数 δ \delta δ的影响,我们在方程 2 中实验了 δ \delta δ的不同值。在图 4 中,我们将识别精度绘制为 δ \delta δ的函数。更大的 δ \delta δ导致更多的候选目标,从而基于词典的转录更准确。另一方面,由于更长的 BK 树搜索时间,以及更大数量的候选序列用于测试,计算成本随着 δ \delta δ的增大而增加。实际上,我们选择 δ = 3 \delta=3 δ=3作为精度和速度之间的折衷。

Figure 4

图 4。蓝线图:识别准确率作为 δ \delta δ的函数。红条:每个样本的词典搜索时间。在 IC03 数据集上使用 50k 词典进行的测试。

3.4. 乐谱识别

乐谱通常由排列在五线谱的音符序列组成。识别图像中的乐谱被称为光学音乐识别(OMR)问题。以前的方法通常需要图像预处理(主要是二值化),五线谱检测和单个音符识别[29]。我们将 OMR 作为序列识别问题,直接用 CRNN 从图像中预测音符的序列。为了简单起见,我们仅认识音调,忽略所有和弦,并假定所有乐谱具有相同的大调音阶(C 大调)。

据我们所知,没有用于评估音调识别算法的公共数据集。为了准备 CRNN 所需的训练数据,我们从[2]中收集了 2650 张图像。每个图像中有一个包含 3 到 20 个音符的乐谱片段。我们手动标记所有图像的真实标签序列(不是的音调序列)。收集到的图像通过旋转,缩放和用噪声损坏增强到了 265k 个训练样本,并用自然图像替换它们的背景。对于测试,我们创建了三个数据集:1)“纯净的”,其中包含从[2]收集的 260 张图像。实例如图 5.a 所示;2)“合成的”,使用“纯净的”创建的,使用了上述的增强策略。它包含 200 个样本,其中一些如图 5.b 所示;3)“现实世界”,其中包含用手机相机拍摄的音乐书籍中的 200 张图像。例子如图 5.c 所示。

Figure 5

图 5。(a)从[2]中收集的干净的乐谱图像。(b)合成的乐谱图像。©用手机相机拍摄的现实世界的乐谱图像。

由于我们的训练数据有限,因此我们使用简化的 CRNN 配置来减少模型容量。与表 1 中指定的配置不同,我们移除了第 4 和第 6 卷积层,将 2 层双向 LSTM 替换为 2 层单向 LSTM。网络对图像对和对应的标签序列进行训练。使用两种方法来评估识别性能:1)片段准确度,即正确识别的乐谱片段的百分比;2)平均编辑距离,即预测音调序列与真实值之间的平均编辑距离。为了比较,我们评估了两种商用 OMR 引擎,即 Capella Scan[3]和 PhotoScore[4]。

表 4 总结了结果。CRNN 大大优于两个商业系统。Capella Scan 和 PhotoScore 系统在干净的数据集上表现相当不错,但是它们的性能在合成和现实世界数据方面显著下降。主要原因是它们依赖于强大的二值化来检五线谱和音符,但是由于光线不良,噪音破坏和杂乱的背景,二值化步骤经常会在合成数据和现实数据上失败。另一方面,CRNN 使用对噪声和扭曲具有鲁棒性的卷积特征。此外,CRNN 中的循环层可以利用乐谱中的上下文信息。每个音符不仅自身被识别,而且被附近的音符识别。因此,通过将一些音符与附近的音符进行比较可以识别它们,例如对比他们的垂直位置。

Table 4

表 4。在我们收集的数据集上,CRNN 和两个商业 OMR 系统对音调识别准确率的对比。通过片段准确率和平均编辑距离(“片段准确率/平均编辑距离”)来评估性能。

结果显示了 CRNN 的泛化性,因为它可以很容易地应用于其它的基于图像的序列识别问题,需要极少的领域知识。与 Capella Scan 和 PhotoScore 相比,我们的基于 CRNN 的系统仍然是初步的,并且缺少许多功能。但它为 OMR 提供了一个新的方案,并且在音高识别方面表现出有前途的能力。

资源下载地址:https://download.csdn.net/download/sheziqiong/88444261
资源下载地址:https://download.csdn.net/download/sheziqiong/88444261

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是基于BP神经网络图片验证码识别Python代码: 首先,我们需要导入相关的库: ```python import numpy as np import matplotlib.pyplot as plt from PIL import Image ``` 接着,我们需要准备训练数据。假设我们有一个包含100个验证码图片的数据集,每个验证码有5个字符,每个字符大小为30x30像素。我们可以将每个字符转换成一个长度为900的向量,然后将5个字符的向量合并成一个长度为4500的向量。将这些向量保存到一个numpy数组,作为训练数据。 ```python # 加载训练数据 X_train = [] y_train = [] for i in range(100): for j in range(5): im = Image.open(f"captcha_{i}_{j}.png") # 加载验证码图片 im = im.convert("L") # 转换为灰度图 im = im.resize((30, 30)) # 缩放为30x30像素 X_train.append(np.array(im).flatten()) # 将字符转换成向量并加入训练数据 y_train.append(i) # 记录验证码的序号 X_train = np.array(X_train) y_train = np.array(y_train) ``` 接着,我们需要对训练数据进行预处理。将像素值归一化到0到1之间,并对标签进行one-hot编码。 ```python # 对训练数据进行预处理 X_train = X_train / 255.0 y_train_onehot = np.zeros((len(y_train), 100)) y_train_onehot[np.arange(len(y_train)), y_train] = 1 ``` 接下来,我们可以构建BP神经网络模型。这里我们使用一个包含一个隐藏层的神经网络,隐藏层的大小为100。输入层大小为4500,输出层大小为100,代表100个不同的验证码。 ```python # 构建BP神经网络模型 class NeuralNetwork: def __init__(self, input_size, hidden_size, output_size): self.W1 = np.random.randn(input_size, hidden_size) * 0.01 self.b1 = np.zeros((1, hidden_size)) self.W2 = np.random.randn(hidden_size, output_size) * 0.01 self.b2 = np.zeros((1, output_size)) def forward(self, X): self.z1 = np.dot(X, self.W1) + self.b1 self.a1 = np.tanh(self.z1) self.z2 = np.dot(self.a1, self.W2) + self.b2 exp_scores = np.exp(self.z2) self.probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True) return self.probs def backward(self, X, y, learning_rate): delta3 = self.probs delta3[range(len(X)), y] -= 1 dW2 = np.dot(self.a1.T, delta3) db2 = np.sum(delta3, axis=0, keepdims=True) delta2 = np.dot(delta3, self.W2.T) * (1 - np.power(self.a1, 2)) dW1 = np.dot(X.T, delta2) db1 = np.sum(delta2, axis=0) self.W1 -= learning_rate * dW1 self.b1 -= learning_rate * db1 self.W2 -= learning_rate * dW2 self.b2 -= learning_rate * db2 def train(self, X, y, learning_rate, num_passes): for i in range(num_passes): probs = self.forward(X) self.backward(X, y, learning_rate) if i % 10 == 0: loss = self.calculate_loss(X, y) print(f"iteration {i}: loss = {loss}") def calculate_loss(self, X, y): num_examples = len(X) correct_logprobs = -np.log(self.probs[range(num_examples), y]) data_loss = np.sum(correct_logprobs) return 1.0 / num_examples * data_loss nn = NeuralNetwork(4500, 100, 100) nn.train(X_train, y_train, 0.01, 1000) ``` 最后,我们可以使用训练好的模型对新的验证码进行识别。首先需要将验证码转换成向量,然后使用训练好的神经网络模型进行预测。 ```python # 加载测试数据 im = Image.open("test_captcha.png") im = im.convert("L") im = im.resize((30, 150)) X_test = np.array(im).reshape(5, 30*30) # 对测试数据进行预处理 X_test = X_test / 255.0 # 使用训练好的模型进行预测 y_test_prob = nn.forward(X_test) y_test = np.argmax(y_test_prob, axis=1) # 输出预测结果 print("Predicted labels:") print(y_test) ``` 以上就是基于BP神经网络图片验证码识别Python代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值