文档智能(一):基于OpenCV的文档图像校正

news2024/11/19 15:34:05

文档智能(一):基于OpenCV的文档图像校正
发表时间2023年1月7日创作地点湖北省武汉市作者:ixy_com&[Aneerban Chakraborty]

在这里插入图片描述

封面图片来源:DocTr

本文关键词:文档智能、文档图像校正、OpenCV、形态学变换、边缘检测、轮廓检测、透视变换

1、研究背景

基本概念:文档智能是指通过计算机进行自动阅读、理解以及分析商业文档的过程,是自然语言处理和计算机视觉交叉领域的一个重要研究方向。近年来,数字图像处理技术以及深度学习的飞速发展,极大地推动了文档智能领域的发展,以文档版面分析、文档信息抽取、文档视觉问答、文档图像分类以及文档图像校正等任务为代表的的文档智能任务得到了性能上的显著提升。

任务来源:为积极响应企业数字化转型发展的现实需求,我部承担了基于知识图谱的**研究任务。其中,收集得到的大规模文档数据中有极大比例的PDF扫描件。与可编辑文档PDF格式不同,该类型文档不可编辑,实为图像数据;同时,由于数据收集方等各种不可控因素,导致大量文档图像数据出现扭曲、倾斜、颠倒等情况;因此,为了便于数据处理,提升PDF扫描件的字符识别精度,首先对其进行文档图像校正处理。

---- 数字智能研发


内容说明:在本文中,我将简要介绍基于OpenCV的文档图像校正基本流程,并代码实践的形式加以展示。如下图所示,目前相关研究材料非常充足,本文仅做简单记录,用以交流。基本目标为:介绍OpenCV的基本使用,包括但不限于形态学处理、边缘检测、角点检测、透视变换等章节内容,核心内容为数字图像处理相关技术。全文内容包含以下部分:

在这里插入图片描述

图 1-1 文档图像校正相关研究(万方数据)

内容目录:

  • OpenCV基本使用(opencv-contrib-python)
  • 形态学处理(Morphological operation)
  • GrabCut图像分割(GrabCut)
  • 边缘检测(Edge Detection)
  • 角点检测(Corner Points)
  • 透视变换(Perspective Transform)
  • 局限性(Limitations)

2、研究内容

2.1 OpenCV基本使用

Opencv是一个开源的计算机视觉库,内部包含丰富的数字图像处理工具。其支持多平台安装使用,安装教程与相关简介本文不做赘述。利用Opencv可以进行图像处理、特征检测与描述、视频分析、相机校准与3D重建、机器学习、计算摄影以及目标检测等任务。相关工具箱的集成化程度非常高,可参见Opencv 4.0文档。

这里用图像滤波举例,将使用各种低通滤波器(LPF)进行图像模糊,并对图像应用自定义滤波器(二维卷积)。LPF有助于降低噪音,高通滤波器HPF有助于在图像中找到边缘。OpenCV中的 c v . f i l t e r 2 D ( ) cv.filter2D() cv.filter2D()函数即可实现上述功能。首先读入原始图像,如下图:

在这里插入图片描述

图 2.1-1 原始图像示例
# 使用自定义的卷积核(滤波器)对输入图像进行二维卷积操作
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt


"""
print(np.__version__)
print(cv.__version__)
1.21.2
4.3.0
"""

img = cv.imread('./OpenCV.jpg')
kernel = np.ones((5, 5), np.float32)/25
dst = cv.filter2D(img, -1, kernel)

plt.subplot(121)
plt.title('Original image')
plt.imshow(img)
# 第二张子图
plt.subplot(122)
plt.title('Filtered image') 
plt.imshow(dst)

plt.show()

在这里插入图片描述

图 2.1-2 图像滤波示例
# 对输入图像进行均值模糊
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt


"""
print(np.__version__)
print(cv.__version__)
1.21.2
4.3.0
"""

img = cv.imread('./OpenCV.jpg')

dst = cv.blur(img, (5, 5))

plt.subplot(121)
plt.title('Original image')
plt.imshow(img)

plt.subplot(122)
plt.title('Blurred image')
plt.imshow(dst)

plt.show()

2.2 形态学处理

