深度学习火车票识别系统 计算机竞赛

news2024/11/27 2:45:59

文章目录

  • 0 前言
  • 1 课题意义
    • 课题难点:
  • 2 实现方法
    • 2.1 图像预处理
    • 2.2 字符分割
    • 2.3 字符识别
      • 部分实现代码
  • 3 实现效果
  • 4 最后

0 前言

🔥 优质竞赛项目系列,今天要分享的是

🚩 图像识别 火车票识别系统

该项目较为新颖,适合作为竞赛课题方向,学长非常推荐!

🥇学长这里给一个题目综合评分(每项满分5分)

  • 难度系数:3分
  • 工作量:3分
  • 创新点:4分

🧿 更多资料, 项目分享:

https://gitee.com/dancheng-senior/postgraduate

1 课题意义

在这里插入图片描述

目前火车乘务员在卧铺旅客在上车前为其提供将火车票换成位置信息卡服务,在旅客上车前,由于上车人数多,而且大多数旅客都携带大量行李物品,而且乘车中老人和小孩也较多。在换卡这一过程中,人员拥挤十分厉害,而且上火车时,火车门窄阶梯也较陡,危险系数十分高。乘务员维持秩序十分困难。换卡之后,在旅客下车之前乘务员又要将位置信息卡换成火车票。这一过程冗长且对于旅客基本没有任何有用的意义。如果通过光学符识别软件,乘务员利用ipad等电子产品扫描采集火车票图像,读取文本图像,通过识别算法转成文字,将文字信息提取出来,之后存储起来,便于乘务员统计查看,在旅客到站是,系统自动提醒乘务员某站点下车的所有旅客位置信息。随着铁路交通的不断优化,车次与旅客人数的增加,火车票免票系统将更加便捷,为人们带来更好的服务。

课题难点:

由于火车票票面文字识别属于多种字体混排,低品质的专用印刷汉子识别。火车票文字笔画粘连,断裂,识别复杂度高,难度大,采用目前较好的OCR技术都比较难以实现。

2 实现方法

2.1 图像预处理

火车票经过扫描装置火车照相机等装置将图像传递到计算机,经过灰度处理保存为一幅灰度图。如果要对火车票进行后期的识别,那么就一定要对图像做二值化,之后再对二值化的图像进行版面分析,确定我们所需要的信息所在,之后才能进行单个字符的分割,才能对字符做提取特征点的工作,之后按照我们对比确定的规则来进行判决从而达到识别效果。

由于火车票容易被污损、弯折,而且字符的颜色也是有所不同,火车票票号是红色,而其他信息显示则为黑色,票面的背景包括红色和蓝色两种彩色,这些特点都使得火车票的文字识别不同于一般的文字识别。在识前期,要对火车票图像做出特定的处理才能很好的进行后续的识别。本次课题所研究的预处理有平常所处理的二值化,平滑去噪之外还需要针对不同字符颜色来进行彩色空间上的平滑过滤。

预处理流程如下所示

在这里插入图片描述

2.2 字符分割

字符分割就是在版面分析后得到的文本块切分成为文字行,之后再将行分割成单个字符,来进行后续的字符识别。这是OCR系统里至关重要的一环,直接影响识别效果。字符分割的主流方式有三种,一种是居于图像特种来寻找分割的准则,这是从结构角度进行分析切割。另一种方式是根据识别效果反馈来确认分割结果有无问题,这种方式是基于识别的切分。还有一种整体切分方式,把字符串当做整体,系统进行以词为基础的识别比并非字识别,一般这一方式要根据先验知识来进行辅助判断。

分割效果如下图所示:
在这里插入图片描述
在这里插入图片描述

2.3 字符识别

中文/数字/英文 识别目前最高效的方法就是使用深度学习算法进行识别。

字符识别对于深度学习开发者来说是老生常谈了,这里就不在复述了;

网络可以视为编解码器结构,编码器由特征提取网络ResneXt-50和双向长短时记忆网络(BiLSTM)构成,解码器由加入注意力机制的长短时记忆网络(LSTM)构成。网络结构如下图所示。

在这里插入图片描述

网络训练流程如下:
在这里插入图片描述

部分实现代码

这里学长提供一个简单网络字符识别的训练代码:
(需要完整工程及代码的同学联系学长获取)

