一次完整的OCR实践记录
一、任务介绍
这次的任务是对两百余张图片里面特定的编号进行识别,涉及保密的原因,这里就不能粘贴出具体的图片了,下面粘贴出一张类似需要识别的图片。

假如说我的数据源如上图所示,那么我需要做的工作就是将上面图片里面标红的数字给识别出来。
我采用的算法是GitHub - YCG09/chinese_ocr: CTPN + DenseNet + CTC based end-to-end Chinese OCR implemented using tensorflow and keras,这是基于Tensorflow和keras框架采用ctpn+densenet+CTC算法来完成对图片指定内容的字符识别。
二、 图像标注
既然要进行OCR识别,那么一定要对已有的数据源进行图像标注工作,这里采用的工具是labelImg,相信大家如果有搞深度学习这块的话一定对这个工具不会陌生。

对图像具体的标注流程,我这里就不做说明了,网上有很多资料可以查找。这里需要作特别说明的是,对于ctpn的训练,label的名字为text,对于densenet的训练来说的话,就需要把标注框里面的内容当作label。
然后就是数据增强这块,这里需要记录的有两点,一就是原始的数据源比较少就必须做数据增强,不然做出来的效果肯定不太行,二就是怎么做数据增强,由于这里的数据比较简单,需要识别的内容也是有规律可行的,那这里就用不着采用比较复杂的数据增强,所以我做的数据增强就是对图像随机进行裁剪和倾斜,当然这里裁剪的尺寸和倾斜的角度一定要控制好,不然就会影响图片的质量。
import cv2
import numpy as np
import random
import os
from PIL import Image# 数据增强的代码img_path = r "*****************"
save_path = r "****************"# 随机倾斜图片
def rotate_ima(img_path,save_path):for file in os.listdir(img_path):img = cv2.imread(os.path.join(img_path, file ), 0 )rows,cols = img.shape# cols-1 and rows-1 are the coordinate limits.# 每张图片倾斜4张for i in range ( 4 ):a = random.randint( 2 , 6 )print (a)# 指定左右倾斜for j in range ( 2 ):a = - aM = cv2.getRotationMatrix2D(((cols - 1 ) / 2.0 ,(rows - 1 ) / 2.0 ),a, 1 )dst = cv2.warpAffine(img,M,(cols,rows))#cv2.imshow('img',img)#cv2.imshow('dst',dst)cv2.imwrite(os.path.join(save_path, 'rot_' + str (i) + '_' + str (j) + file ),dst)#cv2.waitKey(0)cv2.destroyAllWindows()# 随机裁剪图片
def cut_img(img_path,save_path):all_file = []for file in os.listdir(img_path):all_file.append( file )file1 = random.sample(all_file, 2 )for x in file1:im = Image. open (os.path.join(img_path,x))crop_all = []for c in range ( 5 ): # 对每张图片随机生成5张for i in range ( 4 ):a = random.randint( 100 , 400 )crop_all.append(a)region = im.crop((crop_all[ 0 ],crop_all[ 1 ],im.size[ 0 ] - crop_all[ 2 ],im.size[ 1 ] - crop_all[ 3 ]))region.save(os.path.join(save_path, 'cut_' + str (c) + '_' + x))#rotate_ima(img_path,save_path)
cut_img(img_path,save_path)
然后我大概生成了3000张左右的图片就开始进行数据标注了,标注了大概六七个小时才把这些数据标注给完成。
有了这些标注数据过后,就可以正式开始训练了。
三、CTPN训练
关于CTPN训练流程在chinese_ocr/ctpn at master · YCG09/chinese_ocr · GitHub的readme已经说的很清楚了。但是我这里就列出我所踩的坑吧。
最开始我直接把标注的数据制作成VOC2007数据集的格式丢进去训练,然后训练出来的效果并不好,后面我才在周围同事的提醒下有一个关键的步骤忘了做。

因为CTPN是进行文字检测并不同于普通的目标检测,它的检测原理是对单个的字符进行检测然后拼接在一起。

因为我们在进行数据标注的时候是对一整行文本进行拉框标注,但是如果要进行CTPN训练的话就需要对这个框划分成很多个矩形小框,划分的方法就是上面的split_label.py程序。
但是要进行上面一步的前提就是需要更改标注文件,使用labelImg标注出来的文件是一个图像对应一个xml文件,但是这里需要更改成一个图像对应一个txt文件,txt里面存放的是标注框的四个坐标,共计八个点(注意坐标点的顺序)。如下所示
410,1554,1723,1554,1723,1736,410,1736
然后在运行split_label.py,接着ToVoc.py,这里面的代码细节需要自行更改,这里就不做说明了。
然后就可以正式开始训练了,截图如下:

这里粘贴出一个错误需要注意:

解决方案就是删除cache文件夹
四、DenseNet+CTC训练
DenseNet+CTC训练主要分为两个步骤,一是图像处理,二是txt文件处理。
图像处理的话,在我们拿到标注好的数据之后需要对原始图像进行裁剪工作,就是根据标注的坐标裁剪出具体的图像,就拿上面的图像来说,我们需要的图像如下所示。

然后再对裁剪后的图像进行resize工作,resize成(280,32),这样的话图像处理这一部分就算完成了。
txt处理的话,这里我们需要对xml文件进行一系列处理来达到下面的效果。

前面card_900.jpg代表图像名称,后面这一串字符代表需要识别的字符在下面这个文件里面的位置索引。

注意这里txt里面存放的是所有图像里面待识别字符的编号,不是一个图像对应一个txt。
做到这一步过后,在把生成的txt划分成训练集和测试集,就算成功制作出来训练DenseNet的数据集了。

然后就可以开始训练了,截图如下:

五、总结
这次这个小的OCR项目历时大概十天左右,从数据标注再到训练模型,里面踩了很多坑,也做了很多次尝试,也查阅了很多资料,也向周围同事请教了很多次,总算功夫不负有心人,总算完成了这次项目。
这个记录只是记录了大概的流程,很多代码细节并不方便透露,更多详情参阅上面给出的GitHub地址。记录下这个更多是方便自己以后查阅。
相关文章:
一次完整的OCR实践记录
一、任务介绍 这次的任务是对两百余张图片里面特定的编号进行识别,涉及保密的原因,这里就不能粘贴出具体的图片了,下面粘贴出一张类似需要识别的图片。 假如说我的数据源如上图所示,那么我需要做的工作就是将上面图片里面标红的数…...
Java中常见的密码学知识
现代密码学 散列函数 散列函数,也见杂凑函数、摘要函数或哈希函数,可将任意长度的消息经过运算,变成固定长度数值,常见的有MD5、SHA-1、SHA256,多应用在文件校验,数字签名中。 MD5 可以将任意长度的原文生…...
Leetcode.2171 拿出最少数目的魔法豆
题目链接 Leetcode.2171 拿出最少数目的魔法豆 Rating : 1748 题目描述 给你一个 正 整数数组 beans,其中每个整数表示一个袋子里装的魔法豆的数目。 请你从每个袋子中 拿出 一些豆子(也可以 不拿出),使得剩下的 非空…...
day1 计算机组成与结构考点汇总
一、重点知识点 计算机硬件组成、运算器、控制器奇偶校验码、循环冗余校验码、海明码指令系统:指令操作数寻址方式、CISC和RISC、指令流水线的计算存储系统:分级存储、局部性原理、cache、主存编址计算、磁盘输入输出技术:程序查询方式、中断…...
Java虚拟机的类加载机制
Java虚拟机的类加载机制综述类的生命周期类加载器双亲委派模型---综述 我们编写的Java代码如何能在一个操作系统上运行呢?一般来说,我们使用javac命令将.java文件编译成.class文件,也就是Java字节码文件,然后由JVM将字节码文件加…...
分治法实现合并排序(归并排序),理解分治算法思想,实现分治算法的完美例子合并排序(含码源与解析)
🎊【数据结构与算法】专题正在持续更新中,各种数据结构的创建原理与运用✨,经典算法的解析✨都在这儿,欢迎大家前往订阅本专题,获取更多详细信息哦🎏🎏🎏 🪔本系列专栏 -…...
Typescript 类 (class)
基本用法 (通过关键字 class) // 基本用法 class VueService {constructor() {} // 构造器 } 类的约束(通过关键字 implements) // 接口定义属性类型 interface VueProps {name: stringinit: () > void }// 约束类 class VueService implements Vue…...
KDZD程控超低频高压发生器
一、产品概述 本产品接合了现代数字变频技术,采用微机控制,升压、降压、测量、保护自动化。由于电子化,所以体积小重量轻、大屏幕液晶显示,清晰直观、且能显示输出波形、打印试验报告。 设计指标符合《电力设备专用测试仪器通用…...
【华为OD机试 2023最新 】 过滤组合字符串(C++)
文章目录 题目描述输入描述输出描述用例题目解析C++题目描述 数字0、1、2、3、4、5、6、7、8、9分别关联 a~z 26个英文字母。 0 关联 “a”,”b”,”c”1 关联 “d”,”e”,”f”2 关联 “g”,”h”,”i”3 关联 “j”,”k”,”l”4 关联 “m”,”n”,”o”5 关联 “p”,”q”…...
Java笔记034-坦克大战【2】
目录 坦克大战【2】 线程-应用到坦克大战 坦克大战0.3 思路分析: 代码实现: 坦克大战0.4 增加功能 特别说明 思路分析: 代码实现: 坦克大战0.5 增加功能 思路分析: 代码实现: 坦克大战【2】 …...
【算法】【数组与矩阵模块】桶排序思想解决无序数组排序后相邻数间的最大差值
目录前言问题介绍解决方案代码编写java语言版本c语言版本c语言版本思考感悟写在最后前言 当前所有算法都使用测试用例运行过,但是不保证100%的测试用例,如果存在问题务必联系批评指正~ 在此感谢左大神让我对算法有了新的感悟认识! 问题介绍 …...
C语言—函数
函数库函数自定义函数函数的参数函数的调用函数的嵌套调用和链式访问函数的声明和定义函数递归递归与迭代函数递归的经典题目维基百科(台湾方面维护的,翻译形式跟大陆有所差异)中对函数的定义:子程序在计算机科学中,子…...
Autosar模式管理实战系列03-基于Davinci工具的WDGM配置
本文框架 前言1.WdgMConfigSet 配置2. 新建监控实体(SE)2.1 新建检测点(Checkpoint)2.2 设置 WdgMInternalTransitions3. WdgMLocalStatusParams配置4. WdgMAliveSupervision配置5. 代码插入指导前言 前面我们介绍了WdgM(看门狗管理)是一个 AutoSAR 的基础模块,负责管理看门…...
AutoML-sklearn and torch
一、auto-sklearn 1.1 环境依赖 额外安装swig 第三方库 linux 支持, mac,windows不支持 1.2 示例代码 time_left_for_this_task 设定任务最大时间 per_run_time_limit 每个子任务最大训练时间 include 可以限制任务训练的模型 import autosklearn.classific…...
《扬帆优配》算力概念股大爆发,主力资金大扫货
3月22日,9股封单金额超亿元,工业富联、鸿博股份、鹏鼎控股分别为3.01亿元、2.78亿元、2.37亿元。 今日三大指数团体收涨,收盘共34股涨停,首要集中于数字经济方向,其间云核算、CPO大迸发。除去5只ST股,算计2…...
机械臂+底盘三维模型从solidworks到moveit配置功能包
文章目录 导出底盘STEP加载机械臂模型组合机械臂和底盘三维模型导出URDF在moveit中进行配置新建工作目录设置ROS工作空间的环境变量进入moveit setup加载URDF文件self-CollisionsPlanning groupsRobot posesControllersSimulationAuthor information生成配置包在rviz中进行可视…...
高并发系统设计:缓存、降级、限流、(熔断)
高并发系统设计:缓存、降级、限流、(熔断) 在开发高并发系统时有三把利器用来保护系统:缓存、降级和限流。 非核心服务可以采用降级、熔断,核心服务采用缓存和限流(隔离流量可以最大限度的保障业务无损)。 缓存 缓…...
《辉煌优配》放量大涨,A股成交额重回万亿!PCB板块继续领跑
多只绩优PCB概念股超跌。 今日A股放量反弹,成交额从头站上万亿关口。芯片板块掀涨停潮,景嘉微、芯原股份20cm涨停,紫光国微、兆易创新、跃岭股份等封板;AI算力、存储器、光模块、云核算等板块全线拉升,板块内个股再度批…...
Vue封装的过度与动画
动画效果 先把样式封装好,然后设置一个动画 不需要vue也能实现的动画的效果,我们只需要判断一下,然后动态的添加和删除类名即可 那能不能不自己写动态,就靠vue 首先我们要靠<transition>标签把需要动画的包裹起来 vue中…...
流量监控-ntopng
目录介绍安装使用介绍 ntopng是原始ntop的下一代版本,ntop是监视网络使用情况的网络流量探测器。ntopng基于libpcap,并且以可移植的方式编写,以便实际上可以在每个Unix平台,MacOSX和Windows上运行。 ntopng(是的&…...
linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...
Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)
文章目录 1.什么是Redis?2.为什么要使用redis作为mysql的缓存?3.什么是缓存雪崩、缓存穿透、缓存击穿?3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...
【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...
HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...
08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险
C#入门系列【类的基本概念】:开启编程世界的奇妙冒险 嘿,各位编程小白探险家!欢迎来到 C# 的奇幻大陆!今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类!别害怕,跟着我,保准让你轻松搞…...
LLaMA-Factory 微调 Qwen2-VL 进行人脸情感识别(二)
在上一篇文章中,我们详细介绍了如何使用LLaMA-Factory框架对Qwen2-VL大模型进行微调,以实现人脸情感识别的功能。本篇文章将聚焦于微调完成后,如何调用这个模型进行人脸情感识别的具体代码实现,包括详细的步骤和注释。 模型调用步骤 环境准备:确保安装了必要的Python库。…...
五子棋测试用例
一.项目背景 1.1 项目简介 传统棋类文化的推广 五子棋是一种古老的棋类游戏,有着深厚的文化底蕴。通过将五子棋制作成网页游戏,可以让更多的人了解和接触到这一传统棋类文化。无论是国内还是国外的玩家,都可以通过网页五子棋感受到东方棋类…...