使用OpenCV提供的 c v 2. m o r p h o l o g y E x ( ) cv2.morphologyEx() cv2.morphologyEx()函数对输入图像做形态学的开与闭操作,其过程依赖于腐蚀(Erode)与膨胀(Dilate)。在本案例中,我们对输入图像进行闭操作,即先执行膨胀、再执行腐蚀操作。反复执行图像的闭操作,将得到输入图像的空白页面。

说明:因为后文需要对数据图像进行边缘检测,为了避免文档图像中的条纹或字符影响边缘检测的结果,这里将其处理为空白页面,实现过程如下代码block所示,其中示例数据来自于github。

# 首先读入待处理的原始图像
img = cv2.imread('./inputs/img1.jpg', cv2.IMREAD_COLOR)
plt.imshow(img)

在这里插入图片描述

图 2.2-1 待处理的文本图像数据
# 图像预处理:输入图像的尺寸缩放以便于处理
# 首先获取输入文本图像的shape以及对应的最大值
max_dim = max(img.shape)
# 定义size的阈值
dim_limit = 1080
# 进行size判断
if max_dim > dim_limit:
    resize_tor = dim_limit/max_dim
    img = cv2.resize(img, None, fx=resize_tor, fy=resize_tor)
    
# 将原始图像拷贝一份
origin_img = copy()
# 重复执行闭操作,从而移除文档图像中的文本
kernel = np.ones((5,5),np.uint8)
# 这里以执行次数为4举例,通过与原图对比可以发现,文本图像中的文字已多半被移除。但仍视具体情况需调整迭代次数!
img = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel, iterations= 4)
plt.imshow(img)

在这里插入图片描述

图 2.2-2 迭代执行图像闭操作后的文本图像

2.3 GrabCut图像分割

经过上述多个步骤的文本图像预处理之后,得到了一张版面为空白的文本图像数据。则接下来的工作为:去除文本图像版面区域以外的背景。这里使用GrabCut方式实现图像数据分割。

GrabCut方法说明:

  • 在本例中,文档图像区域被认为是前景对象(foreground),其边界框以外的所有区域都被认为是背景(background);
  • 使用GrabCut方法可以自动实现背景区域的消除,则剩下的区域就是前景对象了;

如果手动地绘制前景对象的边界框,则人为主观性太强。因此,这里使用GrabCut方法自动地确定前景和背景,实现如下:

# 通过GrabCut算法实现前景对象的分割
mask = np.zeros(img.shape[:2],np.uint8)
bgdModel = np.zeros((1,65),np.float64)
fgdModel = np.zeros((1,65),np.float64)
rect = (20,20,img.shape[1]-20,img.shape[0]-20)
cv2.grabCut(img,mask,rect,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_RECT)
mask2 = np.where((mask==2)|(mask==0),0,1).astype('uint8')
img = img*mask2[:,:,np.newaxis]

处理效果如下图所示,可见前景对象以外的区域均被分割出来。

在这里插入图片描述

图 2.3-1 图像分割后的前景对象

2.4 边缘检测

经过上述小节的处理后,现在的文本图像数据以没有干扰背景的空白页面呈现,于是就可以有效地执行边缘检测操作。这里通过使用Canany算法来实现文档区域边缘的检测。其调用形式如下:
e d g e s = c v 2. C a n n y ( i m a g e , t h r e s h o l d 1 , t h r e s h o l d 2 [ , e d g e s [ , a p e r t u r e S i z e [ , L 2 g r a d i e n t ] ] ] ) edges = cv2.Canny( image, threshold1, threshold2[, edges[, apertureSize[, L2gradient]]] ) edges=cv2.Canny(image,threshold1,threshold2[,edges[,apertureSize[,L2gradient]]])
参数说明:

  • image:为输入图像;
  • threshold1:第一个阈值,first threshold for the hysteresis procedure.
  • threshold2:第二个阈值, second threshold for the hysteresis procedure.
  • apertureSize:是Sobel operator的孔径大小(aperture size).
  • L2gradient:作为一个标记,表明是否使用给为准确的L2范数来计算图像梯度。

处理步骤:

(1)首先对输入图像进行灰度化处理,使其满足canny算法的处理需求;