import tensorflow as tf
import numpy as np
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets('MNIST_data', one_hot=True)
#1、开始建立一个图
sess = tf.InteractiveSession()#启动一个交互会话
x = tf.placeholder(tf.float32, shape=[None, 784])#x和y_都用一个占位符表示
y_ = tf.placeholder(tf.float32, shape=[None, 10])

W = tf.Variable(tf.zeros([784, 10]))#W和b因为需要改变,所以定义为初始化为0的变量
b = tf.Variable(tf.zeros(10))

#2、建立预测部分的操作节点
y = tf.matmul(x,W) + b  #计算wx+b
cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y)) #计算softmax交叉熵的均值

#3、现在已经得到了损失函数,接下来要做的就是最小化这一损失函数,这里用最常用的梯度下降做
# 为了用到前几节说过的内容,这里用学习率随训练下降的方法执行
global_step = tf.Variable(0, trainable = False)#建立一个可变数,而且这个变量在计算梯度时候不被影响,其实就是个全局变量
start_learning_rate = 0.5#这么写是为了清楚
#得到所需的学习率,学习率每100个step进行一次变化,公式为decayed_learning_rate = learning_rate * decay_rate ^(global_step / decay_steps)
learning_rate = tf.train.exponential_decay(start_learning_rate, global_step, 10, 0.9, staircase=True)

train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(cross_entropy)#梯度下降最小化交叉熵
#这是因为在交互的Session下可以这样写Op.run(),还可以sess.run(tf.global_variables_initializer())
tf.global_variables_initializer().run()#初始化所有变量

#iteration = 1000, Batch_Size = 100 
for _ in range(1000):
    batch = mnist.train.next_batch(100)#每次选出100个数据
    train_step.run(feed_dict = {x:batch[0], y_: batch[1]})#给Placeholder填充数据就可以了

correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1)) #首先比较两个结果的差异
#这时的correct_prediction应该类似[True, False, True, True],然后只要转为float的形式再求加和平均就知道准确率了
#这里的cast是用于形式转化
accuracy = tf.reduce_mean(tf.cast(correct_prediction, dtype=tf.float32))
#打印出来就可以了,注意这个时候accuracy也只是一个tensor,而且也只是一个模型的代表,还需要输入数据
print(accuracy.eval(feed_dict={x: mnist.test.images, y_: mnist.test.labels}))

sess.close()

#首先把要重复用的定义好
def weight_variable(shape):
    initial = tf.truncated_normal(shape=shape, stddev=0.1)
    return tf.Variable(initial)
def bias_variable(shape):
    initial = tf.constant(0.1, shape=shape)#常量转变量,
    return tf.Variable(initial)
def conv2d(x, f):
    return tf.nn.conv2d(x, f, strides=[1,1,1,1], padding='SAME')
def max_pool_22(x):
    return tf.nn.max_pool(x, ksize=[1,2,2,1], strides=[1,2,2,1], padding='SAME')

sess = tf.InteractiveSession()#启动一个交互会话
x = tf.placeholder(tf.float32, shape=[None, 784])#x和y_都用一个占位符表示
y_ = tf.placeholder(tf.float32, shape=[None, 10])
x_image = tf.reshape(x, [-1, 28, 28, 1])
#第一层:
#1、设计卷积核1
fW1 = weight_variable([5,5,1,32])#[height, weight, in_channel, out_channel]
fb1 = bias_variable([32])

#2、卷积加池化
h1 = tf.nn.relu(conv2d(x_image,fW1)+ fb1)
h1_pool = max_pool_22(h1)

#第二层
fW2 = weight_variable([5,5,32,64])#[height, weight, in_channel, out_channel]
fb2 = bias_variable([64])

h2 = tf.nn.relu(conv2d(h1_pool,fW2)+ fb2)
h2_pool = max_pool_22(h2)

#全部变成一维全连接层,这里因为是按照官方走的,所以手动计算了经过第二层后的图片尺寸为7*7
#来定义了一个wx+b所需的w和b的尺寸,注意这里的W和b不是卷积所用的了
h2_pool_flat = tf.reshape(h2_pool, [-1, 7*7*64])#首先把数据变成行表示
W_fc1 = weight_variable([7 * 7 * 64, 1024])
b_fc1 = bias_variable([1024])
h_fc1 = tf.nn.relu(tf.matmul(h2_pool_flat, W_fc1) + b_fc1)

