跳转至

通用表格识别v2产线使用教程

1. 通用表格识别v2产线介绍

表格识别是一种自动从文档或图像中识别和提取表格内容及其结构的技术,广泛应用于数据录入、信息检索和文档分析等领域。通过使用计算机视觉和机器学习算法,表格识别能够将复杂的表格信息转换为可编辑的格式,方便用户进一步处理和分析数据。

通用表格识别v2产线(PP-TableMagic)用于解决表格识别任务,对图片中的表格进行识别,并以HTML格式输出。与通用表格识别产线不同,本产线新引入了表格分类和表格单元格检测两个模块,通过采用“表格分类+表格结构识别+单元格检测”多模型串联组网方案,实现了相比通用表格识别产线更好的端到端表格识别性能。基于此,通用表格识别v2产线原生支持针对性地模型微调,各类开发者均能对通用表格识别v2产线进行不同程度的自定义微调,使其在不同应用场景下都能得到令人满意的性能。除此之外,通用表格识别v2产线同样支持使用端到端表格结构识别模型(例如 SLANet、SLANet_plus 等),并且支持有线表、无线表独立配置表格识别方式,开发者可以自由选取和组合最佳的表格识别方案。

本产线的使用场景覆盖通用、制造、金融、交通等各个领域。本产线同时提供了灵活的服务化部署方式,支持在多种硬件上使用多种编程语言调用。不仅如此,本产线也提供了二次开发的能力,您可以基于本产线在您自己的数据集上训练调优,训练后的模型也可以无缝集成。

通用表格识别产线v2中包含必选的表格结构识别模块、表格分类模块、表格单元格定位模块、文本检测模块和文本识别模块,以及可选的版面区域检测模块、文档图像方向分类模块和文本图像矫正模块

如果您更注重模型的精度,请选择精度较高的模型;如果您更在意模型的推理速度,请选择推理速度较快的模型;如果您关注模型的存储大小,请选择存储体积较小的模型。

👉模型列表详情

表格结构识别模块模型:

模型模型下载链接 精度(%) GPU推理耗时(ms)
[常规模式 / 高性能模式]
CPU推理耗时(ms)
[常规模式 / 高性能模式]
模型存储大小(MB) 介绍
SLANeXt_wired 推理模型/训练模型 69.65 85.92 / 85.92 - / 501.66 351M SLANeXt 系列是百度飞桨视觉团队自研的新一代表格结构识别模型。相较于 SLANet 和 SLANet_plus,SLANeXt 专注于对表格结构进行识别,并且对有线表格(wired)和无线表格(wireless)的识别分别训练了专用的权重,对各类型表格的识别能力都得到了明显提高,特别是对有线表格的识别能力得到了大幅提升。
SLANeXt_wireless 推理模型/训练模型

表格分类模块模型:

模型模型下载链接 Top1 Acc(%) GPU推理耗时(ms)
[常规模式 / 高性能模式]
CPU推理耗时(ms)
[常规模式 / 高性能模式]
模型存储大小(MB)
PP-LCNet_x1_0_table_cls 推理模型/训练模型 94.2 2.62 / 0.60 3.17 / 1.14 6.6

表格单元格检测模块模型:

模型模型下载链接 mAP(%) GPU推理耗时(ms)
[常规模式 / 高性能模式]
CPU推理耗时(ms)
[常规模式 / 高性能模式]
模型存储大小(MB) 介绍
RT-DETR-L_wired_table_cell_det 推理模型/训练模型 82.7 33.47 / 27.02 402.55 / 256.56 124M RT-DETR 是第一个实时的端到端目标检测模型。百度飞桨视觉团队基于 RT-DETR-L 作为基础模型,在自建表格单元格检测数据集上完成预训练,实现了对有线表格、无线表格均有较好性能的表格单元格检测。
RT-DETR-L_wireless_table_cell_det 推理模型/训练模型

文本检测模块模型:

模型模型下载链接 检测Hmean(%) GPU推理耗时(ms)
[常规模式 / 高性能模式]
CPU推理耗时(ms)
[常规模式 / 高性能模式]
模型存储大小(MB) 介绍
PP-OCRv5_server_det 推理模型/训练模型 83.8 89.55 / 70.19 383.15 / 383.15 84.3 PP-OCRv5 的服务端文本检测模型,精度更高,适合在性能较好的服务器上部署
PP-OCRv5_mobile_det 推理模型/训练模型 79.0 10.67 / 6.36 57.77 / 28.15 4.7 PP-OCRv5 的移动端文本检测模型,效率更高,适合在端侧设备部署
PP-OCRv4_server_det 推理模型/训练模型 69.2 127.82 / 98.87 585.95 / 489.77 109 PP-OCRv4 的服务端文本检测模型,精度更高,适合在性能较好的服务器上部署
PP-OCRv4_mobile_det 推理模型/训练模型 63.8 9.87 / 4.17 56.60 / 20.79 4.7 PP-OCRv4 的移动端文本检测模型,效率更高,适合在端侧设备部署

文本识别模块模型:

