You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将扫描版PDF转DOCX并利用layout-parser保留图表表格与格式

用Layout Parser实现扫描PDF转DOCX并保留图表表格格式

整体流程概述

扫描PDF本质是图片集合,要保留格式转DOCX需分三步:PDF转高清图片→Layout Parser版面分析(区分文本/表格/图表)→分区域处理后整合到DOCX。以下是具体实现方案:


1. 准备依赖

先安装所需工具库:

pip install layoutparser pdf2image easyocr python-docx table-transformer opencv-python

2. 扫描PDF转高清图片

用pdf2image将PDF每页转为300DPI的PNG(高DPI是OCR和版面分析准确率的关键):

from pdf2image import convert_from_path

# 转换PDF为图片列表
pages = convert_from_path("scanned_document.pdf", dpi=300)
# 保存单页图片
for idx, page in enumerate(pages):
    page.save(f"page_{idx+1}.png", "PNG")

3. Layout Parser版面分析

加载预训练的PubLayNet模型,识别页面中的文本、表格、图表区域,并按阅读顺序排序:

import layoutparser as lp

# 加载预训练版面分析模型(支持识别文本、标题、列表、表格、图表)
model = lp.Detectron2LayoutModel(
    config_path="lp://PubLayNet/mask_rcnn_X_101_32x8d_FPN_3x/config",
    label_map={0: "Text", 1: "Title", 2: "List", 3:"Table", 4:"Figure"},
    extra_config=["MODEL.ROI_HEADS.SCORE_THRESH_TEST", 0.8]  # 过滤低置信度区域
)

# 处理单页图片示例
image = lp.read_image("page_1.png")
layout = model.detect(image)

# 按区域类型分类
text_blocks = [block for block in layout if block.type in ["Text", "Title", "List"]]
table_blocks = [block for block in layout if block.type == "Table"]
figure_blocks = [block for block in layout if block.type == "Figure"]

# 按页面阅读顺序排序(从上到下,从左到右)
text_blocks = lp.Layout(text_blocks).sort(key=lambda x: (x.coordinates[1], x.coordinates[0]))
table_blocks = lp.Layout(table_blocks).sort(key=lambda x: (x.coordinates[1], x.coordinates[0]))
figure_blocks = lp.Layout(figure_blocks).sort(key=lambda x: (x.coordinates[1], x.coordinates[0]))

4. 分区域处理内容

文本区域:用EasyOCR替代pytesseract提升识别效果

EasyOCR无需额外配置,多语言支持更好,复杂排版下准确率优于pytesseract:

import easyocr

# 初始化OCR阅读器(支持多语言,比如中文+英文:['ch_sim','en'])
reader = easyocr.Reader(['en'])

text_content = []
for block in text_blocks:
    # 裁剪文本区域
    segment_image = image.crop(block.coordinates)
    # OCR识别
    result = reader.readtext(segment_image)
    # 拼接文本内容
    block_text = "\n".join([text for (bbox, text, score) in result])
    text_content.append((block, block_text))

表格区域:用Table Transformer提取结构化表格

专门的表格识别模型,能准确提取行列结构和单元格内容:

from table_transformer import TableStructureRecognizer, TableOCR

# 初始化表格识别工具
tsr = TableStructureRecognizer()
table_ocr = TableOCR(reader)  # 复用之前的EasyOCR实例

table_contents = []
for table_block in table_blocks:
    table_image = image.crop(table_block.coordinates)
    # 识别表格行列结构
    table_structure = tsr.predict(table_image)
    # 提取单元格文本
    table_data = table_ocr.predict(table_image, table_structure)
    table_contents.append((table_block, table_data))

图表区域:保留原始图像

直接裁剪图表区域保存为临时文件,后续插入DOCX:

import os

if not os.path.exists("temp_figures"):
    os.mkdir("temp_figures")

figure_paths = []
for idx, fig_block in enumerate(figure_blocks):
    fig_image = image.crop(fig_block.coordinates)
    fig_path = f"temp_figures/figure_{idx+1}.png"
    fig_image.save(fig_path)
    figure_paths.append((fig_block, fig_path))

5. 整合内容到DOCX

用python-docx按页面顺序插入文本、表格、图片,还原原PDF排版:

from docx import Document
from docx.shared import Inches

doc = Document()

# 合并所有区域并按阅读顺序排序
all_blocks = text_content + table_contents + figure_paths
all_blocks.sort(key=lambda x: (x[0].coordinates[1], x[0].coordinates[0]))

for block in all_blocks:
    block_obj, content = block
    if block_obj.type in ["Text", "Title", "List"]:
        # 标题用Heading样式,普通文本用Paragraph
        if block_obj.type == "Title":
            doc.add_heading(content, level=1)
        else:
            doc.add_paragraph(content)
    elif block_obj.type == "Table":
        # 生成对应行列的表格
        table_data = content
        table = doc.add_table(rows=len(table_data), cols=len(table_data[0]))
        for i in range(len(table_data)):
            for j in range(len(table_data[i])):
                table.cell(i,j).text = table_data[i][j]
    elif block_obj.type == "Figure":
        # 插入图片并适配页面宽度
        doc.add_picture(content, width=Inches(6))

# 保存最终DOCX
doc.save("converted_document.docx")

额外优化建议

  • 若OCR效果不佳,可对图片做预处理(灰度化、降噪、二值化):
import cv2

def preprocess_image(image_path):
    img = cv2.imread(image_path)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    denoised = cv2.GaussianBlur(gray, (3,3), 0)
    _, thresh = cv2.threshold(denoised, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    return thresh

处理图片时替换为image = preprocess_image("page_1.png")即可。

  • 超复杂表格可尝试TableNet模型,进一步提升结构识别准确率。

内容的提问来源于stack exchange,提问作者Musaib Ahmed Razzaqui

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 11:17:38