(2)然后对灰度图像进行高斯模糊处理,去除图像中的噪声;

(3)对处理后的图像做边缘检测;

(4)对处理后的图像做膨胀操作(dilate),获取文档的轮廓线。

# 基于canny-edge的边缘检测,处理后的效果如下图所示:
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (11, 11), 0)
# Edge Detection.
canny = cv2.Canny(gray, 100, 200)
canny = cv2.dilate(canny, cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5)))
plt.imshow(canny)

在这里插入图片描述

图 2.4-1 边缘检测后的图像数据

2.5 轮廓检测

说明1:边缘检测与轮廓检测的区别?

轮廓检测的目标是确定闭合物体的形状,特别是因为对于具有相同颜色强度的连续点,寻找轮廓的方法是确定的,而边缘检测是通过检测颜色强度内的变化来进行的。参考相关issue。

通过上述小节的边缘检测,得到文档图像数据的边缘,这里进一步通过轮廓检测得到这些边缘所对应的闭合轮廓。调用过程如下:
c o n t o u r s , h i e r a r c h y = c v 2. f i n d C o n t o u r s ( i m a g e , m o d e , m e t h o d [ , c o n t o u r s [ , h i e r a r c h y [ , o f f s e t ] ] ] ) contours, hierarchy = cv2.findContours( image, mode, method[, contours[, hierarchy[, offset]]] ) contours,hierarchy=cv2.findContours(image,mode,method[,contours[,hierarchy[,offset]]])