模型模型下载链接 识别 Avg Accuracy(%) GPU推理耗时(ms)
[常规模式 / 高性能模式]
CPU推理耗时(ms)
[常规模式 / 高性能模式]
模型存储大小(MB) 介绍
PP-OCRv5_server_rec 推理模型/训练模型 86.38 8.46 / 2.36 31.21 / 31.21 81 PP-OCRv5_rec 是新一代文本识别模型。该模型致力于以单一模型高效、精准地支持简体中文、繁体中文、英文、日文四种主要语言,以及手写、竖版、拼音、生僻字等复杂文本场景的识别。在保持识别效果的同时,兼顾推理速度和模型鲁棒性,为各种场景下的文档理解提供高效、精准的技术支撑。
PP-OCRv5_mobile_rec 推理模型/训练模型 81.29 5.43 / 1.46 21.20 / 5.32 16
PP-OCRv4_server_rec_doc 推理模型/训练模型 86.58 8.69 / 2.78 37.93 / 37.93 182 PP-OCRv4_server_rec_doc是在PP-OCRv4_server_rec的基础上,在更多中文文档数据和PP-OCR训练数据的混合数据训练而成,增加了部分繁体字、日文、特殊字符的识别能力,可支持识别的字符为1.5万+,除文档相关的文字识别能力提升外,也同时提升了通用文字的识别能力
PP-OCRv4_mobile_rec 推理模型/训练模型 78.74 5.26 / 1.12 17.48 / 3.61 10.5 PP-OCRv4的轻量级识别模型,推理效率高,可以部署在包含端侧设备的多种硬件设备中
PP-OCRv4_server_rec 推理模型/训练模型 85.19 8.75 / 2.49 36.93 / 36.93 173 PP-OCRv4的服务器端模型,推理精度高,可以部署在多种不同的服务器上
en_PP-OCRv4_mobile_rec 推理模型/训练模型 70.39 4.81 / 1.23 17.20 / 4.18 7.5 基于PP-OCRv4识别模型训练得到的超轻量英文识别模型,支持英文、数字识别
> ❗ 以上列出的是文本识别模块重点支持的4个核心模型,该模块总共支持18个全量模型,包含多个多语言文本识别模型,完整的模型列表如下:
👉模型列表详情 * PP-OCRv5 多场景模型
模型模型下载链接 中文识别 Avg Accuracy(%) 英文识别 Avg Accuracy(%) 繁体中文识别 Avg Accuracy(%) 日文识别 Avg Accuracy(%) GPU推理耗时(ms)
[常规模式 / 高性能模式]
CPU推理耗时(ms)
[常规模式 / 高性能模式]
模型存储大小(MB) 介绍
PP-OCRv5_server_rec 推理模型/训练模型 86.38 64.70 93.29 60.35 8.46 / 2.36 31.21 / 31.21 81 PP-OCRv5_rec 是新一代文本识别模型。该模型致力于以单一模型高效、精准地支持简体中文、繁体中文、英文、日文四种主要语言,以及手写、竖版、拼音、生僻字等复杂文本场景的识别。在保持识别效果的同时,兼顾推理速度和模型鲁棒性,为各种场景下的文档理解提供高效、精准的技术支撑。
PP-OCRv5_mobile_rec 推理模型/训练模型 81.29 66.00 83.55 54.65 5.43 / 1.46 21.20 / 5.32 16
* 中文识别模型
模型模型下载链接 识别 Avg Accuracy(%) GPU推理耗时(ms)
[常规模式 / 高性能模式]
CPU推理耗时(ms)
[常规模式 / 高性能模式]
模型存储大小(MB) 介绍
PP-OCRv4_server_rec_doc 推理模型/训练模型 86.58 8.69 / 2.78 37.93 / 37.93 182 PP-OCRv4_server_rec_doc是在PP-OCRv4_server_rec的基础上,在更多中文文档数据和PP-OCR训练数据的混合数据训练而成,增加了部分繁体字、日文、特殊字符的识别能力,可支持识别的字符为1.5万+,除文档相关的文字识别能力提升外,也同时提升了通用文字的识别能力
PP-OCRv4_mobile_rec 推理模型/训练模型 78.74 5.26 / 1.12 17.48 / 3.61 10.5 PP-OCRv4的轻量级识别模型,推理效率高,可以部署在包含端侧设备的多种硬件设备中
PP-OCRv4_server_rec 推理模型/训练模型 85.19 8.75 / 2.49 36.93 / 36.93 173 PP-OCRv4的服务器端模型,推理精度高,可以部署在多种不同的服务器上
PP-OCRv3_mobile_rec 推理模型/训练模型 72.96 3.89 / 1.16 8.72 / 3.56 10.3 PP-OCRv3的轻量级识别模型,推理效率高,可以部署在包含端侧设备的多种硬件设备中
模型模型下载链接 识别 Avg Accuracy(%) GPU推理耗时(ms)
[常规模式 / 高性能模式]
CPU推理耗时(ms)
[常规模式 / 高性能模式]
模型存储大小(MB) 介绍
ch_SVTRv2_rec 推理模型/训练模型 68.81 10.38 / 8.31 66.52 / 30.83 80.5 SVTRv2 是一种由复旦大学视觉与学习实验室(FVL)的OpenOCR团队研发的服务端文本识别模型,其在PaddleOCR算法模型挑战赛 - 赛题一:OCR端到端识别任务中荣获一等奖,A榜端到端识别精度相比PP-OCRv4提升6%。
模型模型下载链接 识别 Avg Accuracy(%) GPU推理耗时(ms)
[常规模式 / 高性能模式]
CPU推理耗时(ms)
[常规模式 / 高性能模式]
模型存储大小(MB) 介绍
ch_RepSVTR_rec 推理模型/训练模型 65.07 6.29 / 1.57 20.64 / 5.40 48.8 RepSVTR 文本识别模型是一种基于SVTRv2 的移动端文本识别模型,其在PaddleOCR算法模型挑战赛 - 赛题一:OCR端到端识别任务中荣获一等奖,B榜端到端识别精度相比PP-OCRv4提升2.5%,推理速度持平。
* 英文识别模型
模型模型下载链接 识别 Avg Accuracy(%) GPU推理耗时(ms)
[常规模式 / 高性能模式]
CPU推理耗时(ms)
[常规模式 / 高性能模式]
模型存储大小(MB) 介绍
en_PP-OCRv4_mobile_rec 推理模型/训练模型 70.39 4.81 / 1.23 17.20 / 4.18 7.5 基于PP-OCRv4识别模型训练得到的超轻量英文识别模型,支持英文、数字识别
en_PP-OCRv3_mobile_rec 推理模型/训练模型 70.69 3.56 / 0.78 8.44 / 5.78 17.3 基于PP-OCRv3识别模型训练得到的超轻量英文识别模型,支持英文、数字识别
* 多语言识别模型
模型模型下载链接 识别 Avg Accuracy(%) GPU推理耗时(ms)
[常规模式 / 高性能模式]
CPU推理耗时(ms)
[常规模式 / 高性能模式]
模型存储大小(MB) 介绍
korean_PP-OCRv3_mobile_rec 推理模型/训练模型 60.21 3.73 / 0.98 8.76 / 2.91 9.6 基于PP-OCRv3识别模型训练得到的超轻量韩文识别模型,支持韩文、数字识别
japan_PP-OCRv3_mobile_rec 推理模型/训练模型 45.69 3.86 / 1.01 8.62 / 2.92 9.8 基于PP-OCRv3识别模型训练得到的超轻量日文识别模型,支持日文、数字识别
chinese_cht_PP-OCRv3_mobile_rec 推理模型/训练模型 82.06 3.90 / 1.16 9.24 / 3.18 10.8 基于PP-OCRv3识别模型训练得到的超轻量繁体中文识别模型,支持繁体中文、数字识别
te_PP-OCRv3_mobile_rec 推理模型/训练模型 95.88 3.59 / 0.81 8.28 / 6.21 8.7 基于PP-OCRv3识别模型训练得到的超轻量泰卢固文识别模型,支持泰卢固文、数字识别
ka_PP-OCRv3_mobile_rec 推理模型/训练模型 96.96 3.49 / 0.89 8.63 / 2.77 17.4 基于PP-OCRv3识别模型训练得到的超轻量卡纳达文识别模型,支持卡纳达文、数字识别
ta_PP-OCRv3_mobile_rec 推理模型/训练模型 76.83 3.49 / 0.86 8.35 / 3.41 8.7 基于PP-OCRv3识别模型训练得到的超轻量泰米尔文识别模型,支持泰米尔文、数字识别
latin_PP-OCRv3_mobile_rec 推理模型/训练模型 76.93 3.53 / 0.78 8.50 / 6.83 8.7 基于PP-OCRv3识别模型训练得到的超轻量拉丁文识别模型,支持拉丁文、数字识别
arabic_PP-OCRv3_mobile_rec 推理模型/训练模型 73.55 3.60 / 0.83 8.44 / 4.69 17.3 基于PP-OCRv3识别模型训练得到的超轻量阿拉伯字母识别模型,支持阿拉伯字母、数字识别
cyrillic_PP-OCRv3_mobile_rec 推理模型/训练模型 94.28 3.56 / 0.79 8.22 / 2.76 8.7 基于PP-OCRv3识别模型训练得到的超轻量斯拉夫字母识别模型,支持斯拉夫字母、数字识别
devanagari_PP-OCRv3_mobile_rec 推理模型/训练模型 96.44 3.60 / 0.78 6.95 / 2.87 8.7 基于PP-OCRv3识别模型训练得到的超轻量梵文字母识别模型,支持梵文字母、数字识别
模型模型下载链接 mAP(0.5)(%) GPU推理耗时(ms)
[常规模式 / 高性能模式]
CPU推理耗时(ms)
[常规模式 / 高性能模式]
模型存储大小(MB) 介绍
PP-DocLayout-L 推理模型/训练模型 90.4 33.59 / 33.59 503.01 / 251.08 123.76 基于RT-DETR-L在包含中英文论文、杂志、合同、书本、试卷和研报等场景的自建数据集训练的高精度版面区域定位模型
PP-DocLayout-M 推理模型/训练模型 75.2 13.03 / 4.72 43.39 / 24.44 22.578 基于PicoDet-L在包含中英文论文、杂志、合同、书本、试卷和研报等场景的自建数据集训练的精度效率平衡的版面区域定位模型
PP-DocLayout-S 推理模型/训练模型 70.9 11.54 / 3.86 18.53 / 6.29 4.834 基于PicoDet-S在中英文论文、杂志、合同、书本、试卷和研报等场景上自建数据集训练的高效率版面区域定位模型
> ❗ 以上列出的是版面检测模块重点支持的3个核心模型,该模块总共支持11个全量模型,包含多个预定义了不同类别的模型,完整的模型列表如下:
👉模型列表详情 * 表格版面检测模型
模型模型下载链接 mAP(0.5)(%) GPU推理耗时(ms)
[常规模式 / 高性能模式]
CPU推理耗时(ms)
[常规模式 / 高性能模式]
模型存储大小(MB) 介绍
PicoDet_layout_1x_table 推理模型/训练模型 97.5 9.57 / 6.63 27.66 / 16.75 7.4 基于PicoDet-1x在自建数据集训练的高效率版面区域定位模型,可定位表格这1类区域
* 3类版面检测模型,包含表格、图像、印章
模型模型下载链接 mAP(0.5)(%) GPU推理耗时(ms)
[常规模式 / 高性能模式]
CPU推理耗时(ms)
[常规模式 / 高性能模式]
模型存储大小(MB) 介绍
PicoDet-S_layout_3cls 推理模型/训练模型 88.2 8.43 / 3.44 17.60 / 6.51 4.8 基于PicoDet-S轻量模型在中英文论文、杂志和研报等场景上自建数据集训练的高效率版面区域定位模型
PicoDet-L_layout_3cls 推理模型/训练模型 89.0 12.80 / 9.57 45.04 / 23.86 22.6 基于PicoDet-L在中英文论文、杂志和研报等场景上自建数据集训练的效率精度均衡版面区域定位模型
RT-DETR-H_layout_3cls 推理模型/训练模型 95.8 114.80 / 25.65 924.38 / 924.38 470.1 基于RT-DETR-H在中英文论文、杂志和研报等场景上自建数据集训练的高精度版面区域定位模型
* 5类英文文档区域检测模型,包含文字、标题、表格、图片以及列表
模型模型下载链接 mAP(0.5)(%) GPU推理耗时(ms)
[常规模式 / 高性能模式]
CPU推理耗时(ms)
[常规模式 / 高性能模式]
模型存储大小(MB) 介绍
PicoDet_layout_1x 推理模型/训练模型 97.8 9.62 / 6.75 26.96 / 12.77 7.4 基于PicoDet-1x在PubLayNet数据集训练的高效率英文文档版面区域定位模型
* 17类区域检测模型,包含17个版面常见类别,分别是:段落标题、图片、文本、数字、摘要、内容、图表标题、公式、表格、表格标题、参考文献、文档标题、脚注、页眉、算法、页脚、印章
模型模型下载链接 mAP(0.5)(%) GPU推理耗时(ms)
[常规模式 / 高性能模式]
CPU推理耗时(ms)
[常规模式 / 高性能模式]
模型存储大小(MB) 介绍
PicoDet-S_layout_17cls 推理模型/训练模型 87.4 8.80 / 3.62 17.51 / 6.35 4.8 基于PicoDet-S轻量模型在中英文论文、杂志和研报等场景上自建数据集训练的高效率版面区域定位模型
PicoDet-L_layout_17cls 推理模型/训练模型 89.0 12.60 / 10.27 43.70 / 24.42 22.6 基于PicoDet-L在中英文论文、杂志和研报等场景上自建数据集训练的效率精度均衡版面区域定位模型
RT-DETR-H_layout_17cls 推理模型/训练模型 98.3 115.29 / 101.18 964.75 / 964.75 470.2 基于RT-DETR-H在中英文论文、杂志和研报等场景上自建数据集训练的高精度版面区域定位模型

