竞赛 基于机器视觉的火车票识别系统

文章目录

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

0 前言

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

基于机器视觉的火车票识别系统

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

🧿 更多资料, 项目分享:

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一个Operationprint("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 实现效果

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

最后

🧿 更多资料, 项目分享:

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

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Linux学习笔记】 - 常用指令学习及其验证(上)

前言:本文主要记录对Linux常用指令的使用验证。环境为阿里云服务器CentOS 7.9。关于环境如何搭建等问题,大家可到同平台等各大资源网进行搜索学习,本文不再赘述。 由于本人对Linux学习程度尚且较浅,本文仅介绍验证常用指令的常用…

27、Flink 的SQL之SELECT (SQL Hints 和 Joins)介绍及详细示例(2-1)

Flink 系列文章 1、Flink 部署、概念介绍、source、transformation、sink使用示例、四大基石介绍和示例等系列综合文章链接 13、Flink 的table api与sql的基本概念、通用api介绍及入门示例 14、Flink 的table api与sql之数据类型: 内置数据类型以及它们的属性 15、Flink 的ta…

7-15 求矩阵的局部极大值

输入格式: 输入在第一行中给出矩阵A的行数M和列数N(3≤M,N≤20);最后M行,每行给出A在该行的N个元素的值。数字间以空格分隔。 输出格式: 每行按照“元素值 行号 列号”的格式输出一个局部极大值&#xff0…

事件监听-@TransactionalEventListener与@EventListener的介绍、区别和使用

文章目录 前言事件监听-TransactionalEventListener与EventListener的介绍、区别和使用1. EventListener 是什么?2. TransactionalEventListener 是什么?3. TransactionalEventListener与EventListener的缺点3.1. TransactionalEventListener 的缺点:3.2. EventLi…

2.9 PE结构:重建导入表结构

脱壳修复是指在进行加壳保护后的二进制程序脱壳操作后,由于加壳操作的不同,有些程序的导入表可能会受到影响,导致脱壳后程序无法正常运行。因此,需要进行修复操作,将脱壳前的导入表覆盖到脱壳后的程序中,以…

openGauss学习笔记-69 openGauss 数据库管理-创建和管理普通表-更新表中数据

文章目录 openGauss学习笔记-69 openGauss 数据库管理-创建和管理普通表-更新表中数据 openGauss学习笔记-69 openGauss 数据库管理-创建和管理普通表-更新表中数据 修改已经存储在数据库中数据的行为叫做更新。用户可以更新单独一行、所有行或者指定的部分行。还可以独立更新…

【linux基础(六)】Linux中的开发工具(中)--gcc/g++

💓博主CSDN主页:杭电码农-NEO💓   ⏩专栏分类:Linux从入门到开通⏪   🚚代码仓库:NEO的学习日记🚚   🌹关注我🫵带你学更多操作系统知识   🔝🔝 Linux中的开发工具 1. 前言2.…

为什么建议将常量用const关键字来修饰

嵌入式软件中,内存资源是非常宝贵的,即sram资源。因此我们在编码过程中需要规划好并且使用好sram资源,这点非常重要! 在此之前需要预备一点基础知识,在IAR中,一般会用ICF配置文件给工程配置存储区域&#…

MongoDB差异数据对比的快速指南

MongoDB是一种非关系型数据库,它以灵活的 JSON-like 文档的形式存储数据,这种特性使其在处理大量数据和实现快速开发时更具有优势。而由于其灵活的数据模型和强大的性能,MongoDB 被广泛应用在各种业务场景中。随着业务的发展和数据的增长&…

vue中v-for循环数组使用方法中splice删除数组元素(错误:每次都删掉点击的下面的一项)

总结:平常使用v-for的key都是使用index,这里vue官方文档也不推荐,这个时候就出问题了,我们需要key为唯一标识,这里我使用了时间戳(new Date().getTime())处理比较复杂的情况, 本文章…

解决虚拟机重启后ifconfig看不到IP的问题

目录 背景 解决方案 背景 虚拟机,桥接模式,启动后一切正常,但重启后发现终端连不上虚机了,也ping不到,最后检查发现,IP消失了,虚机没有IP了。 解决方案 不论是否重启,只要是看不…

【css | loading】各种简单的loading特效

先看一下简单的效果图 线上预览 https://code.juejin.cn/pen/7278511766991339579 代码 HTML <!-- / 1 --><section><div class"sk-rotating-plane"></div></section><!-- / 2 --><section><div class"sk-doub…

【CSS3】

文章目录 1.简介2.边框3.圆角4.背景5.渐变CSS3 径向渐变6.文本效果7.字体8.2D转换9.3D转换10.过渡11.动画12.多列13.用户界面14.按钮 ​ 1.简介 模块 CSS3 被拆分为"模块"。旧规范已拆分成小块&#xff0c;还增加了新的。 一些最重要 CSS3 模块如下&#xff1a; 选…

内网隧道代理技术(二十六)之 搭建ICMP隧道上线CS

搭建ICMP隧道上线CS ICMP隧道原理 ICMP隧道简单实用,是一个比较特殊的协议。在一般的通信协议里,如果两台设备要进行通信,肯定需要开放端口,而在ICMP协议下就不需要。最常见的ping命令就是利用的ICMP协议,攻击者可以利用命令行得到比回复更多的ICMP请求。在通常情况下,…

input 的 placeholder 样式

::placeholder 伪元素 这个伪元素可以改变 input、textarea 占位文本的样式。 input::placeholder {color: green; }完整的兼容性写法&#xff1a; input {&::-webkit-input-placeholder, /* WebKit browsers*/ &:-moz-input-placeholder, /* Mozilla Firefox 4 to …

67、数据源配置 及 配置多个数据源--C3P0 数据源 和 Hikari 数据源

★ Spring Boot如何选择DataSource数据源 优先级从高到低&#xff1a; HikariCP > Tomcat pooling DataSource > Commons DBCP2 如果要使用Tomcat pooling DataSource这种池化数据源&#xff0c; 那么可以用</exclusions>这个把HikariCP 排除掉&#xff0c;然后sp…

16. Docker容器监控CAdvisor+InfluxDB+Granfana

目录 1、前言 2、原始命令 3、CAdvisorInfluxDBGranfana 3.1、什么是CAdvisor 3.2、什么是Influxdb 3.3、什么是Granfana 4、安装使用 4.1、安装influxdb 4.2、安装CAdvisor 4.3、安装Granfana 4.4、访问Influxdb 4.5、创建CAdvisor数据库 4.6、访问CAdvisor 4.7…

评价模型:层次分析法

1. 模型建立 1.1 建立层次结构模型 在深入分析实际问题的基础上&#xff0c;将有关的各个因素按照不同属性自上而下地分解成若干层次&#xff0c;同一层的诸因素从属于上一层的因素或对上层因素有影响&#xff0c;同时又支配下一层的因素或受到下层因素的作用。最上层为目标层…

python集合

集合set set_python1.集合的创建2.集合的相关操作3.集合间的关系4.集合的数学操作5.集合生成式 set_python 集合(set)是一个可变的数据类型&#xff0c;它用于存储一组唯一的元素。集合中的元素是无序的&#xff0c;并且不能重复。可以使用大括号{}或者set()函数来创建一个集合…

C# OpenVino Yolov8 Pose 姿态识别

效果 项目 代码 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using OpenCvSharp;namespace OpenVino_Yolov8_Demo {public…