# 对边缘检测后的文档图像数据进行轮廓检测
con = np.zeros_like(img)
# 对检测得到的边缘获取其轮廓
contours, hierarchy = cv2.findContours(canny, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
# 保留最大的轮廓,将其绘制在画布上,效果如下图:
page = sorted(contours, key=cv2.contourArea, reverse=True)[:5]
con = cv2.drawContours(con, page, -1, (0, 255, 255), 3)

在这里插入图片描述

图 2.5-1 轮廓检测结果

2.6 角点检测

文档图像校正的最终目标是要进行文档区域的对齐(align),为了实现此目标,需要获取文档其余的四个角点坐标。通过轮廓检测后,已经获取到了文档图像的轮廓信息,进一步通过使用 c v 2. a p p r o x P o l y D P cv2.approxPolyDP cv2.approxPolyDP获取角点数据。实现过程如下:

# 对轮廓检测后的数据进行角点检测
con = np.zeros_like(img)
for c in page:
    # arcLength计算轮廓周长或曲线长度
  epsilon = 0.02 * cv2.arcLength(c, True)
  corners = cv2.approxPolyDP(c, epsilon, True)
  if len(corners) == 4:
      break
cv2.drawContours(con, c, -1, (0, 255, 255), 3)
cv2.drawContours(con, corners, -1, (0, 255, 0), 10)
corners = sorted(np.concatenate(corners).tolist())
 
for index, c in enumerate(corners):
  character = chr(65 + index)
  cv2.putText(con, character, tuple(c), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 1, cv2.LINE_AA)

在这里插入图片描述

图 2.6-1 角点检测结果

2.7 透视变换

至此,获取到了文档图像数据的四个角点坐标,利用 c v 2. g e t P e r s p e c t i v e T r a n s f o r m cv2.getPerspectiveTransform cv2.getPerspectiveTransform来对其进行透视变换,从而实现图像的对齐,得到校正之后的文档图像数据。

# 透视变换
M = cv2.getPerspectiveTransform(np.float32(corners), np.float32(destination_corners))
# Perspective transform using homography.
final = cv2.warpPerspective(orig_img, M, (destination_corners[2][0], destination_corners[2][1]), flags=cv2.INTER_LINEAR)

最终实现效果如下:

在这里插入图片描述

图 2.7-1 图像对齐效果

3、内容总结

至此,文档图像校正过程基本结束。基于此方法基本可以批量实现扭曲文档图像的校正处理,然后进行后去的文档智能任务将得到极大便捷,比如光学字符识别等。回归本文,相关内容总结如下:

  • 对OpenCV的基本使用"浅尝辄止",该工具库足够强大到难以想象,实践中积累;
  • 介绍了基本的形态学处理,包括腐蚀与膨胀操作,以及其组合操作,开闭操作;
  • 对边缘检测、轮廓检测进行了实践;
  • 基于GrabCut对文档图像做了分割处理,去掉了图像背景信息;
  • 局限:当文档前景对象与图像背景区域高度相似或融合、当图像区域未完全在整张图像区域内,则此种方法失效!
  • 疑问:此种方法符合进行效果的评估? 漏报率和错报率?
  • 后续:将结合相关文献,实践基于深度学习的文档图像校正方法,相关内容将发布在神经网络漫谈系列栏目。

4、参考文献

[1] 参考文献: 原文同步转载链接 。

[2] 周丽,冯百明,关煜,等. 面向智能手机拍摄的变形文档图像校正[J]. 计算机工程与科学,2022,44(1):102-109. DOI:10.3969/j.issn.1007-130X.2022.01.012.

[3] GrabCut算法:参考开源DOC链接.

5、版权声明

[1] 版权声明:本文为博主原创文章,转载或者引用本文内容请注明来源及原作者

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

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

相关文章

从零实现Dooring低代码印章组件

上一篇文章和大家分享了低代码平台组件间通信方案的几种实现:低代码平台组件间通信方案复盘今天继续和大家分享一下比较有意思的可视化印章组件的实现.你将收获低代码组件的基本设计模式印章组件的设计原理(canvas相关)如何快速将任意组件集成到低代码平台正文低代码组件的基本…

雷鸟X2:开启可量产全彩MicroLED光波导AR眼镜新起点

从最近的AR眼镜新品来看,采用MicroLED光波导方案已经成为了明显的趋势,可见业内对于光学的大方向还是非常统一的。不仅如此,各个厂商都拿出自己最优的方案来进行探索和验证,比如有的看重“极轻”、有的看重“视觉”、有的看重“价…

使用Jenkins一键打包部署 SpringBoot应用

一般而言,一个项目部署的由:拉取代码->构建->测试->打包->部署等过程组成,如果我们经常需要部署项目,特别是在微服务时代,服务特别多的情况下,不停的测试打包部署,那估计得有个人一…

数学:一夜读罢头飞雪

文章目录引子代数,几何与分析数学之美微积分形式的统一之美伽罗华群论的深刻之美几何的形体之美公理与定理集合论的公理欧几里得几何公理算术公理实数系的公理系统数学攀登的路径数学的符号系统希腊字母表物理与数学推荐的数学读物参考链接引子 贺新郎读史 人猿相揖…

【阶段二】Python数据分析数据可视化工具使用05篇:统计直方图、面积图与箱型图

本篇的思维导图: 统计直方图 统计直方图(histogram)形状类似柱形图,却有着与柱形图完全不同的含义。统计直方图涉及统计学的概念,首先要从数据中找出它的最大值和最小值,然后确定一个区间,使其包含全部测量数据,将区间分成若干个小区间,统计测量结果出现在各…

详细讲解Linux PCI驱动框架分析

说明: Kernel版本:4.14 ARM64处理器 使用工具:Source Insight 3.5, Visio 1. 概述 从本文开始,将会针对PCIe专题来展开,涉及的内容包括: PCI/PCIe总线硬件; Linux PCI驱动核心框…

通俗理解Platt scaling/Platt缩放/普拉特缩放

一、引言 最近在读论文的时候接触到Platt scaling,有点不理解这个概念。然后好奇心比较重,就看了一些科普,并追根溯源调查了一下Platt scaling。最终搞懂了这个概念,写个博客记录一下。中文翻译有看到:普拉特缩放&…

通信原理与MATLAB(十一):QAM的调制解调

目录1.QAM的调制原理2.QAM的解调原理3.QAM代码4.结果图5.特点1.QAM的调制原理 QAM调制原理如下图所示,基带码元波形经过串并转换分成I、Q两路,然后再经过电平转换(00转换成-1,01转换成-3,10转换成1,11转换成3),再与对应的载波相乘&#xff0…

scMDC:针对单细胞多模态数据进行聚类

目录摘要引言背景介绍单细胞数据聚类方法回顾ZINBscMDC摘要 单细胞多模态测序技术的发展是为了在同一细胞中同时分析不同模态的数据,它为在单细胞水平上联合分析多模态数据从而识别不同细胞类型提供了一个独特的机会。正确的聚类结果对于下游复杂生物功能研究至关重…

JavaEE多线程-认识多线程

目录一、认识操作系统二、认识进程三、内存管理四、什么是线程(Thread)?五、为什么要有线程?六、进程和线程的关系一、认识操作系统 我们需要简单了解一下操作系统。 操作系统是一组主管并控制计算机操作、运用和运行硬件、软件资源和提供公共服务来组织…

【Python】sklearn机器学习之DBSCAN聚类

文章目录基本原理测试构造函数基本原理 DBSCAN算法是比较经典的聚类算法了,除了sklearn之外,open3d这种常用的点云模块也提供了DBSCAN算法的实现,例如Open3d数据滤波和点云分割。 和其他聚类算法相比,DBSCAN存在一种去中心化的特…

六、Gtk4-Widgets (3)

1 Open 信号 1.1 G_APPLICATION_HANDLES_OPEN flag 在上一节中,我们使用GtkTextView、GtkTextBuffer和GtkScrolledWindow创建了一个非常简单的编辑器。我们将为程序添加文件读取功能,并将其改进为文件查看器。 要给出文件名,最简单的方法是…

(软考)系统架构师大纲

考试要求: 掌握计算机硬软件与网络的基础知识;熟悉信息系统开发过程;理解信息系统开发标准、常用信息技术标准;熟悉主流的中间件和应用服务器平台;掌握软件系统建模、系统架构设计基本技术;熟练掌握信息安全技术、安全策略、安全管理知识;了解信息化、信息技术有关…

使用Vite搭建vue3+TS项目

vite简介 vite 是一个基于 Vue3 单文件组件的非打包开发服务器,它具有快速的冷启动,不需要等待打包操作;并且官网说是下一代的前端构建工具。 初始化项目 npm init vitelatest1.输入项目名称 2.选择Vue 3.选择TS 4.启动项目 5.项目启…

【阶段三】Python机器学习07篇:模型评估函数介绍(回归模型)

本篇的思维导图: 模型评估函数介绍(回归模型) 绝对误差与相对误差: 设Y表示实际值, 表示预测值,则称E为绝对误差(Absolute Error),计算公式如式所示: e为相对误差(Relative Error),计算公式如式所示:

Maven怎么写本地仓库没有的架包坐标

什么是jar包的坐标? 当我们使用Maven开发一个项目时,需要向项目中导入很多个jar包,这些jar包不需要我们自己一个个的导入,只需要在创建的项目中的pom.xml文件中写上需要的jar包的坐标,Maven就会去本地仓库找有没有这个…

黑马学ElasticSearch(一)

目录: (1)初识ES-什么是elasticsearch (2)初识ES-倒排索引 (3)ES与MySQL的概念对比 (4)安装ES (1)初识ES-什么是elasticseach 随着业务的发…

MYSQL8.0+远程连接|主从复制配置|各种错误(吐血整理)

目录 环境介绍 主机/从机文件配置 主机部分 从机部分 连接测试 报错踩坑|解决办法 写在前面:最近在做项目优化,看完黑马的mysql的主从复制后,准备着手来练练,没想到这入坑就是三四天的错,心情烦躁。如今已解决&a…

SpringCloud笔记 - Day1 概念注册中心负载均衡

https://www.bilibili.com/video/BV1LQ4y127n4 1. 微服务导学 异步通信可以大大提高服务的并发。 服务的异常定位: 分布式日志服务系统监控和链路追踪 自动化部署:Jenkins——docker——k8s——RANCHER 持续集成 2. 微服务导学2 微服务治理、异步通…

【EHub_tx1_tx2_E100】Ubuntu18.04 + ROS_ Melodic + RS-LiDAR-16 激光雷达测试

简介:介绍 RS-LiDAR-16 16线激光雷达 在EHub_tx1_tx2_E100载板,TX1核心模块环境(Ubuntu18.04)下测试ROS驱动,如何打开使用RVIZ 查看点云数据,本文的前提条件是你的TX1里已经安装了ROS版本:Melo…