文本图像矫正模块模型(可选):

模型模型下载链接 CER GPU推理耗时(ms)
[常规模式 / 高性能模式]
CPU推理耗时(ms)
[常规模式 / 高性能模式]
模型存储大小(MB) 介绍
UVDoc 推理模型/训练模型 0.179 19.05 / 19.05 - / 869.82 30.3 高精度文本图像矫正模型

文档图像方向分类模块模型(可选):

模型模型下载链接 Top-1 Acc(%) GPU推理耗时(ms)
[常规模式 / 高性能模式]
CPU推理耗时(ms)
[常规模式 / 高性能模式]
模型存储大小(MB) 介绍
PP-LCNet_x1_0_doc_ori 推理模型/训练模型 99.06 2.62 / 0.59 3.24 / 1.19 7 基于PP-LCNet_x1_0的文档图像分类模型,含有四个类别,即0度,90度,180度,270度
测试环境说明:
  • 性能测试环境
    • 测试数据集:
      • 文档图像方向分类模型:PaddleX 自建的数据集,覆盖证件和文档等多个场景,包含 1000 张图片。
      • 版面区域检测模型:PaddleOCR 自建的版面区域检测数据集,包含中英文论文、杂志、合同、书本、试卷和研报等常见的 500 张文档类型图片。
      • 表格版面检测模型:PaddleOCR 自建的版面表格区域检测数据集,包含中英文 7835 张带有表格的论文文档类型图片。
      • 3类版面检测模型:PaddleOCR 自建的版面区域检测数据集,包含中英文论文、杂志和研报等常见的 1154 张文档类型图片。
      • 5类英文文档区域检测模型:PubLayNet 的评估数据集,包含英文文档的 11245 张图片。
      • 17类区域检测模型:PaddleOCR 自建的版面区域检测数据集,包含中英文论文、杂志和研报等常见的 892 张文档类型图片。
      • 表格结构识别模型:PaddleX 内部自建高难度中文表格识别数据集。
      • 表格单元格检测模型:PaddleX 内部自建评测集。
      • 表格分类模型:PaddleX 内部自建评测集。
      • 文本检测模型:PaddleOCR 自建的中文数据集,覆盖街景、网图、文档、手写多个场景,其中检测包含 500 张图片。
      • 中文识别模型: PaddleOCR 自建的中文数据集,覆盖街景、网图、文档、手写多个场景,其中文本识别包含 1.1w 张图片。
      • ch_SVTRv2_rec:PaddleOCR算法模型挑战赛 - 赛题一:OCR端到端识别任务A榜评估集。
      • ch_RepSVTR_rec:PaddleOCR算法模型挑战赛 - 赛题一:OCR端到端识别任务B榜评估集。
      • 英文识别模型:PaddleX 自建的英文数据集。
      • 多语言识别模型:PaddleX 自建的多语种数据集。
    • 硬件配置:
      • GPU:NVIDIA Tesla T4
      • CPU:Intel Xeon Gold 6271C @ 2.60GHz
      • 其他环境:Ubuntu 20.04 / CUDA 11.8 / cuDNN 8.9 / TensorRT 8.6.1.6
  • 推理模式说明
模式 GPU配置 CPU配置 加速技术组合
常规模式 FP32精度 / 无TRT加速 FP32精度 / 8线程 PaddleInference
高性能模式 选择先验精度类型和加速策略的最优组合 FP32精度 / 8线程 选择先验最优后端(Paddle/OpenVINO/TRT等)

2. 快速开始

PaddleX 所提供的模型产线均可以快速体验效果,你可以在本地使用命令行或 Python 体验通用表格识别v2产线的效果。

2.1 在线体验

暂不支持在线体验。

2.2 本地体验

在本地使用通用表格识别v2产线前,请确保您已经按照PaddleX本地安装教程完成了PaddleX的wheel包安装。如果您希望选择性安装依赖,请参考安装教程中的相关说明。该产线对应的依赖分组为 ocr

2.1 命令行方式体验

一行命令即可快速体验表格识别产线效果,使用 测试文件,并将 --input 替换为本地路径,进行预测

paddlex --pipeline table_recognition_v2 \
        --use_doc_orientation_classify=False \
        --use_doc_unwarping=False \
        --input table_recognition_v2.jpg \
        --save_path ./output \
        --device gpu:0

注:PaddleX 官方模型默认从 HuggingFace 获取,如运行环境访问 HuggingFace 不便,可通过环境变量修改模型源为 BOS:PADDLE_PDX_MODEL_SOURCE="BOS",未来将支持更多主流模型源;

相关的参数说明可以参考2.2 Python脚本方式集成中的参数说明。支持同时指定多个设备以进行并行推理,详情请参考 产线并行推理

