system: [SYSTEM]

user: 2. 水表数字识别的实现 本文提出的水表数字自动识别方法包括原始水表图像预处理、卷积神经网络的训练和结果预测，其中数据预处理操作又包括定位、切割单个字符、通过椒盐噪声、旋转扩增数据集、灰度化、滤波以及局部阈值分割等，水表数字识别流程图如图1所示。 图1. 水表数字识别流程图 2.1. 定位切割 对于原始的水表图像，如图2所示，首先需要定位分割出读数区域，然后将五位的读数切割为单个的字符，以便后续的预处理。 图2. 原始水表图像 本文中每一张原始水表图像都有对应的文本标签，文本标签中给出了该张图片中数字矩形区域的四个顶点坐标以及读数，因此可根据所给的坐标定位分割出数字区域。由于真实场景下拍摄方式、角度等因素的影响，图像可能存在倾斜，读数不在一条水平线上的问题，所以在进行分割之前要先对图像进行矫正，使其旋转一定的角度后，读数区域可水平放置。这一过程可通过比较左上角和右上角的横坐标，计算得到所需旋转的角度，再进行定位分割，从而获取水平放置的读数区域。根据读数区域是规则的矩形的特性，对读数区域进行五等分便可以得到单个字符的图像。部分数据集如图3所示。 图3. 部分数据集 2.2. 数据集扩增 深度学习要以大量数据为基础条件，因所获取的数据大多为清晰规则的，较为单一，使用该数据集训练得到的模型识别较为复杂的图像时准确率会下降，因此扩增数据集，使训练集丰富多样是很有必要的。本文采用增加椒盐噪声以及旋转一定的角度来丰富扩增数据，以提高模型识别模糊或倾斜图像时的准确率。 椒盐噪声(salt-and-paper noise)也称为脉冲噪声，是由图像传感器、传输信道、解码处理等产生的黑白相间的亮暗点噪声，往往是由图像切割引起的。增加椒盐噪声算法伪代码如表1所示，增加前后的效果图如图4所示。 图4. 增加椒盐噪声效果图 Table 1 Add pepper and salt noise algorithm pseudocod 算法1：增加椒盐噪声 其中image为数据集中的图像；prob为噪声比例；result为增加椒盐噪声后的图像 Input:image，prob; Output:result; for i in range (image.shape[ 0 ]) for j in range(image.shapr[ 1 ]) rdn=random.random() if rdn < prob 将该像素点添加黑点，即椒噪声 elif rdn > 1-prob 将该像素点添加白点，即盐噪声 else像素点不变 end if end for end for 表1. 增加椒盐噪声算法伪代码 2.3. 灰度化 图像灰度化是指图像中的每一像素点的分量都满足R = G = B = V的关系，此时的V称为是灰度值，灰度图像即指含有亮度信息、不含彩色信息的图像。真实场景下所拍摄的图像均为彩色的，处理三个通道的数据比较复杂，因此可先将图像进行灰度化处理，将每个像素点的RGB值统一为同一个值，灰度化后的图像将由三通道变为单通道，单通道的数据处理相比较起来会简单许多。灰度化处理前后效果图如图5所示。 图5. 灰度化效果图 2.4. 滤波 中值滤波器是一种非线性滤波器，在输入的图像x(n1， n2)中，以任一像素为中心设置一个确定的领域A，A的边长为2N + 1， ( N = 0 ， 1 ， 2 ， ⋯ )，将领域内各像素的强度值按照大小顺序进行排列，取中值作为该像素点的输出值，遍历整张图像便可以完成滤波的操作。图像在传输的过程中，主要由于传输信道的干扰而容易受到噪声的污染，本文在加噪过程中使用的是椒盐噪声，同时在图像进行分割时也容易产生椒盐噪声，因椒盐噪声值为255或0，它散布在领域中，不是最大值便是最小值，不可能成为中值，因此选用中值滤波的方法来进行去噪，效果良好。 2.5. 局部阈值分割 通过观察数据集可以发现，在真实场景下拍摄的水表图像，由于存在拍摄角度、光照等的影响，图像的灰度可能是不均匀分布的，本文采用局部阈值分割 [ 15 ] 的方法，根据图像不同区域的亮度分布，计算其局部阈值，从而减少了光照不均匀等因素给实验带来的影响。 2.6. LeNet网络模型的搭建 本文采用的方法是基于LeNet网络模型，进行了部分的改进，它是一个相对较小的卷积神经网络，由3个卷积层(convolution， Conv)、2个池化层(Pooling)、1个全连接层(fullconnected， FC)和1个输出层(Output)构成，其网络架构如图6所示。 本文的网络结构在原始的LeNet模型上进行了改进，输入的图片大小为28 * 28，其中卷积层卷积核的大小为3 * 3，卷积步长为1，使获取的图像中原始信号增强，降低噪音；池化层池化核大小为2 * 2，有效降低网络训练参数及模型过拟合程度。 1) 输入图像：卷积神经网络的输入图像为1个大小为28 * 28的图像。 2) 卷积层(Conv)：输入图像和1个大小为3 * 3的卷积核进行卷积计算，输出处理之后的特征图。卷积计算公式为： 图6. LeNet网络架构 x i j = f ( w i j × x i − 1 + b i j ) (1) f ( x ) = 1 1 + e − x (2) 式中， x i − 1 表示上层特征图； x i j 表示卷积核j对应输出的特征图； w i j 表示第j个卷积核的权重参数，即上一层第i个特征图与该层第j个特征图之间进行卷积操作 [ 16 ]； b i j 表示偏置值； f ( x ) 表示激活函数。 3) 池化层(Pooling)：在卷积层之后引入池化层，对特征图像进行过滤、降维，实现缩减特征图的尺寸 [ 17 ]，防止数据过于庞大，提高运算效率。使用2 * 2大小的池化核对每个特征图进行处理。池化计算公式如下： x i j = P o o l i n g ( x i − 1 ) (3) 式中， x i − 1 表示上层特征图； x i j 表示经池化后对应输出的特征图； P o o l i n g ( x ) 表示池化函数。 4) 全连接层(FC)：该层对提取到的特征进行非线性组合，整合所有的局部特征信息，将之前的特征图像相连接。 5) 输出层(Output)：输出不同类别的概率值，本文需识别0~9共10个数字，因此设置10个类别，概率值最大的即为图像的分类标签。 LeNet卷积神经网络模型伪代码如表2所示。 Table 2 Pseudocode of LeNet model algorith 算法2：改进后的LeNet卷积神经网络模型 Input:原始图像28 * 28 model = models.Sequential() model.add(layers.Conv2D(32， (3， 3)， activation='relu'， input_shape=(28， 28， 1))) model.add(layers.MaxPooling2D((2， 2))) model.add(layers.Conv2D(64， (3， 3)， activation='relu')) model.add(layers.MaxPooling2D((2， 2))) model.add(layers.Conv2D(64， (3， 3)， activation='relu')) model.add(layers.Flatten()) model.add(layers.Dense(64， activation='relu')) model.add(layers.Dense(10， activation='softmax')) 表2. LeNet模型算法伪代码