#定义dropout,选择性失活,首先指定一个失活的比例
prob = tf.placeholder(tf.float32)
h_dropout = tf.nn.dropout(h_fc1, prob)

#最后一个全连接层,输出10个值,用于softmax
W_fc2 = weight_variable([1024, 10])
b_fc2 = bias_variable([10])
y_conv = tf.matmul(h_dropout, W_fc2) + b_fc2

#梯度更新,这里采用另一种优化方式AdamOptimizer
cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y_conv))
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
correct_prediction = tf.equal(tf.argmax(y_conv,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

#初始化
sess.run(tf.global_variables_initializer())
for i in range(2000):
    batch = mnist.train.next_batch(50)
    if i%100 == 0:
        train_accuracy = accuracy.eval(feed_dict = {x:batch[0],y_:batch[1], prob:1.0}) #这里是计算accuracy用的eval,不是在run一个Operation
        print("step %d, training accuracy %g"%(i, train_accuracy))
    train_step.run(feed_dict={x: batch[0], y_: batch[1], prob: 0.5})
print("test accuracy %g"%accuracy.eval(feed_dict={x: mnist.test.images, y_: mnist.test.labels, prob: 1.0}) )

3 实现效果

车票图
在这里插入图片描述
识别效果:
在这里插入图片描述

4 最后

🧿 更多资料, 项目分享:

https://gitee.com/dancheng-senior/postgraduate

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1287113.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

详细介绍如何使用 SSD 进行实时物体检测:单次 MultiBox 探测器-含源码

介绍 在实时对象检测中,主流范例传统上采用多步骤方法,包括边界框、像素或特征重采样以及高质量分类器应用的提议。虽然这种方法已经实现了高精度,但其计算需求往往阻碍了其对实时应用的适用性。然而,单次多框检测器 (SSD) 代表了基于深度学习的对象检测的突破性飞跃。SSD…

rust中动态数组Vec的简单使用

在Rust中,Vector(简称Vec)是一个动态数组数据结构,它可以动态地增加或减少其容量。Vec是Rust标准库中的一个常见类型,非常适合用于存储和操作一系列相同类型的值。 Vec其实是一个智能指针,用于在堆上分配内…

自定义软件app定制开发的需求和趋势|企业网站小程序搭建

自定义软件app定制开发的需求和趋势|企业网站小程序搭建 随着智能手机的普及和移动互联网的快速发展,移动应用程序(App)成为人们日常生活和工作中必不可少的一部分。然而,市面上已有的应用程序并不能完全满足用户的个性化需求&…

编写测试用例的17个技巧

1、前言 测试用例是任何测试周期的第一步,对任何项目都非常重要。如果在此步骤中出现任何问题,则在整个软件测试过程中都会扩大影响。如果测试人员在创建测试用例模板时使用正确的过程和准则,则可以避免这种情况。 在本文中将分享一些简单而…

synchronized底层原理(一)

文章目录 1. 问题引入2. 相关概念3. Synchronized使用4. Synchronized底层原理1. 简介2. Monitor(管程/监视器)3. Java语言的内置管程synchronized4. Java对象的内存布局5. 如何使用MarkWord记录锁状态6. 偏向锁7. 轻量级锁 1. 问题引入 假设我们有1000…

PostGIS学习教程十:空间索引

PostGIS学习教程十:空间索引 回想一下,空间索引是空间数据库的三个关键特性之一。空间索引使得使用空间数据库存储大型数据集成为可能。在没有空间索引的情况下,对要素的任何搜索都需要对数据库中的每条记录进行"顺序扫描"。索引通…

在gitlab中使用gitlab-sshd替换ssh服务

参考:https://docs.gitlab.com/ee/administration/operations/gitlab_sshd.html 说明 gitlab-sshd 是 OpenSSH 的轻量级替代品,用于提供 SSH 操作。虽然 OpenSSH 使用受限的 shell 方法,但 gitlab-sshd 的行为更像是一个现代的多线程服务器应…

mabatis基于xml方式和注解方式实现多表查询

前面步骤 http://t.csdnimg.cn/IPXMY 1、解释 在数据库中,单表的操作是最简单的,但是在实际业务中最少也有十几张表,并且表与表之间常常相互间联系; 一对一、一对多、多对多是表与表之间的常见的关系。 一对一:一张…

【Maven】安装和使用

1. Maven 概述 Maven 是一款用于管理和构建 java 项目的工具,可以进行依赖管理、统一项目结构和项目构建。 1.1 Maven 模型 项目对象模型 (Project Object Model)依赖管理模型(Dependency)构建生命周期/阶段(Build lifecycle & phases) 1.2 Maven 仓库 仓库的…

ROS2教程01 ROS2介绍

ROS2介绍 版权信息 Copyright 2023 Herman YeAuromix. All rights reserved.This course and all of its associated content, including but not limited to text, images, videos, and any other materials, are protected by copyright law. The author holds all right…

高级搜索——伸展树Splay详解

文章目录 伸展树Splay伸展树Splay的定义局部性原理Splay的伸展操作逐层伸展双层伸展zig-zig/zag-zagzig-zag/zag-zigzig/zag双层伸展的效果与效率 伸展树的实现动态版本实现递增分配器节点定义Splay类及其接口定义伸展操作左单旋右单旋右左/左右双旋伸展 查找操作删除操作插入操…

【laBVIEW学习】4.声音播放,自定义图标,滚动条设置,保存参数以及恢复参数

一。声音播放(报错,未实现) 1.报错4810 2.解决方法: 暂时未解决。 二。图片修改 1.目标:灯泡---》自定义灯泡 2.步骤: 1.右键点击--》自定义运行 表示可以制作自定义类型 2.右键--》打开自定义类型 这样就…

【Qt开发流程】之对象模型2:属性系统

描述 Qt提供了一个复杂的属性系统,类似于一些编译器供应商提供的属性系统。然而,作为一个独立于编译器和平台的库,Qt不依赖于非标准的编译器特性,如__property或[property]。 Qt解决方案适用于Qt支持的所有平台上的任何标准c编译…

java的GUI基础使用

java.awt包提供了基本的GUI设计工具,主要包括组件(Component)、容器(Container)和布局管理器(LayoutManager); Java的图形用户界面的最基本组成部分是组件(Component&…

Hadoop学习笔记(HDP)-Part.11 安装Kerberos

目录 Part.01 关于HDP Part.02 核心组件原理 Part.03 资源规划 Part.04 基础环境配置 Part.05 Yum源配置 Part.06 安装OracleJDK Part.07 安装MySQL Part.08 部署Ambari集群 Part.09 安装OpenLDAP Part.10 创建集群 Part.11 安装Kerberos Part.12 安装HDFS Part.13 安装Ranger …

数据库事务:保障数据一致性的基石

目录 1. 什么是数据库事务? 1.1 ACID特性解析 2. 事务的实现与控制 2.1 事务的开始和结束 2.2 事务的隔离级别 3. 并发控制与事务管理 3.1 并发控制的挑战 3.2 锁和并发控制算法 4. 最佳实践与性能优化 4.1 事务的划分 4.2 批处理操作 5. 事务的未来发展…

odoo自定义提示性校验

背景: 在odoo16的原生的代码里,可以给按钮添加一个 confirm属性,从而达到 提示性校验的效果。 问题: 这个属性加了之后一定会弹出提示性校验的对话框,于是如何根据我们的实际业务,从后端返回提示性信息,…

极致体验云上无缝协作

探索SOLIDWORKS云上之旅 谁适合应用3DEXPERIENCE云平台? 迈向云策略的数字化转型企业、加速新品上市的企业创新部门、资源有限的小微及初创企业 什么是3DEXPERIENCE云平台? 3DEXPERIENCE(3DX)是一种业务与创新平台,可让所有组织整体实时了解业务活动和生态系统&#xff0c…

Python的海龟 turtle 库使用详细介绍(画任意多边形,全网最详细)

学Turtle库,其实就是学数学,而且还能提高对数学和学习的兴趣。Turtle库还能够帮助孩子更好地理解几何学和数学概念,比如角度、比例、几何图形的性质等等,是Python中一个很有趣的库。 前言 Turtle库是Python中一个很有趣的库&…

【计算机组成体系结构】主存储器的基本组成

一、半导体元器件存储二进制0/1的原理 一个存储器逻辑上分为MAR,MDR和存储体,这三块在时序逻辑电路的控制下相互配合工作。 而存储体有多个存储单元构成,每个存储单元又由每个存储元构成。一个存储元可以存放一位的二进制的0/1。 一个存储元…