一次完整的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(是的&…...
(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
day52 ResNet18 CBAM
在深度学习的旅程中,我们不断探索如何提升模型的性能。今天,我将分享我在 ResNet18 模型中插入 CBAM(Convolutional Block Attention Module)模块,并采用分阶段微调策略的实践过程。通过这个过程,我不仅提升…...
376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...
ios苹果系统,js 滑动屏幕、锚定无效
现象:window.addEventListener监听touch无效,划不动屏幕,但是代码逻辑都有执行到。 scrollIntoView也无效。 原因:这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作,从而会影响…...
MySQL JOIN 表过多的优化思路
当 MySQL 查询涉及大量表 JOIN 时,性能会显著下降。以下是优化思路和简易实现方法: 一、核心优化思路 减少 JOIN 数量 数据冗余:添加必要的冗余字段(如订单表直接存储用户名)合并表:将频繁关联的小表合并成…...
从 GreenPlum 到镜舟数据库:杭银消费金融湖仓一体转型实践
作者:吴岐诗,杭银消费金融大数据应用开发工程师 本文整理自杭银消费金融大数据应用开发工程师在StarRocks Summit Asia 2024的分享 引言:融合数据湖与数仓的创新之路 在数字金融时代,数据已成为金融机构的核心竞争力。杭银消费金…...
探索Selenium:自动化测试的神奇钥匙
目录 一、Selenium 是什么1.1 定义与概念1.2 发展历程1.3 功能概述 二、Selenium 工作原理剖析2.1 架构组成2.2 工作流程2.3 通信机制 三、Selenium 的优势3.1 跨浏览器与平台支持3.2 丰富的语言支持3.3 强大的社区支持 四、Selenium 的应用场景4.1 Web 应用自动化测试4.2 数据…...
