Python使用PaddleOCR实现PDF/图片文字识别与版面还原

 更新时间:2025年11月28日 09:10:29   作者:weixin_46244623  
本文介绍了如何利用 PaddleOCR 实现对 PDF 文件或图片 的文字识别,并在识别后将文本内容按照 原始版面位置 进行还原重建,感兴趣的小伙伴可以了解下

摘要

本文介绍了如何利用 PaddleOCR 实现对 PDF 文件或图片 的文字识别,并在识别后将文本内容按照 原始版面位置 进行还原重建。文章详细讲解了实现流程,包括 图像预处理OCR 识别版面坐标提取与重排、以及最终生成 可编辑的 PDF 或可视化输出 的过程。

本文将带你使用 PaddleOCR 实现一个完整流程:

# 升级 pip
python -m pip install --upgrade pip
 
# 设置清华源加速下载(可选)
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
 
# 安装 PaddlePaddle CPU 版本
python -m pip install paddlepaddle==3.2.0 -i https://www.paddlepaddle.org.cn/packages/stable/cpu/
 
# 安装辅助库
python -m pip install PyMuPDF Pillow reportlab tqdm beautifulsoup4
 
# 安装指定版本 PaddleOCR
python -m pip install paddleocr==3.2.0

1. 初始化 PaddleOCR(使用高精度服务器模型)

import os
import cv2
import json
import numpy as np
import base64
from xml.etree.ElementTree import Element, SubElement, tostring
from paddleocr import PaddleOCR
ocr = PaddleOCR(
    text_detection_model_name="PP-OCRv5_server_det",
    text_recognition_model_name="PP-OCRv5_server_rec",
    use_doc_orientation_classify=False,
    use_doc_unwarping=False,
    use_textline_orientation=False
)

2. 执行 OCR 识别

INPUT_IMG = "./page_4.png"
result = ocr.predict(INPUT_IMG)
data = result[0]  # 取第一页结果

返回结构包含:

  • rec_texts: 识别的文本列表
  • rec_polys: 每个文本的多边形坐标(4个点)
  • input_path: 原图路径

3. 读取原图获取尺寸

orig_img = cv2.imread(data["input_path"])
img_h, img_w = orig_img.shape[:2]
print(f"原图尺寸: {img_w} x {img_h}")

4. 创建 SVG 根节点(透明背景)

svg = Element("svg", {
    "xmlns": "http://www.w3.org/2000/svg",
    "width": str(img_w),
    "height": str(img_h),
    "viewBox": f"0 0 {img_w} {img_h}",
    "style": "background:none"
})

5. 内嵌仿宋字体(Base64 编码)

FONT_PATH = os.path.expanduser("~/.paddlex/fonts/simfang.ttf")

with open(FONT_PATH, "rb") as f:
    font_data = base64.b64encode(f.read()).decode("utf-8")

