OCR的有效数据增强

news2024/12/23 9:53:49

9db64e08b54f450a45a2ff8763f0ee86.png

背景

我面临着需要尽可能准确识别手写金额的挑战。难点在于保持误判率低于0.01%。由于数据集中样本数量固定,因此数据增强是合乎逻辑的选择。快速搜索未发现针对光学字符识别(OCR)的现成方法。因此,我挽起袖子,亲自创建了一个数据增强例程。它在训练过程中被使用,并帮助我的模型实现了目标。继续阅读以了解详情。

通过每次训练图像时引入小的变化,模型不太可能过拟合,更容易泛化。我将其与TROCR一起使用,但任何其他模型也应该受益。

测试设置

由于无法分享来自专有数据集的图像,我原本想使用IAM手写数据库的样本,但我未收到使用权限的回复。因此,我为演示创建了一些自己的示例。

我将使用OpenCV和albumentations库进行三种类型的修改:形态学、噪声和变换。

OpenCV是一个众所周知的计算机视觉库。Albumentations是一个相对较新的Python库,用于进行简单但功能强大的图像增强。

还有一个不错的演示网站,你可以在其中尝试albumentations的功能。但由于无法使用自己的图像进行测试,因此我创建了一个Jupyter笔记本,用于在本文中渲染所有增强的图像。请随时在Colab中打开并进行实验。

我们将首先展示单独的修改,附有一些解释,然后讨论将它们结合在一起的技术。我将假设所有图像都是灰度的,并已经进行了对比度增强(例如,CLAHE)。


第一种增强技术:形态学修改

这些与结构的形状有关。简单来说:它们可用于使文本行看起来像用细或粗笔写的。它们被称为腐蚀和膨胀。不幸的是,这些目前还没有包含在albumentations库中,因此我必须借助opencv来实现。

为了产生像是使用宽线宽度笔的效果,我们可以膨胀原始图像:

114c95e408a4386d47287266703852a3.png

另一方面,腐蚀(顺便说一下)模拟了使用细笔写的效果:

4b6a72ce75509a5204c034a4ed564d6f.png

在这里要小心,最后一个参数——即迭代次数——不要设置得太高(这里设置为3),否则手写完全被去除。

cv2.dilate(img, kernel,iterations=random.randint(1, 3))

对于我们的数据集,我们只能将其设置为1,因此这确实取决于你的数据。

第二种增强技术:引入噪声

我们可以从图像中删除黑色像素,也可以添加白色像素。有几种方法可以实现这一点。我尝试了许多方法,但这是我的简短清单:

黑色下降颜色的RandomRain非常有害。即使对我来说,仍然很难阅读文本。这就是为什么我选择将其发生的机会设置得很低的原因:

5c40df5f7caf45965f6875e75bc05993.png
RandomShadow会用不同强度的线模糊文本: 0b5651b383c210f9b38fa5d2ad8d19c4.png

PixelDropout轻松将随机像素变为黑色:

2d71c1eb1248d3baa19671b728c9bcf4.png

与黑色滴落相比,具有白色滴落颜色的RandomRain使文字解体,从而增强了训练的难度。就像当拍摄了复印一份传真的照片时看到的低质量一样。可以将此变换发生的概率设置得更高。

5ed6d6eed97b7304bc785b8dd14f16c7.png

在较小程度上,PixelDropout到白色也会产生相同的效果。但它更多地导致图像普遍褪色:

5824148b11280a516c493ed61a23e463.png
第三种增强技术:变换

ShiftScaleRotate:在这里要小心参数。尽量避免一些文本被切断并超出原始尺寸。同时进行缩放和旋转。确保不要过度使用太大的参数。否则,第一个样本的机会更大。你可以看到它实际上将文本移出图像。通过选择较大的边界框,可以防止这种情况——有效地在文本周围添加更多的空白。

31dc8b7439bbdd9796c4a7fd708002f8.png

模糊。老(但金贵)可靠的技术。将以不同的强度执行。

05b0cf9f33c84327b83eefdb2b17d2e0.png