👉 运行后,得到的结果为:(点击展开)
{'res': {'input_path': 'table_recognition_v2.jpg', 'page_index': None, 'model_settings': {'use_doc_preprocessor': False, 'use_layout_detection': True, 'use_ocr_model': True}, 'layout_det_res': {'input_path': None, 'page_index': None, 'boxes': [{'cls_id': 8, 'label': 'table', 'score': 0.86655592918396, 'coordinate': [0.0125130415, 0.41920784, 1281.3737, 585.3884]}]}, 'overall_ocr_res': {'input_path': None, 'page_index': None, 'model_settings': {'use_doc_preprocessor': False, 'use_textline_orientation': False}, 'dt_polys': array([[[   9,   21],
        ...,
        [   9,   59]],

       ...,

       [[1046,  536],
        ...,
        [1046,  573]]], dtype=int16), 'text_det_params': {'limit_side_len': 960, 'limit_type': 'max', 'thresh': 0.3, 'box_thresh': 0.6, 'unclip_ratio': 2.0}, 'text_type': 'general', 'textline_orientation_angles': array([-1, ..., -1]), 'text_rec_score_thresh': 0, 'rec_texts': ['部门', '报销人', '报销事由', '批准人:', '单据', '张', '合计金额', '元', '车费票', '其', '火车费票', '飞机票', '中', '旅住宿费', '其他', '补贴'], 'rec_scores': array([0.99958128, ..., 0.99317062]), 'rec_polys': array([[[   9,   21],
        ...,
        [   9,   59]],

       ...,

       [[1046,  536],
        ...,
        [1046,  573]]], dtype=int16), 'rec_boxes': array([[   9, ...,   59],
       ...,
       [1046, ...,  573]], dtype=int16)}, 'table_res_list': [{'cell_box_list': [array([ 0.13052222, ..., 73.08310249]), array([104.43082511, ...,  73.27777413]), array([319.39041221, ...,  73.30439308]), array([424.2436837 , ...,  73.44736794]), array([580.75836265, ...,  73.24003914]), array([723.04370201, ...,  73.22717598]), array([984.67315757, ...,  73.20420387]), array([1.25130415e-02, ..., 5.85419208e+02]), array([984.37072837, ..., 137.02281502]), array([984.26586998, ..., 201.22290352]), array([984.24017417, ..., 585.30775765]), array([1039.90606773, ...,  265.44664314]), array([1039.69549644, ...,  329.30540779]), array([1039.66546714, ...,  393.57319954]), array([1039.5122689 , ...,  457.74644783]), array([1039.55535972, ...,  521.73030403]), array([1039.58612144, ...,  585.09468392])], 'pred_html': '<html><body><table><tbody><tr><td>部门</td><td></td><td>报销人</td><td></td><td>报销事由</td><td></td><td colspan="2">批准人:</td></tr><tr><td colspan="6" rowspan="8"></td><td colspan="2">单据 张</td></tr><tr><td colspan="2">合计金额 元</td></tr><tr><td rowspan="6">其 中</td><td>车费票</td></tr><tr><td>火车费票</td></tr><tr><td>飞机票</td></tr><tr><td>旅住宿费</td></tr><tr><td>其他</td></tr><tr><td>补贴</td></tr></tbody></table></body></html>', 'table_ocr_pred': {'rec_polys': array([[[   9,   21],
        ...,
        [   9,   59]],

       ...,

       [[1046,  536],
        ...,
        [1046,  573]]], dtype=int16), 'rec_texts': ['部门', '报销人', '报销事由', '批准人:', '单据', '张', '合计金额', '元', '车费票', '其', '火车费票', '飞机票', '中', '旅住宿费', '其他', '补贴'], 'rec_scores': array([0.99958128, ..., 0.99317062]), 'rec_boxes': array([[   9, ...,   59],
       ...,
       [1046, ...,  573]], dtype=int16)}}]}}