style_el = SubElement(svg, "style")
style_el.text = f"""
@font-face {{
  font-family: 'SimFang';
  src: url(data:font/truetype;charset=utf-8;base64,{font_data}) format('truetype');
}}
text {{
  font-family: 'SimFang';
  fill: rgb(0,0,0);
  dominant-baseline: middle;
  text-anchor: middle;
  white-space: pre;
}}

6. 智能绘制文字(支持旋转 + 竖排)

for text, poly in zip(data["rec_texts"], data["rec_polys"]):
    if not text.strip(): 
        continue

    box = np.array(poly, dtype=np.float32).reshape(4, 2)
    x0, y0 = box.min(axis=0)
    x1, y1 = box.max(axis=0)
    w_box, h_box = x1 - x0, y1 - y0

    # 计算旋转角度(以左下→右下边为基准)
    angle = np.degrees(np.arctan2(box[1][1] - box[0][1], box[1][0] - box[0][0]))
    font_size = max(8, int(min(w_box, h_box) * 0.8))

    # 判断是否为竖排文字
    vertical = h_box > 2.5 * w_box and h_box > 60

    if vertical:
        # 竖排:逐字垂直排列
        cx = (x0 + x1) / 2
        y = y0
        gap = h_box / max(len(text), 1)
        for ch in text:
            text_el = SubElement(svg, "text", {
                "x": str(cx),
                "y": str(y + gap / 2),
                "font-size": str(font_size),
                "transform": f"rotate({angle},{cx},{y + gap / 2})"
            })
            text_el.text = ch
            y += gap
    else:
        # 横排:整体旋转
        cx = (x0 + x1) / 2
        cy = (y0 + y1) / 2
        text_el = SubElement(svg, "text", {
            "x": str(cx),
            "y": str(cy),
            "font-size": str(font_size),
            "transform": f"rotate({angle},{cx},{cy})"
        })
        text_el.text = text

7. 保存 SVG 文件

OUTPUT_SVG = "page_1_transparent.svg"
with open(OUTPUT_SVG, "wb") as f:
    f.write(tostring(svg, encoding="utf-8", xml_declaration=True))

print(f"已生成透明可复制文字 SVG: {OUTPUT_SVG}")

8.效果展示

9.完整代码

import os
import cv2
import json
import numpy as np
import base64
from xml.etree.ElementTree import Element, SubElement, tostring
from paddleocr import PaddleOCR
# ================== 配置 ==================
ocr = PaddleOCR(
    text_detection_model_name="PP-OCRv5_server_det",
    text_recognition_model_name="PP-OCRv5_server_rec",
    use_doc_orientation_classify=False,
    use_doc_unwarping=False,
    use_textline_orientation=False
)

INPUT_IMG   = "./page_4.png"
OUTPUT_PDF  = "page_1_restored.pdf"
INPUT_JSON = "./page_4_res.json"
FONT_PATH   = os.path.expanduser("~/.paddlex/fonts/simfang.ttf")
SCALE       = 3


# ================== 1. OCR 使用 predict ==================
print("正在执行 OCR: result = ocr.predict(INPUT_IMG)")
try:
    results = ocr.predict(INPUT_IMG)
except Exception as e:
    print(f"\nOCR 失败页: {e}")
    continue

# ---------- 保存 JSON + 带框图 ----------
for res_idx, res in enumerate(results):
    res.save_to_img(os.path.join(f"page_boxed.png"))
    res.save_to_json(INPUT_JSON)

# ================== 配置 ==================
FONT_PATH  = os.path.expanduser("~/.paddlex/fonts/simfang.ttf")
OUTPUT_SVG = "page_1_transparent.svg"
TEXT_COLOR = (0, 0, 0)  # 黑色文字
if not os.path.exists(FONT_PATH):
    raise FileNotFoundError(f"字体未找到: {FONT_PATH}")

# ================== 1. 加载 OCR JSON ==================
if not os.path.exists(INPUT_JSON):
    raise FileNotFoundError(f"OCR 结果未找到: {INPUT_JSON}")
with open(INPUT_JSON, "r", encoding="utf-8") as f:
     data = json.load(f)

texts = data["rec_texts"]
polys = data["rec_polys"]

input_path = data.get("input_path")
if not input_path or not os.path.exists(input_path):
    raise FileNotFoundError(f"原图未找到: {input_path}")

# ================== 2. 获取原图尺寸 ==================
orig_img = cv2.imread(input_path)
if orig_img is None:
    raise ValueError(f"无法读取原图: {input_path}")
img_h, img_w = orig_img.shape[:2]
print(f"原图尺寸: {img_w} x {img_h}")

# ================== 3. 创建 SVG 根节点 ==================
svg = Element("svg", {
    "xmlns": "http://www.w3.org/2000/svg",
    "width": str(img_w),
    "height": str(img_h),
    "viewBox": f"0 0 {img_w} {img_h}",
    "style": "background:none"
})

# ================== 4. 内嵌字体(SimFang) ==================
if not os.path.exists(FONT_PATH):
    raise FileNotFoundError(f"字体未找到: {FONT_PATH}")

with open(FONT_PATH, "rb") as f:
    font_data = base64.b64encode(f.read()).decode("utf-8")

style_el = SubElement(svg, "style")
style_el.text = f"""
@font-face {{
  font-family: 'SimFang';
  src: url(data:font/truetype;charset=utf-8;base64,{font_data}) format('truetype');
}}
text {{
  font-family: 'SimFang';
  fill: rgb({TEXT_COLOR[0]}, {TEXT_COLOR[1]}, {TEXT_COLOR[2]});
  dominant-baseline: middle;
  text-anchor: middle;
  white-space: pre;
}}
"""

# ================== 5. 绘制文字(透明背景) ==================
for text, poly in zip(texts, polys):
    if not text.strip():
        continue

    box = np.array(poly, dtype=np.float32).reshape(4, 2)
    x0, y0 = box.min(axis=0)
    x1, y1 = box.max(axis=0)
    w_box, h_box = x1 - x0, y1 - y0
    angle = np.degrees(np.arctan2(box[1][1] - box[0][1], box[1][0] - box[0][0]))
    font_size = max(8, int(min(w_box, h_box) * 0.8))

    vertical = h_box > 2.5 * w_box and h_box > 60

    if vertical:
        # 竖排文字
        cx = (x0 + x1) / 2
        y = y0
        gap = h_box / max(len(text), 1)
        for ch in text:
            text_el = SubElement(svg, "text", {
                "x": str(cx),
                "y": str(y + gap / 2),
                "font-size": str(font_size),
                "transform": f"rotate({angle},{cx},{y + gap / 2})"
            })
            text_el.text = ch
            y += gap
    else:
        # 横排文字
        cx = (x0 + x1) / 2
        cy = (y0 + y1) / 2
        text_el = SubElement(svg, "text", {
            "x": str(cx),
            "y": str(cy),
            "font-size": str(font_size),
            "transform": f"rotate({angle},{cx},{cy})"
        })
        text_el.text = text

# ================== 6. 保存透明可复制 SVG ==================
with open(OUTPUT_SVG, "wb") as f:
    f.write(tostring(svg, encoding="utf-8", xml_declaration=True))

print(f"已生成透明可复制文字 SVG: {OUTPUT_SVG}")

以上就是Python使用PaddleOCR实现PDF/图片文字识别与版面还原的详细内容,更多关于Python PaddleOCR文字识别的资料请关注脚本之家其它相关文章!

相关文章

  • PyTorch中的Subset类简介与应用示例代码

    PyTorch中的Subset类简介与应用示例代码

    在深度学习框架PyTorch中,torch.utils.data.Subset是一个非常有用的类,用于从一个较大的数据集中选择一个子集,本文将介绍Subset的概念、基本用法以及一些实际应用示例,感兴趣的朋友一起看看吧
    2024-08-08
  • Python使用ffmpeg实现将WebM文件转换为MP4文件

    Python使用ffmpeg实现将WebM文件转换为MP4文件

    这篇文章主要介绍了Python如何使用wxPython库创建一个简单的GUI应用程序,可以实现将WebM文件转换为MP4文件,文中的示例代码讲解详细,感兴趣的可以动手尝试一下
    2023-08-08
  • 梯度下降法介绍及利用Python实现的方法示例

    梯度下降法介绍及利用Python实现的方法示例

    梯度下降算法是一个很基本的算法,在机器学习和优化中有着非常重要的作用,下面这篇文章主要给大家介绍了关于利用Python实现梯度下降法的相关资料,对大家具有一定的参考学习价值,需要的朋友们下面来一起看看吧。
    2017-07-07
  • python字典序问题实例

    python字典序问题实例

    这篇文章主要介绍了python字典序问题,是字符串操作一个比较典型的应用,需要的朋友可以参考下
    2014-09-09
  • python time.strptime格式化实例详解

    python time.strptime格式化实例详解

    在本篇文章里小编给大家整理的是一篇关于python time.strptime格式化实例详解内容,对此有兴趣的朋友们可以学习参考下。
    2021-02-02
  • Python利用lxml模块爬取豆瓣读书排行榜的方法与分析

    Python利用lxml模块爬取豆瓣读书排行榜的方法与分析

    这篇文章主要给大家介绍了关于Python爬虫利用lxml模块爬取豆瓣读书排行榜的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Python具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-04-04
  • python中使用zip函数出现<zip object at 0x02A9E418>错误的原因

    python中使用zip函数出现<zip object at 0x02A9E418>错误的原因

    这篇文章主要介绍了python中使用zip函数出现<zip object at 0x02A9E418>错误的原因分析及解决方法,需要的朋友可以参考下
    2018-09-09
  • 深入理解Python虚拟机中浮点数(float)的实现原理及源码

    深入理解Python虚拟机中浮点数(float)的实现原理及源码

    在本篇文章当中主要分析在 cpython 虚拟机当中 float 类型的实现原理以及与他相关的一些源代码,文中的示例代码讲解详细,感兴趣的可以了解一下
    2023-03-03
  • Anaconda中更新当前环境的Python版本详细步骤

    Anaconda中更新当前环境的Python版本详细步骤

    Anaconda是一个开源的Python发行版本,其包含了conda、Python等180多个科学包及其依赖项,下面这篇文章主要给大家介绍了关于Anaconda中更新当前环境的Python版本的详细步骤,需要的朋友可以参考下
    2024-08-08
  • 如何用Python实现简单的Markdown转换器

    如何用Python实现简单的Markdown转换器

    这篇文章主要介绍了如何用Python实现简单的Markdown转换器,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-07-07

最新评论