大结局:将它们全部组合在一起:

这就是力量所在。我们可以随机组合这些效果,创建每个训练时期都包含的独特图像。需要谨慎考虑,不要做太多相同类型的方法。我们可以使用albumentation库中的OneOf函数来实现这一点。OneOf包含一系列可能的变换,正如其名称所暗示的那样,将仅以概率P执行其中的一个。因此,将做更多或更少相似的变换分组是有意义的,以避免过度使用。以下是该函数:

import random
import cv2
import numpy as np
import albumentations as A

#gets PIL image and returns augmented PIL image
def augment_img(img):
  #only augment 3/4th the images
  if random.randint(1, 4) > 3:
      return img

  img = np.asarray(img)     #convert to numpy for opencv

  # morphological alterations
  kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(3,3))
  if random.randint(1, 5) == 1:
    # dilation because the image is not inverted
    img = cv2.erode(img, kernel, iterations=random.randint(1, 2))
  if random.randint(1, 6) == 1:
    # erosion because the image is not inverted
    img = cv2.dilate(img, kernel,iterations=random.randint(1, 1))

  transform = A.Compose([

    A.OneOf([
      #add black pixels noise
      A.OneOf([
             A.RandomRain(brightness_coefficient=1.0, drop_length=2, drop_width=2, drop_color = (0, 0, 0), blur_value=1, rain_type = 'drizzle', p=0.05), 
              A.RandomShadow(p=1),
              A.PixelDropout(p=1),
         ], p=0.9),

      #add white pixels noise
      A.OneOf([
              A.PixelDropout(dropout_prob=0.5,drop_value=255,p=1),
             A.RandomRain(brightness_coefficient=1.0, drop_length=2, drop_width=2, drop_color = (255, 255, 255), blur_value=1, rain_type = None, p=1), 
        ], p=0.9),
    ], p=1),

    #transformations
    A.OneOf([
            A.ShiftScaleRotate(shift_limit=0, scale_limit=0.25, rotate_limit=2, border_mode=cv2.BORDER_CONSTANT, value=(255,255,255),p=1),
            A.ShiftScaleRotate(shift_limit=0.1, scale_limit=0, rotate_limit=8, border_mode=cv2.BORDER_CONSTANT, value=(255,255,255),p=1),
            A.ShiftScaleRotate(shift_limit=0.02, scale_limit=0.15, rotate_limit=11, border_mode=cv2.BORDER_CONSTANT, value=(255,255,255),p=1),  
            A.Affine(shear=random.randint(-5, 5),mode=cv2.BORDER_CONSTANT, cval=(255,255,255), p=1)          
       ], p=0.5),
    A.Blur(blur_limit=5,p=0.25),
  ])
  img = transform(image=img)['image']  
  image = Image.fromarray(img)   
  return image

P代表事件发生的机会。它是一个介于0和1之间的值,其中1表示它总是发生,0表示永远不会发生。

所以,让我们看看它在实际操作中的效果:

b63b93bcf6f92c5c553f8cef37e37c99.png

看起来相当不错,对吧?

另一种方法:

在EASTER 2.0论文中,他们提出了TACo技术。它代表平铺和破坏。(🌮哈哈)它能够实现这样的效果:

fe8fa4b1abb8ef082c7e4a0016542300.png

我还没有尝试过这个方法,因为我的直觉告诉我原始图像被破坏得太厉害。在我看来,如果我看不懂它,计算机也一样。然而,当考虑到作为人类,如果看到'TA█O',你可能会猜到它是'TACO'。我们会看周围的字母,而taco是一个常见的词。但是一个有字典支持的计算机可能会将其解读为'TAMO',这恰好是英语中表示“日本灰”的一个词。

结论

我们讨论了许多图像操作以及它们对OCR任务的好处。我希望这对你有所帮助,或者至少给了你一些尝试的灵感。你可以将我的方法作为基准,但可能需要微调一些参数,使其完美适应你的数据集。请告诉我你的模型准确性提高了多少!

我在这个Jupyter笔记本中公开了这个技术。

