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)。

具体细节参考:

求解矩形相交问题 Rectangle-Intersection-Problem

(b) 以曲线路径(语义上)数量比例为依据判定矢量图

通常,表格的边框/背景、文本样式如高亮/下划线等都是水平或者竖直的路径;但是存在例外情况,例如某些PDF编辑器的文本高亮注释是一个 圆角矩形 填充区域——它的边界由四段圆角曲线和各边的直线路径组成,几何上它属于曲线,但语义上倾向于用于文本样式解析的普通矩形。所以,我们需要从语义的角度区分几何上的曲线路径。

定义语义上的曲线路径为:

路径围成面积与包络矩形面积之比小于阈值(例如0.95)。

曲线围成面积的计算

PDF中的曲线路径由cvy等算符描述的贝塞尔曲线表示。根据PDF给出的4个控制点计算参数方程,进而采样曲线上一系列的点,并根据Shoelace formula计算面积。

最后,统计每一个分组中语义曲线路径数量的占比,一旦超过某个阈值,就认为这个分组的所有路径组成了矢量图。

这个方案的缺点很明显:

  • 如果一副矢量图存在孤立的局部特征,将被错误地拆分为多个分组

  • 如果表格的单元格内嵌套着矢量图,该矢量图将被丢弃

递归投影分割+子轮廓+曲线比例判据

当前测试中的方案,需要python-opency支持。基本思路:

  • 隐藏文本和普通图片,截图整个页面并进行二值化后作为图片输入

  • 递归投影分割页面,得到一些列子区域

  • 针对每一个子区域bbox,用opencv查找所有轮廓,提取其中level-2级别的子轮廓inner_bboxes

  • 检查包含于bbox不存在于 inner_bboxes中的路径集合P

    • 如果曲线路径(语义)数量的占比达到阈值,则认为该子区域为矢量图,进而截取页面的bbox区域作为位图处理

    • 否则,导出路径集合P作进一步表格边框/文本样式解析,同时截取inner_bboxes子区域的嵌套矢量图

其中,递归投影分割(recursive xy cut)解决前一方案遗留的矢量图局部特征问题,通过设置分割的间隙参数合并邻近的本属于同一矢量图的子区域。关于递归投影分割算法的细节参考:

递归投影分割算法 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模型奠定了此方案部署上的可行性,剩下需要解决的两个关键问题:

  • 数据集的准备

  • 模型及精度