运行结果参数说明可以参考[2.2 Python脚本方式集成](#22-python脚本方式集成)中的结果解释。 可视化结果保存在`save_path`下,其中表格识别的可视化结果如下:

2.2 Python脚本方式集成

  • 上述命令行是为了快速体验查看效果,一般来说,在项目中,往往需要通过代码集成,您可以通过几行代码即可完成产线的快速推理,推理代码如下:
from paddlex import create_pipeline

pipeline = create_pipeline(pipeline="table_recognition_v2")

output = pipeline.predict(
    input="table_recognition_v2.jpg",
    use_doc_orientation_classify=False,
    use_doc_unwarping=False,
)

for res in output:
    res.print()
    res.save_to_img("./output/")
    res.save_to_xlsx("./output/")
    res.save_to_html("./output/")
    res.save_to_json("./output/")

在上述 Python 脚本中,执行了如下几个步骤:

(1)通过 create_pipeline() 实例化通用表格识别v2产线对象,具体参数说明如下:

参数 参数说明 参数类型 默认值
pipeline 产线名称或是产线配置文件路径。如为产线名称,则必须为 PaddleX 所支持的产线。 str None
config 产线具体的配置信息(如果和pipeline同时设置,优先级高于pipeline,且要求产线名和pipeline一致)。 dict[str, Any] None
device 产线推理设备。支持指定GPU具体卡号,如“gpu:0”,其他硬件具体卡号,如“npu:0”,CPU如“cpu”。支持同时指定多个设备以进行并行推理,详情请参考产线并行推理文档。 str gpu:0
use_hpip 是否启用高性能推理插件。如果为 None,则使用配置文件或 config 中的配置。 bool | None None
hpi_config 高性能推理配置 dict | None None

(2)调用通用表格识别v2产线对象的 predict() 方法进行推理预测。该方法将返回一个 generator。以下是 predict() 方法的参数及其说明:

参数 参数说明 参数类型 可选项 默认值
input 待预测数据,支持多种输入类型,必填 Python Var|str|list
  • Python Var:如 numpy.ndarray 表示的图像数据
  • str:如图像文件或者PDF文件的本地路径:/root/data/img.jpg如URL链接,如图像文件或PDF文件的网络URL:示例如本地目录,该目录下需包含待预测图像,如本地路径:/root/data/(当前不支持目录中包含PDF文件的预测,PDF文件需要指定到具体文件路径)
  • List:列表元素需为上述类型数据,如[numpy.ndarray, numpy.ndarray][\"/root/data/img1.jpg\", \"/root/data/img2.jpg\"][\"/root/data1\", \"/root/data2\"]
None
use_doc_orientation_classify 是否使用文档方向分类模块 bool|None
  • boolTrue 或者 False
  • None:如果设置为None, 将默认使用产线初始化的该参数值,初始化为True
None
use_doc_unwarping 是否使用文档扭曲矫正模块 bool|None
  • boolTrue 或者 False
  • None:如果设置为None, 将默认使用产线初始化的该参数值,初始化为True
None
use_layout_detection 是否使用版面检测模块 bool|None
  • boolTrue 或者 False
  • None:如果设置为None, 将默认使用产线初始化的该参数值,初始化为True
None
text_det_limit_side_len 文本检测的图像边长限制 int|None
  • int:大于 0 的任意整数;
  • None:如果设置为 None, 将默认使用产线初始化的该参数值,初始化为 960
None
text_det_limit_type 文本检测的图像边长限制类型 str|None
  • str:支持 minmaxmin 表示保证图像最短边不小于 det_limit_side_lenmax 表示保证图像最长边不大于 limit_side_len
  • None:如果设置为 None, 将默认使用产线初始化的该参数值,初始化为 max
None
text_det_thresh 检测像素阈值,输出的概率图中,得分大于该阈值的像素点才会被认为是文字像素点 float|None
  • float:大于 0 的任意浮点数
  • None:如果设置为 None, 将默认使用产线初始化的该参数值 0.3
None
text_det_box_thresh 检测框阈值,检测结果边框内,所有像素点的平均得分大于该阈值时,该结果会被认为是文字区域 float|None
  • float:大于 0 的任意浮点数
  • None:如果设置为 None, 将默认使用产线初始化的该参数值 0.6
None
text_det_unclip_ratio 文本检测扩张系数,使用该方法对文字区域进行扩张,该值越大,扩张的面积越大 float|None
  • float:大于 0 的任意浮点数
  • None:如果设置为 None, 将默认使用产线初始化的该参数值 2.0
None
text_rec_score_thresh 文本识别阈值,得分大于该阈值的文本结果会被保留 float|None
  • float:大于 0 的任意浮点数
  • None:如果设置为 None, 将默认使用产线初始化的该参数值 0.0。即不设阈值
None
use_ocr_results_with_table_cells 是否启用单元格OCR模式,不启用时采用全局OCR结果填充至HTML表格,启用时基于单元格预测结果,对全局OCR结果基于单元格进行切分和重识别,避免出现文字跨单元格连接或缺失的情况。此模式会略微增加推理耗时,并且在不同场景下效果可能不同,请根据实际情况选择。 bool
  • boolTrue 或者 False
True
use_e2e_wired_table_rec_model 是否启用有线表格端到端预测模式,不启用时采用表格单元格检测模型预测结果填充至HTML表格,启用时采用端到端表格结构识别模型的单元格预测结果填充至HTML表格。二者在不同场景下效果不同,请根据实际情况选择。 bool
  • boolTrue 或者 False
False
use_e2e_wireless_table_rec_model 是否启用无线表格端到端预测模式,不启用时采用表格单元格检测模型预测结果填充至HTML表格,启用时采用端到端表格结构识别模型的单元格预测结果填充至HTML表格。二者在不同场景下效果不同,请根据实际情况选择。 bool
  • boolTrue 或者 False
False
use_table_orientation_classify 是否启用表格方向分类模式,不启用时直接基于传入图像进行表格识别,启用时会检测图像中的表格是否存在旋转,能够将表格方向进行90/180/270度的方向校正后再进行表格识别。此模式会略微增加推理耗时,请根据实际情况选择。 bool
  • boolTrue 或者 False
True
use_wired_table_cells_trans_to_html 是否启用有线表单元格直转HTML模式,不启用时正常通过表格结构识别模块预测得到表格的HTML结构,启用时直接基于有线表单元格检测模型预测的各单元格位置排布与几何关系构建HTML结构。此模式在不同场景下效果不同,请根据实际情况选择。一般来说,建议在有线表单元格检测非常准确的场景下开启此模式,以获得更加准确的端到端表格识别结果。 bool
  • boolTrue 或者 False
False
use_wireless_table_cells_trans_to_html 是否启用无线表单元格直转HTML模式,不启用时正常通过表格结构识别模块预测得到表格的HTML结构,启用时直接基于无线表单元格检测模型预测的各单元格位置排布与几何关系构建HTML结构。此模式在不同场景下效果不同,请根据实际情况选择。一般来说,建议在无线表单元格检测非常准确的场景下开启此模式,以获得更加准确的端到端表格识别结果。 bool
  • boolTrue 或者 False
False

如果您需要使用端到端表格结构识别模型,只需在产线配置文件中将对应的表格结构识别模型替换为端到端表格结构识别模型,然后直接加载修改后的配置文件并修改对应的predict() 方法参数即可。例如,如果您需要使用 SLANet_plus 对无线表格做端到端表格识别,只需将配置文件中 WirelessTableStructureRecognition 中的 model_name 替换为 SLANet_plus(如下所示),并在预测时指定 use_e2e_wireless_table_rec_model=True 即可,其余部分无需修改,此时无线表单元格检测模型将不会生效,而是直接使用 SLANet_plus 进行端到端表格识别。

SubModules:
  WiredTableStructureRecognition:
    module_name: table_structure_recognition
    model_name: SLANeXt_wired
    model_dir: null

  WirelessTableStructureRecognition:
    module_name: table_structure_recognition
    model_name: SLANet_plus  # 替换为需使用的端到端表格结构识别模型
    model_dir: null

  WiredTableCellsDetection:
    module_name: table_cells_detection
    model_name: RT-DETR-L_wired_table_cell_det
    model_dir: null

  WirelessTableCellsDetection:
    module_name: table_cells_detection
    model_name: RT-DETR-L_wireless_table_cell_det
    model_dir: null

(3)对预测结果进行处理,每个样本的预测结果均为对应的Result对象,且支持打印、保存为图片、保存为xlsx文件、保存为HTML文件、保存为json文件的操作:

方法 方法说明 参数 参数类型 参数说明 默认值
print() 打印结果到终端 format_json bool 是否对输出内容进行使用 JSON 缩进格式化 True
indent int 指定缩进级别,以美化输出的 JSON 数据,使其更具可读性,仅当 format_jsonTrue 时有效 4
ensure_ascii bool 控制是否将非 ASCII 字符转义为 Unicode。设置为 True 时,所有非 ASCII 字符将被转义;False 则保留原始字符,仅当format_jsonTrue时有效 False
save_to_json() 将结果保存为json格式的文件 save_path str 保存的文件路径,当为目录时,保存文件命名与输入文件类型命名一致
indent int 指定缩进级别,以美化输出的 JSON 数据,使其更具可读性,仅当 format_jsonTrue 时有效 4
ensure_ascii bool 控制是否将非 ASCII 字符转义为 Unicode。设置为 True 时,所有非 ASCII 字符将被转义;False 则保留原始字符,仅当format_jsonTrue时有效 False
save_to_img() 将结果保存为图像格式的文件 save_path str 保存的文件路径,支持目录或文件路径
save_to_xlsx() 将结果保存为xlsx格式的文件 save_path str 保存的文件路径,支持目录或文件路径
save_to_html() 将结果保存为html格式的文件 save_path str 保存的文件路径,支持目录或文件路径
  • 调用print() 方法会将结果打印到终端,打印到终端的内容解释如下:

    • input_path: (str) 待预测图像的输入路径

    • page_index: (Union[int, None]) 如果输入是PDF文件,则表示当前是PDF的第几页,否则为 None

    • model_settings: (Dict[str, bool]) 配置产线所需的模型参数

      • use_doc_preprocessor: (bool) 控制是否启用文档预处理子产线
      • use_layout_detection: (bool) 控制是否启用版面区域检测子产线
      • use_ocr_model: (bool) 控制是否启用OCR子产线
        • layout_det_res: (Dict[str, Union[List[numpy.ndarray], List[float]]]) 版面检测子模块的输出结果。仅当use_layout_detection=True时存在
      • input_path: (Union[str, None]) 版面检测区域模块接受的图像路径,当输入为numpy.ndarray时,保存为None
      • page_index: (Union[int, None]) 如果输入是PDF文件,则表示当前是PDF的第几页,否则为 None
      • boxes: (List[Dict]) 版面印章区域的检测框列表,每个列表中的元素,包含以下字段
        • cls_id: (int) 检测框的印章类别id
        • score: (float) 检测框的置信度
        • coordinate: (List[float]) 检测框的四个顶点坐标,顺序为x1,y1,x2,y2表示左上角的x坐标,左上角的y坐标,右下角x坐标,右下角的y坐标
        • doc_preprocessor_res: (Dict[str, Union[str, Dict[str, bool], int]]) 文档预处理子产线的输出结果。仅当use_doc_preprocessor=True时存在
      • input_path: (Union[str, None]) 图像预处理子产线接受的图像路径,当输入为numpy.ndarray时,保存为None
      • model_settings: (Dict) 预处理子产线的模型配置参数
        • use_doc_orientation_classify: (bool) 控制是否启用文档方向分类
        • use_doc_unwarping: (bool) 控制是否启用文档扭曲矫正
      • angle: (int) 文档方向分类的预测结果。启用时取值为[0,1,2,3],分别对应[0°,90°,180°,270°];未启用时为-1
    • dt_polys: (List[numpy.ndarray]) 文本检测的多边形框列表。每个检测框由4个顶点坐标构成的numpy数组表示,数组shape为(4, 2),数据类型为int16

    • dt_scores: (List[float]) 文本检测框的置信度列表

    • text_det_params: (Dict[str, Dict[str, int, float]]) 文本检测模块的配置参数

      • limit_side_len: (int) 图像预处理时的边长限制值
      • limit_type: (str) 边长限制的处理方式
      • thresh: (float) 文本像素分类的置信度阈值
      • box_thresh: (float) 文本检测框的置信度阈值
      • unclip_ratio: (float) 文本检测框的膨胀系数
      • text_type: (str) 文本检测的类型,当前固定为"general"
    • text_rec_score_thresh: (float) 文本识别结果的过滤阈值

    • rec_texts: (List[str]) 文本识别结果列表,仅包含置信度超过text_rec_score_thresh的文本

    • rec_scores: (List[float]) 文本识别的置信度列表,已按text_rec_score_thresh过滤

    • rec_polys: (List[numpy.ndarray]) 经过置信度过滤的文本检测框列表,格式同dt_polys

    • rec_boxes: (numpy.ndarray) 检测框的矩形边界框数组,shape为(n, 4),dtype为int16。每一行表示一个矩形框的[x_min, y_min, x_max, y_max]坐标 ,其中(x_min, y_min)为左上角坐标,(x_max, y_max)为右下角坐标

  • 调用save_to_json() 方法会将上述内容保存到指定的save_path中,如果指定为目录,则保存的路径为save_path/{your_img_basename}_res.json,如果指定为文件,则直接保存到该文件中。由于json文件不支持保存numpy数组,因此会将其中的numpy.array类型转换为列表形式。

  • 调用save_to_img() 方法会将可视化结果保存到指定的save_path中,如果指定为目录,则保存的路径为save_path/{your_img_basename}_ocr_res_img.{your_img_extension},如果指定为文件,则直接保存到该文件中。(产线通常包含较多结果图片,不建议直接指定为具体的文件路径,否则多张图会被覆盖,仅保留最后一张图)
  • 调用save_to_html() 方法会将上述内容保存到指定的save_path中,如果指定为目录,则保存的路径为save_path/{your_img_basename}_table_1.html,如果指定为文件,则直接保存到该文件中。在通用表格识别v2产线中,将会把图像中表格的HTML形式写入到指定的html文件中。
  • 调用save_to_xlsx() 方法会将上述内容保存到指定的save_path中,如果指定为目录,则保存的路径为save_path/{your_img_basename}_res.xlsx,如果指定为文件,则直接保存到该文件中。在通用表格识别v2产线中,将会把图像中表格的Excel表格形式写入到指定的xlsx文件中。

  • 此外,也支持通过属性获取带结果的可视化图像和预测结果,具体如下:

属性 属性说明
json 获取预测的 json 格式的结果
img 获取格式为 dict 的可视化图像
  • json 属性获取的预测结果为dict类型的数据,相关内容与调用 save_to_json() 方法保存的内容一致。
  • img 属性返回的预测结果是一个字典类型的数据。其中,键分别为 table_res_imgocr_res_imglayout_res_imgpreprocessed_img,对应的值是四个 Image.Image 对象,按顺序分别为:表格识别结果的可视化图像、OCR 结果的可视化图像、版面区域检测结果的可视化图像、图像预处理的可视化图像。如果没有使用某个子模块,则字典中不包含对应的结果图像。

此外,您可以获取通用表格识别v2产线配置文件,并加载配置文件进行预测。可执行如下命令将结果保存在 my_path 中:

paddlex --get_pipeline_config table_recognition_v2 --save_path ./my_path

若您获取了配置文件,即可对通用表格识别v2产线各项配置进行自定义,只需要修改 create_pipeline 方法中的 pipeline 参数值为产线配置文件路径即可。示例如下:

from paddlex import create_pipeline

pipeline = create_pipeline(pipeline="./my_path/table_recognition_v2.yaml")

output = pipeline.predict(
    input="table_recognition_v2.jpg",
    use_doc_orientation_classify=False,
    use_doc_unwarping=False,
)

for res in output:
    res.print()
    res.save_to_img("./output/")
    res.save_to_xlsx("./output/")
    res.save_to_html("./output/")
    res.save_to_json("./output/")

注: 配置文件中的参数为产线初始化参数,如果希望更改通用通用表格识别v2产线初始化参数,可以直接修改配置文件中的参数,并加载配置文件进行预测。同时,CLI 预测也支持传入配置文件,--pipeline 指定配置文件的路径即可。

3. 开发集成/部署

如果产线可以达到您对产线推理速度和精度的要求,您可以直接进行开发集成/部署。

若您需要将产线直接应用在您的Python项目中,可以参考 2.2 Python脚本方式集成中的示例代码。

此外,PaddleX 也提供了其他三种部署方式,详细说明如下:

🚀 高性能推理:在实际生产环境中,许多应用对部署策略的性能指标(尤其是响应速度)有着较严苛的标准,以确保系统的高效运行与用户体验的流畅性。为此,PaddleX 提供高性能推理插件,旨在对模型推理及前后处理进行深度性能优化,实现端到端流程的显著提速,详细的高性能推理流程请参考PaddleX高性能推理指南

☁️ 服务化部署:服务化部署是实际生产环境中常见的一种部署形式。通过将推理功能封装为服务,客户端可以通过网络请求来访问这些服务,以获取推理结果。PaddleX 支持多种产线服务化部署方案,详细的产线服务化部署流程请参考PaddleX服务化部署指南

以下是基础服务化部署的API参考与多语言服务调用示例:

API参考

对于服务提供的主要操作:

  • HTTP请求方法为POST。
  • 请求体和响应体均为JSON数据(JSON对象)。
  • 当请求处理成功时,响应状态码为200,响应体的属性如下:
名称 类型 含义
logId string 请求的UUID。
errorCode integer 错误码。固定为0
errorMsg string 错误说明。固定为"Success"
result object 操作结果。
  • 当请求处理未成功时,响应体的属性如下:
名称 类型 含义
logId string 请求的UUID。
errorCode integer 错误码。与响应状态码相同。
errorMsg string 错误说明。

服务提供的主要操作如下:

  • infer

定位并识别图中的表格。

POST /table-recognition

  • 请求体的属性如下:
名称 类型 含义 是否必填
file string 服务器可访问的图像文件或PDF文件的URL,或上述类型文件内容的Base64编码结果。默认对于超过10页的PDF文件,只有前10页的内容会被处理。
要解除页数限制,请在产线配置文件中添加以下配置:
Serving:
  extra:
    max_num_input_imgs: null
fileType integer | null 文件类型。0表示PDF文件,1表示图像文件。若请求体无此属性,则将根据URL推断文件类型。
visualize boolean | null 是否返回可视化结果图以及处理过程中的中间图像等。
  • 传入 true:返回图像。
  • 传入 false:不返回图像。
  • 若请求体中未提供该参数或传入 null:遵循产线配置文件Serving.visualize 的设置。

例如,在产线配置文件中添加如下字段:
Serving:
  visualize: False
将默认不返回图像,通过请求体中的visualize参数可以覆盖默认行为。如果请求体和配置文件中均未设置(或请求体传入null、配置文件中未设置),则默认返回图像。
useDocOrientationClassify boolean | null 请参阅产线对象中 predict 方法的 use_doc_orientation_classify 参数相关说明。
useDocUnwarping boolean | null 请参阅产线对象中 predict 方法的 use_doc_unwarping 参数相关说明。
useLayoutDetection boolean | null 请参阅产线对象中 predict 方法的 use_layout_detection 参数相关说明。
useOcrModel boolean | null 请参阅产线对象中 predict 方法的 use_ocr_model 参数相关说明。
textDetLimitSideLen integer | null 请参阅产线对象中 predict 方法的 text_det_limit_side_len 参数相关说明。
textDetLimitType string | null 请参阅产线对象中 predict 方法的 text_det_limit_type 参数相关说明。
textDetThresh number | null 请参阅产线对象中 predict 方法的 text_det_thresh 参数相关说明。
textDetBoxThresh number | null 请参阅产线对象中 predict 方法的 text_det_box_thresh 参数相关说明。
textDetUnclipRatio number | null 请参阅产线对象中 predict 方法的 text_det_unclip_ratio 参数相关说明。
textRecScoreThresh number | null 请参阅产线对象中 predict 方法的 text_rec_score_thresh 参数相关说明。
useE2eWiredTableRecModel boolean 请参阅产线对象中 predict 方法的 use_e2e_wired_table_rec_model 参数相关说明。
useE2eWirelessTableRecModel boolean 请参阅产线对象中 predict 方法的 use_e2e_wireless_table_rec_model 参数相关说明。
useWiredTableCellsTransToHtml boolean 请参阅产线对象中 predict 方法的 use_wired_table_cells_trans_to_html 参数相关说明。 No
useWirelessTableCellsTransToHtml boolean 请参阅产线对象中 predict 方法的 use_wireless_table_cells_trans_to_html 参数相关说明。 No
useTableOrientationClassify boolean 请参阅产线对象中 predict 方法的 use_table_orientation_classify 参数相关说明。 No
useOcrResultsWithTableCells boolean 请参阅产线对象中 predict 方法的 use_ocr_results_with_table_cells 参数相关说明。
  • 请求处理成功时,响应体的result具有如下属性:
名称 类型 含义
tableRecResults object 表格识别结果。数组长度为1(对于图像输入)或实际处理的文档页数(对于PDF输入)。对于PDF输入,数组中的每个元素依次表示PDF文件中实际处理的每一页的结果。
dataInfo object 输入数据信息。

tableRecResults中的每个元素为一个object,具有如下属性:

名称 类型 含义
prunedResult object 产线对象的 predict 方法生成结果的 JSON 表示中 res 字段的简化版本,其中去除了 input_pathpage_index 字段。
outputImages object | null 参见产线预测结果的 img 属性说明。图像为JPEG格式,使用Base64编码。
inputImage string | null 输入图像。图像为JPEG格式,使用Base64编码。
多语言调用服务示例
Python
import base64
import requests

API_URL = "http://localhost:8080/table-recognition"
file_path = "./demo.jpg"

with open(file_path, "rb") as file:
    file_bytes = file.read()
    file_data = base64.b64encode(file_bytes).decode("ascii")

payload = {"file": file_data, "fileType": 1}

response = requests.post(API_URL, json=payload)

assert response.status_code == 200
result = response.json()["result"]
for i, res in enumerate(result["tableRecResults"]):
    print(res["prunedResult"])
    for img_name, img in res["outputImages"].items():
        img_path = f"{img_name}_{i}.jpg"
        with open(img_path, "wb") as f:
            f.write(base64.b64decode(img))
        print(f"Output image saved at {img_path}")
C++
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include "cpp-httplib/httplib.h" // https://github.com/Huiyicc/cpp-httplib
#include "nlohmann/json.hpp" // https://github.com/nlohmann/json
#include "base64.hpp" // https://github.com/tobiaslocker/base64

int main() {
    httplib::Client client("localhost", 8080);
    const std::string filePath = "./demo.jpg";
    std::ifstream file(filePath, std::ios::binary | std::ios::ate);
    if (!file) {
        std::cerr << "Error opening file." << std::endl;
        return 1;
    }

    std::streamsize size = file.tellg();
    file.seekg(0, std::ios::beg);
    std::vector buffer(size);

    if (!file.read(buffer.data(), size)) {
        std::cerr << "Error reading file." << std::endl;
        return 1;
    }

    std::string bufferStr(buffer.data(), static_cast(size));
    std::string encodedFile = base64::to_base64(bufferStr);

    nlohmann::json jsonObj;
    jsonObj["file"] = encodedFile;
    jsonObj["fileType"] = 1;

    auto response = client.Post("/table-recognition", jsonObj.dump(), "application/json");

    if (response && response->status == 200) {
        nlohmann::json jsonResponse = nlohmann::json::parse(response->body);
        auto result = jsonResponse["result"];

        if (!result.is_object() || !result["tableRecResults"].is_array()) {
            std::cerr << "Unexpected response structure." << std::endl;
            return 1;
        }

        for (size_t i = 0; i < result["tableRecResults"].size(); ++i) {
            auto tableRecResult = result["tableRecResults"][i];
            std::cout << tableRecResult["prunedResult"] << std::endl;

            if (tableRecResult["outputImages"].is_object()) {
                for (auto& img : tableRecResult["outputImages"].items()) {
                    std::string imgName = img.key();
                    std::string encodedImage = img.value();
                    std::string decodedImage = base64::from_base64(encodedImage);

                    std::string imgPath = imgName + "_" + std::to_string(i) + ".jpg";
                    std::ofstream outputImage(imgPath, std::ios::binary);
                    if (outputImage.is_open()) {
                        outputImage.write(decodedImage.c_str(), static_cast(decodedImage.size()));
                        outputImage.close();
                        std::cout << "Output image saved at " << imgPath << std::endl;
                    } else {
                        std::cerr << "Unable to open file for writing: " << imgPath << std::endl;
                    }
                }
            }
        }
    } else {
        std::cerr << "Failed to send HTTP request." << std::endl;
        if (response) {
            std::cerr << "HTTP status code: " << response->status << std::endl;
            std::cerr << "Response body: " << response->body << std::endl;
        }
        return 1;
    }

    return 0;
}
Java
import okhttp3.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Base64;

public class Main {
    public static void main(String[] args) throws IOException {
        String API_URL = "http://localhost:8080/table-recognition";
        String imagePath = "./demo.jpg";

        File file = new File(imagePath);
        byte[] fileContent = java.nio.file.Files.readAllBytes(file.toPath());
        String base64Image = Base64.getEncoder().encodeToString(fileContent);

        ObjectMapper objectMapper = new ObjectMapper();
        ObjectNode payload = objectMapper.createObjectNode();
        payload.put("file", base64Image);
        payload.put("fileType", 1);

        OkHttpClient client = new OkHttpClient();
        MediaType JSON = MediaType.get("application/json; charset=utf-8");
        RequestBody body = RequestBody.create(JSON, payload.toString());

        Request request = new Request.Builder()
                .url(API_URL)
                .post(body)
                .build();

        try (Response response = client.newCall(request).execute()) {
            if (response.isSuccessful()) {
                String responseBody = response.body().string();
                JsonNode root = objectMapper.readTree(responseBody);
                JsonNode result = root.get("result");

                JsonNode tableRecResults = result.get("tableRecResults");
                for (int i = 0; i < tableRecResults.size(); i++) {
                    JsonNode item = tableRecResults.get(i);

                    JsonNode prunedResult = item.get("prunedResult");
                    System.out.println("Pruned Result [" + i + "]: " + prunedResult.toString());

                    JsonNode outputImages = item.get("outputImages");

                    outputImages.fieldNames().forEachRemaining(imgName -> {
                        String imgBase64 = outputImages.get(imgName).asText();
                        byte[] imgBytes = Base64.getDecoder().decode(imgBase64);
                        String imgPath = "output_" + imgName +  ".jpg";
                        try (FileOutputStream fos = new FileOutputStream(imgPath)) {
                            fos.write(imgBytes);
                            System.out.println("Saved image to: " + imgPath);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    });
                }
            } else {
                System.err.println("Request failed with HTTP code: " + response.code());
            }
        }
    }
}
Go
package main

import (
    "bytes"
    "encoding/base64"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
)

func main() {
    API_URL := "http://localhost:8080/table-recognition"
    filePath := "./demo.jpg"

    fileBytes, err := ioutil.ReadFile(filePath)
    if err != nil {
        fmt.Printf("Error reading file: %v\n", err)
        return
    }
    fileData := base64.StdEncoding.EncodeToString(fileBytes)

    payload := map[string]interface{}{
        "file":     fileData,
        "fileType": 1,
    }
    payloadBytes, err := json.Marshal(payload)
    if err != nil {
        fmt.Printf("Error marshaling payload: %v\n", err)
        return
    }

    client := &http.Client{}
    req, err := http.NewRequest("POST", API_URL, bytes.NewBuffer(payloadBytes))
    if err != nil {
        fmt.Printf("Error creating request: %v\n", err)
        return
    }
    req.Header.Set("Content-Type", "application/json")

    res, err := client.Do(req)
    if err != nil {
        fmt.Printf("Error sending request: %v\n", err)
        return
    }
    defer res.Body.Close()

    if res.StatusCode != http.StatusOK {
        fmt.Printf("Unexpected status code: %d\n", res.StatusCode)
        return
    }

    body, err := ioutil.ReadAll(res.Body)
    if err != nil {
        fmt.Printf("Error reading response body: %v\n", err)
        return
    }

    type TableRecResult struct {
        PrunedResult  map[string]interface{} `json:"prunedResult"`
        OutputImages  map[string]string      `json:"outputImages"`
        InputImage    *string                `json:"inputImage"`
    }

    type Response struct {
        Result struct {
            TableRecResults []TableRecResult `json:"tableRecResults"`
            DataInfo        interface{}      `json:"dataInfo"`
        } `json:"result"`
    }

    var respData Response
    if err := json.Unmarshal(body, &respData); err != nil {
        fmt.Printf("Error unmarshaling response: %v\n", err)
        return
    }

    for i, res := range respData.Result.TableRecResults {
        fmt.Printf("Result %d - prunedResult: %+v\n", i, res.PrunedResult)

        for imgName, imgData := range res.OutputImages {
            imgBytes, err := base64.StdEncoding.DecodeString(imgData)
            if err != nil {
                fmt.Printf("Error decoding image %s_%d: %v\n", imgName, i, err)
                continue
            }

            filename := fmt.Sprintf("%s_%d.jpg", imgName, i)
            if err := ioutil.WriteFile(filename, imgBytes, 0644); err != nil {
                fmt.Printf("Error saving image %s: %v\n", filename, err)
                continue
            }
            fmt.Printf("Saved image to %s\n", filename)
        }
    }
}
C#
using System;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;

class Program
{
    static readonly string API_URL = "http://localhost:8080/table-recognition";
    static readonly string inputFilePath = "./demo.jpg";

    static async Task Main(string[] args)
    {
        var httpClient = new HttpClient();

        byte[] fileBytes = File.ReadAllBytes(inputFilePath);
        string fileData = Convert.ToBase64String(fileBytes);

        var payload = new JObject
        {
            { "file", fileData },
            { "fileType", 1 }
        };
        var content = new StringContent(payload.ToString(), Encoding.UTF8, "application/json");

        HttpResponseMessage response = await httpClient.PostAsync(API_URL, content);
        response.EnsureSuccessStatusCode();

        string responseBody = await response.Content.ReadAsStringAsync();
        JObject jsonResponse = JObject.Parse(responseBody);

        JArray tableRecResults = (JArray)jsonResponse["result"]["tableRecResults"];
        for (int i = 0; i < tableRecResults.Count; i++)
        {
            var res = tableRecResults[i];
            Console.WriteLine($"[{i}] prunedResult:\n{res["prunedResult"]}");

            JObject outputImages = res["outputImages"] as JObject;
            if (outputImages != null)
            {
                foreach (var img in outputImages)
                {
                    string imgName = img.Key;
                    string base64Img = img.Value?.ToString();
                    if (!string.IsNullOrEmpty(base64Img))
                    {
                        string imgPath = $"{imgName}_{i}.jpg";
                        byte[] imageBytes = Convert.FromBase64String(base64Img);
                        File.WriteAllBytes(imgPath, imageBytes);
                        Console.WriteLine($"Output image saved at {imgPath}");
                    }
                }
            }
        }
    }
}
Node.js
const axios = require('axios');
const fs = require('fs');
const path = require('path');

const API_URL = 'http://localhost:8080/table-recognition';
const inputImagePath = './demo.jpg';

function encodeImageToBase64(filePath) {
  const bitmap = fs.readFileSync(filePath);
  return Buffer.from(bitmap).toString('base64');
}

async function callTableRecognitionAPI() {
  const payload = {
    file: encodeImageToBase64(inputImagePath),
    fileType: 1
  };

  try {
    const response = await axios.post(API_URL, payload, {
      headers: {
        'Content-Type': 'application/json'
      },
      maxBodyLength: Infinity
    });

    const results = response.data.result.tableRecResults;

    results.forEach((res, index) => {
      console.log(`Result [${index}] prunedResult:\n`, res.prunedResult);

      const outputImages = res.outputImages || {};
      Object.entries(outputImages).forEach(([imgName, base64Img]) => {
        const outputPath = `${imgName}_${index}.jpg`;
        fs.writeFileSync(outputPath, Buffer.from(base64Img, 'base64'));
        console.log(`Saved image: ${outputPath}`);
      });
    });

  } catch (error) {
    console.error('API request failed:', error.message);
  }
}

callTableRecognitionAPI();

PHP
<?php

$API_URL = "http://localhost:8080/table-recognition";
$image_path = "./demo.jpg";

$image_data = base64_encode(file_get_contents($image_path));
$payload = array(
    "file" => $image_data,
    "fileType" => 1
);

$ch = curl_init($API_URL);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);

$result_array = json_decode($response, true);
$results = $result_array["result"]["tableRecResults"];

foreach ($results as $i => $item) {
    echo "[$i] prunedResult:\n";
    print_r($item["prunedResult"]);

    if (!empty($item["outputImages"])) {
        foreach ($item["outputImages"] as $img_name => $base64_img) {
            $img_path = $img_name . "_" . $i . ".jpg";
            file_put_contents($img_path, base64_decode($base64_img));
            echo "Output image saved at $img_path\n";
        }
    } else {
        echo "No outputImages found for item $i\n";
    }
}
?>


📱 端侧部署:端侧部署是一种将计算和数据处理功能放在用户设备本身上的方式,设备可以直接处理数据,而不需要依赖远程的服务器。PaddleX 支持将模型部署在 Android 等端侧设备上,详细的端侧部署流程请参考PaddleX端侧部署指南。 您可以根据需要选择合适的方式部署模型产线,进而进行后续的 AI 应用集成。

4. 二次开发

如果通用表格识别v2产线提供的默认模型权重在您的场景中,精度或速度不满意,您可以尝试利用您自己拥有的特定领域或应用场景的数据对现有模型进行进一步的微调,以提升通用表格识别v2产线的在您的场景中的识别效果。

4.1 模型微调

由于通用表格识别v2产线包含若干模块,模型产线的效果如果不及预期,可能来自于其中任何一个模块。您可以对识别效果差的图片进行分析,进而确定是哪个模块存在问题,并参考以下表格中对应的微调教程链接进行模型微调。

情形 微调模块 微调参考链接
表格结分类错误 表格分类模块 链接
表格单元格定位错误 表格单元格检测模块 链接
表格结构识别错误 表格结构识别模块 链接
未能成功检测到表格所在区域 版面区域检测模块 链接
文本存在漏检 文本检测模块 链接
文本内容都不准 文本识别模块 链接
整图旋转矫正不准 文档图像方向分类模块 链接
图像扭曲矫正不准 文本图像矫正模块 暂不支持微调

4.2 模型应用

当您使用私有数据集完成微调训练后,可获得本地模型权重文件。

若您需要使用微调后的模型权重,只需对产线配置文件做修改,将微调后模型权重的本地路径替换至产线配置文件中的对应位置即可:

SubModules:
  LayoutDetection:
    module_name: layout_detection
    model_name: PicoDet_layout_1x_table
    model_dir: null # 替换为微调后的版面区域检测模型权重路径

  TableClassification:
    module_name: table_classification
    model_name: PP-LCNet_x1_0_table_cls
    model_dir: null # 替换为微调后的表格分类模型权重路径

  WiredTableStructureRecognition:
    module_name: table_structure_recognition
    model_name: SLANeXt_wired
    model_dir: null # 替换为微调后的有线表格结构识别模型权重路径

  WirelessTableStructureRecognition:
    module_name: table_structure_recognition
    model_name: SLANeXt_wireless
    model_dir: null # 替换为微调后的无线表格结构识别模型权重路径

  WiredTableCellsDetection:
    module_name: table_cells_detection
    model_name: RT-DETR-L_wired_table_cell_det
    model_dir: null # 替换为微调后的有线表格单元格检测模型权重路径

  WirelessTableCellsDetection:
    module_name: table_cells_detection
    model_name: RT-DETR-L_wireless_table_cell_det
    model_dir: null # 替换为微调后的无线表格单元格检测模型权重路径

SubPipelines:
  DocPreprocessor:
    pipeline_name: doc_preprocessor
    use_doc_orientation_classify: True
    use_doc_unwarping: True
    SubModules:
      DocOrientationClassify:
        module_name: doc_text_orientation
        model_name: PP-LCNet_x1_0_doc_ori
        model_dir: null # 替换为微调后的文档图像方向分类模型权重路径

      DocUnwarping:
        module_name: image_unwarping
        model_name: UVDoc
        model_dir: null

  GeneralOCR:
    pipeline_name: OCR
    text_type: general
    use_doc_preprocessor: False
    use_textline_orientation: False
    SubModules:
      TextDetection:
        module_name: text_detection
        model_name: PP-OCRv5_server_det
        model_dir: null # 替换为微调后的文本检测模型权重路径
        limit_side_len: 960
        limit_type: max
        max_side_limit: 4000
        thresh: 0.3
        box_thresh: 0.4
        unclip_ratio: 1.5

      TextRecognition:
        module_name: text_recognition
        model_name: PP-OCRv5_server_rec
        model_dir: null # 替换为微调后文本识别的模型权重路径
        batch_size: 1
        score_thresh: 0
随后, 参考2.2 本地体验中的命令行方式或Python脚本方式,加载修改后的产线配置文件即可。

5. 多硬件支持

PaddleX 支持英伟达 GPU、昆仑芯 XPU、昇腾 NPU和寒武纪 MLU 等多种主流硬件设备,仅需修改 --device 参数即可完成不同硬件之间的无缝切换。

例如,您使用昇腾 NPU 进行通用表格识别v2产线的推理,使用的 CLI 命令为:

paddlex --pipeline table_recognition_v2 \
        --use_doc_orientation_classify=False \
        --use_doc_unwarping=False \
        --input table_recognition_v2.jpg \
        --save_path ./output \
        --device npu:0

当然,您也可以在 Python 脚本中 create_pipeline() 时或者 predict() 时指定硬件设备。

若您想在更多种类的硬件上使用通用表格识别v2产线,请参考PaddleX多硬件使用指南

评论