https://github.com/Toon-nooT/notebooks/blob/main/OCR_data_augmentations.ipynb

参考引用

https://opencv.org/

https://albumentations.ai/

https://fki.tic.heia-fr.ch/databases/iam-handwriting-database

https://arxiv.org/abs/2205.14879

https://github.com/Toon-nooT/notebooks

☆ END ☆

如果看到这里,说明你喜欢这篇文章,请转发、点赞。微信搜索「uncle_pn」,欢迎添加小编微信「 woshicver」,每日朋友圈更新一篇高质量博文。

扫描二维码添加小编↓

c71f277d83bcf620ed40e35f8faf2077.jpeg

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

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

相关文章

数据挖掘案例-商品零售购物篮分析

数据挖掘案例-商品零售购物篮分析 1. 背景与挖掘目标 现代商品种类繁多,顾客往往会由于需要购买的商品众多而变得疲于选择,且顾客并不会因为商品选择丰富而选择购买更多的商品。 例如,货架上有可口可乐和百事可乐,若顾客需要选…

「全新升级,性能更强大——ONLYOFFICE 桌面编辑器 8.1 深度评测」

文章目录 一、背景二、界面设计与用户体验三、主要新功能亮点3.1 高效协作处理3.2 共同编辑,毫无压力3.3 批注与提及3.4 追踪更改3.5 比较与合并3.6 管理版本历史 四、性能表现4.1 集成 AI 工具4.2 插件强化 五、用户反馈与使用案例 一、背景 Ascensio System SIA -…

服务器数据恢复—raid故障导致部分分区无法识别/不可用的数据恢复案例

服务器数据恢复环境: 一台某品牌DL380服务器中3块SAS硬盘组建了一组raid。 服务器故障: RAID中多块磁盘出现故障离线导致RAID瘫痪,其中一块硬盘状态指示灯显示红色。服务器上运行的数据库在D分区,备份文件存放在E分区。由于RAID瘫…

Git之checkout/reset --hard/clean -f区别(四十二)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒…

生命在于学习——Python人工智能原理(4.4)

三、Python的数据类型 3.2 Python的组合数据类型 特点:表示多个元素的组合,可以包含不同类型的元素,甚至是其他的组合数据类型。 在内存中通常需要额外的空间来存储元素间的关系。 组合数据类型能够将多个同类型或不同类型的数据组织起来&a…

Centos+Jenkins+Maven+Git 将生成的JAR部署到远程服务器上

1、登录 没有安装的参考下面的安装步骤先安装: Jenkins安装手册 输入账号、密码登录系统。 2、新建任务 2.1 创建页面 1,“输入一个任务名称”; 2,任务类型点击“构建一个maven项目”; 3,点击“确定”,此时,构建任务创建完成。 2.2 General 1、描述:输入要部署…

热电发电机越来越受到研发关注

热电发电机 (TEG) 利用热量(或更准确地说,温差)和众所周知的塞贝克效应来发电。它们的应用范围从收集可用热能,尤其是在工业和其他情况下“浪费”的热能,到在放射性同位素热发电机 (RTG) 中使用航天器的放射性电源作为…

day45--RocketMQ(三)

1. 高级功能 1.1 消息存储 分布式队列因为有高可靠性的要求,所以数据要进行持久化存储。 消息生成者发送消息MQ收到消息,将消息进行持久化,在存储中新增一条记录返回ACK给生产者MQ push 消息给对应的消费者,然后等待消费者返回A…

离镜头5cm也能拍清?Pura 70 超聚光微距如何做到“贴脸拍摄”?

虽然微距摄影在手机上已经算不得什么新鲜的功能,但要把微距摄影拍出高质量的效果,还是具有挑战性的。 众所周知,在微距摄影领域,镜头离被拍摄物品越近,照片的解析力和细节就越突出。但对于器件来讲,对焦距离…

年入百万不是梦?小米汽车员工晒收入,揭秘行业高薪背后的真相!

