pdf2docx开发概要:矢量图处理¶
发布于:2021-06-26 | 分类:process automation
通常情况下,PDF提取出的路径Path
是一些直线/曲线描边(Stroke)或填充(Fill),可以用于表格边框/单元格背景、文字高亮/下划线等样式的解析。实际上,矢量图也是由这些路径组成的,这就可能出现如下问题:
-
对含有矢量图的路径进行表格解析,导致错误的、不存在的表格结构
-
PyMuPDF
提取的pixmap
并不包含矢量图,导致重建docx
时丢失矢量图
解决方案是识别和重建矢量图。技术强如Solid Document
,可以在Word中以Shape形式近乎完美重建矢量图;奈何本人水平有限,只能采用截图的形式截取矢量图区域,然后插入到Word中相应的位置。当然,截图前需要隐藏文字,以避免截图的文字和原来的文本重复。至此,关键的工作是识别矢量图区域——本文记录针对此问题探索的一些方案。
路径分组+曲线比例判据¶
这是<=0.5.2
版本一直采用的方案,基于**基本假设**:考虑到复杂图形/形状的展现离不开曲线,假设矢量图中必然存在 一定比例 的曲线路径。分为两步,同时也是两个关键点:
-
以是否相交为依据分组所有路径,每一组路径都是潜在的矢量图、表格区域,当然也可能是文本样式例如一条下划线
-
统计每一个分组中的曲线路径:
- 曲线路径数量的占比达到阈值(可自定义),该分组即被认为是矢量图,进而截图作为普通图片处理
- 否则,仅保留该分组中正交于坐标轴的路径,用于后续表格、文字样式的解析
(a) 以是否相交为依据分组所有路径¶
图是解决这个问题的直接手段:
- 每一条路径看作图的
顶点
,两条路径是否相交构成了边
- 于是,所有路径及其连接关系构成了一个
非连通图
- 遍历这个非连通图得到每一个
连通分量
,即为每一个分组
关键点在于建立这个图,即以 任意两条路径是否相交 为依据建立图的邻接列表表示。为降低复杂度,引入简化处理:判断路径的包络矩形是否相交。注意本文提及的包络矩形Boundary Box
都是平行于坐标轴的(ISO-oriented
)。
具体细节参考:
(b) 以曲线路径(语义上)数量比例为依据判定矢量图¶
通常,表格的边框/背景、文本样式如高亮/下划线等都是水平或者竖直的路径;但是存在例外情况,例如某些PDF编辑器的文本高亮注释是一个 圆角矩形 填充区域——它的边界由四段圆角曲线和各边的直线路径组成,几何上它属于曲线,但语义上倾向于用于文本样式解析的普通矩形。所以,我们需要从语义的角度区分几何上的曲线路径。
定义语义上的曲线路径为:
路径围成面积与包络矩形面积之比小于阈值(例如0.95)。
曲线围成面积的计算
PDF中的曲线路径由c
、v
、y
等算符描述的贝塞尔曲线表示。根据PDF给出的4个控制点计算参数方程,进而采样曲线上一系列的点,并根据Shoelace formula计算面积。
最后,统计每一个分组中语义曲线路径数量的占比,一旦超过某个阈值,就认为这个分组的所有路径组成了矢量图。
这个方案的缺点很明显:
-
如果一副矢量图存在孤立的局部特征,将被错误地拆分为多个分组
-
如果表格的单元格内嵌套着矢量图,该矢量图将被丢弃
递归投影分割+子轮廓+曲线比例判据¶
当前测试中的方案,需要python-opency
支持。基本思路:
-
隐藏文本和普通图片,截图整个页面并进行二值化后作为图片输入
-
递归投影分割页面,得到一些列子区域
-
针对每一个子区域
bbox
,用opencv
查找所有轮廓,提取其中level-2级别的子轮廓inner_bboxes
-
检查包含于
bbox
但 不存在于inner_bboxes
中的路径集合P
,-
如果曲线路径(语义)数量的占比达到阈值,则认为该子区域为矢量图,进而截取页面的
bbox
区域作为位图处理 -
否则,导出路径集合
P
作进一步表格边框/文本样式解析,同时截取inner_bboxes
子区域的嵌套矢量图
-
其中,递归投影分割(recursive xy cut)解决前一方案遗留的矢量图局部特征问题,通过设置分割的间隙参数合并邻近的本属于同一矢量图的子区域。关于递归投影分割算法的细节参考:
提取level-2子轮廓的理解
旨在解决表格中嵌套矢量图的问题。
-
如果当前区域为表格,且某个单元格中存在一张矢量图,则level-0为表格外轮廓,level-1为表格内轮廓即单元格轮廓,于是level-2为潜在的单元格内矢量图的轮廓。这也是判断路径时排除level-2级轮廓的原因所在。
-
如果当前区域为矢量图,则一般情况下不存在level-2轮廓,从而并不影响判断逻辑。
注意opency
轮廓层级的一个细节:
如果单元格内矢量图与单元格边框之间的距离很小,本应属于level-2的矢量图轮廓将被分配到level-1级,即与包含它的单元格轮廓在同一级。因此,实际操作中注意将包含于其他同级轮廓的伪level-1轮廓考虑到level-2轮廓中去;相应地,排除level-2中包含于该伪level-1级的轮廓,因为它实际上属于level-3了。
相比从路径本身出发的路径分组方案,基于opencv
图像处理的递归投影分割+子轮廓方案表现出了更好的稳定性,但是依旧无法摆脱基于规则的方法的局限性——总是存在例外情况,例如:一副不包含任何曲线路径的柱状图。
递归投影分割+CNN分类¶
待探索的方向。
opencv
支持tensorflow
模型奠定了此方案部署上的可行性,剩下需要解决的两个关键问题:
-
数据集的准备
-
模型及精度