近日,社交媒体上出现了一位小米汽车员工的“凡尔赛”发言,其晒出的收入水平引发了网友们的热议。 这份令人艳羡的薪资条,也让“小米汽车待遇”迅速登上了热搜榜。究竟是什么样的魔力,让这家造车新势力能够开出如此优渥的条件&…

linux与windows环境下qt程序打包教程

一、演示环境 qt5.14.2 二、Linux 2.1 关联依赖文件 2.1.1 下载打包工具 在Windows环境下可以使用 Qt Creator自带的官方工具进行打包,而Linux环境下没有官方工具,需要借助第三方工具才能打包。如:linuxdeployqt、CQtDeployer、AppImage…

薄冰英语语法学习--名词1-不规则的

昨天学了,规则的,就是加es,或者变y为i加es,以及加s,还有变f和fe为v加es 今天学不规则。不规则就是完全没有规则,和s和es没有关系。就写死了告诉你,这个词的复数就是这样写。要硬背的。 首先来自古代英语的…

【数据结构与算法】最短路径,Floyd算法,Dijkstra算法 详解

Floyd算法 for (int k 0; k < n; k) {for (int i 0; i < n; i) {for (int j 0; j < n; j) {if (d[i][k] ! INF && d[k][j] ! INF) {d[i][j] min(d[i][j], d[i][k] d[k][j]);}}} }Dijkstra算法&#xff08;基于最小堆&#xff09; void dijkstra(int st…

篮球联盟管理系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;管理员管理&#xff0c;球员管理&#xff0c;用户管理&#xff0c;球队管理&#xff0c;论坛管理&#xff0c;篮球资讯管理&#xff0c;基础数据管理 前台账户功能包括&#xff1a;系统首页&#xff0…

零基础STM32单片机编程入门(二)GPIO详解及驱动LED灯实战含源码视频

文章目录 一.概要二.STM32F103C8T6单片机GPIO口特点二.STM32单片机GPIO内部结构图三.单片机GPIO推挽输出信号流向四.单片机GPIO浮空输入信号流向四.单片机GPIO引脚的复用以及重映射五.CubeMX配置一个GPIO输出驱动LED灯例程六.CubeMX工程源代码下载七.讲解视频链接地址八.小结 一…

集成了工作流引擎的办公系统,直接开发OA,ERP,mes,srm,hrm(源码)

前言 activiti工作流引擎项目&#xff0c;企业erp、oa、hr、crm等企事业办公系统轻松落地&#xff0c;一套完整并且实际运用在多套项目中的案例&#xff0c;满足日常业务流程审批需求。 一、项目形式 springbootvueactiviti集成了activiti在线编辑器&#xff0c;流行的前后端…

基于Java超市库存管理系统设计和实现(源码+LW+调试文档+讲解等)

&#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN作者、博客专家、全栈领域优质创作者&#xff0c;博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f31f;文末获取源码数据库&#x1f31f;感兴趣的可以先收藏起来&#xff0c;还…

线上OOM问题排查总结

自己搭建了一个小博客&#xff0c;该文章与博客文章同步。 一般情况下&#xff0c;出现OOM主要有一下三种原因。 一次性申请对象的太多。更改申请对象数量。内存资源耗尽未释放。找到未释放的对象进行释放。本身资源不够。jmap -heap 查看堆信息。 分几种情况解决&#xff1…

基于FreeRTOS+STM32CubeMX+LCD1602+MCP4142(SPI接口)的数字电位器Proteus仿真

一、仿真原理图: 二、仿真效果: 三、STM32CubeMX配置: 1)、时钟配置: 2)、SPI配置: 3)、GPIO配置: 四、软件部分: 1)、主功能函数: void Task0_Function(void) { uint16_t buffer; uint8_t value[3]; buffer = M

python遍历文件夹中所有图片

python遍历文件夹中的图片-CSDN博客 这个是之前的版本&#xff0c;现在这个版本会更好&#xff0c;直接进来就在列表中 path glob.glob("1/*.jpg")print(path)print(len(path))path_img glob.glob("1/*.jpg")path_img.extend(path)print(len(path_img))…