体验了一把 paddleocr , 顺便撸了一个 桌面端 PDF识别工具

一. 前言

近期在研究 OCR 的一些工具 ,想着先试试本地识别 , 后面再尝试一下 AI 的效率,最后选出一个好点的 。

这一篇主要是了解了一下 paddleocr 的使用。

二. 安装启动

官方使用文档 :github.com/PaddlePaddl...

环境准备

python 复制代码
// --- 我这里使用的是 Anaconda 建的虚拟环境 ,以下可以跳过
conda create --prefix "D:\code\python\enviroment\pdf_env" python=3.11.9
conda activate "D:\code\python\enviroment\pdf_env"



// ---------------- Anaconda
# 安装基础组件
pip install PyQt6 
pip install PyQt6-WebEngine 
pip install PyQt6-Frameless-Window 
pip install PyQt6-Fluent-Widgets -i https://pypi.org/simple/

# 安装 paddleocr
pip install paddleocr

# 安装 paddlepaddle (这里为了避免性能要求高,所以采用CPU 版本) 
# 另外还有性能更好的 GPU 版本 -> https://www.paddlepaddle.org.cn/install/quick
python -m pip install paddlepaddle==3.1.0 -i https://www.paddlepaddle.org.cn/packages/stable/cpu/

# 安装 PyMuPDF 用于处理 PDF
pip install PyMuPDF

运行项目 (CPU )

  • 结果是出来了 ,但是这性能太吓人了 ,我这 CPU 也不算差呀

换个 GPU 试试

js 复制代码
python -m pip uninstall paddlepaddle


// 查看自己的版本(Windows 版本)
nvidia-smi


// 安装对应版本
python -m pip install paddlepaddle-gpu==3.1.0 -i https://www.paddlepaddle.org.cn/packages/stable/cu126/

三. 核心代码

python 复制代码
import os
import fitz  # PyMuPDF
from paddleocr import PaddleOCR
import time
from datetime import datetime
from prettytable import PrettyTable
import csv
import traceback
import logging
import json

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler("ocr_service.log"),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger("OCR_Service")

def ocr_pdf_pages(pdf_path: str, page_numbers: list[int], output_dir: str = None):
    """
    使用 PaddleOCR 对 PDF 文件的指定页面进行 OCR,并将结构化结果统一导出到 CSV。

    Args:
        pdf_path (str): PDF 文件的路径。
        page_numbers (list[int]): 需要读取的页码列表 (例如 [1, 3, 5])。
        output_dir (str, optional): 输出结果的目录。如果指定,将保存图片、JSON 和汇总的 CSV 文件。
    """
    start_time = time.time()
    start_datetime = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    logger.info(f"开始处理时间: {start_datetime}")

    if not os.path.exists(pdf_path):
        logger.error(f"错误:找不到 PDF 文件 '{pdf_path}'")
        return

    # 初始化 PaddleOCR 引擎
    logger.info("正在初始化 PaddleOCR 引擎,这可能需要一些时间...")
    ocr_start_time = time.time()

    ocr = PaddleOCR(
        # --- 核心功能与模型设置 ---
        lang="ch",                      # 1. 语言:指定为中文模型('ch' 支持中英文和数字)
        ocr_version="PP-OCRv5",         # 2. 模型版本:使用先进的PP-OCRv5
        use_angle_cls=False,             # 3. 方向矫正:自动检测文字方向并旋转图片

        # device="gpu:0",               # (新版推荐) 这是更现代的写法,指定使用0号GPU
        use_tensorrt=False,              # 5. TensorRT加速:在NVIDIA GPU上获得极致性能 (需提前安装TensorRT)
        precision='fp16',               # 6. 精度:使用半精度(fp16),速度更快,显存占用更低 (需要GPU支持)
        
        # --- 性能与设备优化 (CPU用户) ---
        enable_mkldnn=True,             # 7. MKLDNN加速:若在CPU上运行,此选项可提升Intel CPU的性能
        cpu_threads=6,                  # 8. CPU线程数:在CPU模式下运行时使用的核心数

        # --- 效果微调 ---
        text_rec_score_thresh=0.5,      # 9. 识别阈值:只返回置信度高于 0.5 的识别结果,过滤掉模糊的猜测
    )
    ocr_end_time = time.time()
    logger.info(f"引擎初始化完成。耗时: {ocr_end_time - ocr_start_time:.2f} 秒")

    # 如果指定了输出目录,确保它存在
    if output_dir:
        os.makedirs(output_dir, exist_ok=True)

    # 初始化列表以保存所有页面的数据,用于最后统一导出
    all_csv_rows = []
    csv_header = ['page', 'text', 'score', 'x_min', 'y_min', 'x_max', 'y_max']

    try:
        # 打开 PDF 文件
        doc = fitz.open(pdf_path)

        # 遍历指定的页码
        for page_num in page_numbers:
            page_start_time = time.time()
            # 验证页码是否在有效范围内 (fitz 从 0 开始索引, 用户输入从 1 开始)
            if not (1 <= page_num <= doc.page_count):
                logger.warning(f"警告:页码 {page_num} 超出范围 (总页数: {doc.page_count})。已跳过。")
                continue

            logger.info(f"\n--- 正在处理第 {page_num} 页 ---")

            # 加载页面并转换为高分辨率图像
            page = doc.load_page(page_num - 1)
            pix = page.get_pixmap(dpi=300)
            temp_img_path = f"temp_page_{page_num}.png"
            pix.save(temp_img_path)

            # 进行 OCR 识别
            predict_start_time = time.time()
            result = ocr.predict(input=temp_img_path)
            predict_end_time = time.time()
            logger.info(f"OCR 识别耗时: {predict_end_time - predict_start_time:.2f} 秒")

            # 处理单页的识别结果
            # predict 返回一个列表,对于单个图像,我们只关心第一个元素
            page_result_obj = result[0] if result else None
            
            if page_result_obj:
                # 你原来的代码
                page_result_obj.print()
                page_result_obj.save_to_img("output")
                page_result_obj.save_to_json("output")
                
                # --- 新增代码 ---
                # 1. 使用点号(.)直接获取 rec_texts 属性的值,并存入新变量 all_texts
                all_texts = page_result_obj['rec_texts']
                
                # 2. (可选) 打印这个新变量,验证结果
                print("成功提取的文本内容:", all_texts)
                
                # 现在 all_texts 就是一个列表,包含了所有识别出的文本
                # 你可以对它进行任何操作,比如遍历
                for text_item in all_texts:
                    print(f"识别到的单项文本: {text_item}")
                    
            else:
                logger.info(f"--- 第 {page_num} 页未识别到文本 ---")

            # 删除临时图像文件
            if os.path.exists(temp_img_path):
                os.remove(temp_img_path)

            page_end_time = time.time()
            logger.info(f"第 {page_num} 页处理完成,耗时: {page_end_time - page_start_time:.2f} 秒")

        doc.close()

    except Exception as e:
         # 使用 traceback.format_exc() 获取完整的异常栈字符串
        error_stack = traceback.format_exc()
        
        # 将其与您的自定义信息一起打印出来
        logger.error(f"处理 PDF 时发生严重错误:\n{error_stack}")

    # 在所有页面处理完毕后,将收集到的数据写入一个 CSV 文件
    if output_dir and all_csv_rows:
        csv_path = os.path.join(output_dir, "structured_ocr_results.csv")
        logger.info(f"\n正在将所有结果汇总到: {csv_path}")
        try:
            with open(csv_path, 'w', newline='', encoding='utf-8-sig') as f:
                writer = csv.writer(f)
                writer.writerow(csv_header)
                writer.writerows(all_csv_rows)
            logger.info(f"✅ 汇总 CSV 文件已成功保存!")
        except IOError as e:
            logger.error(f"❌ 汇总导出 CSV 文件失败: {e}")

    end_time = time.time()
    end_datetime = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    total_time = end_time - start_time
    logger.info(f"\n处理结束时间: {end_datetime}")
    logger.info(f"总处理时间: {total_time:.2f} 秒 ({total_time/60:.2f} 分钟)")

使用效果 :

四. 使用时的一些注意事项

4.1 PaddleOCR 对象的准备

4.2 关于请求参数的作用

python 复制代码
def predict(
    self,
    # 待识别的图片,可以是路径、URL或图片数据
    input,
    # 是否自动旋转图片方向
    use_doc_orientation_classify=None,
    # 是否自动校正弯曲图片
    use_doc_unwarping=None,
    # 是否自动判断文本行方向
    use_textline_orientation=None,
    
    # 临时修改文本检测模型的最长边限制
    text_det_limit_side_len=None,
    # 临时修改文本检测的最长边限制类型
    text_det_limit_type=None,
    # 临时修改文本检测的二值化阈值
    text_det_thresh=None,
    # 临时修改文本检测的检测框得分阈值
    text_det_box_thresh=None,
    # 临时修改文本检测的文本框扩大比例
    text_det_unclip_ratio=None,
    # 临时修改文本识别的置信度阈值
    text_rec_score_thresh=None,
    
    # 结果保存格式 (txt, json, pdf, pdf_searchable)
    save_format=None,
    # 结果保存路径
    save_path=None,
    # 结果可视化或生成PDF时使用的字体路径
    font_path=None,
):
    # ... 函数的具体实现逻辑 ...
    pass

4.3 Result 结果

@ paddlepaddle.github.io/PaddleOCR/m...

总结

源码 @ gitee.com/antblack/an...

一次小尝试 没啥好说的 , 图形界面基于之前自己搭的脚手架 ,还是比较快的。

整体来说还是基于本地性能 , 好的 GPU > CPU . 性能还行 ,1-2 秒一张图(显卡笔记本4060

最近业余时间没那么多了 ,只能学些小东西了~~~

最后的最后 ❤️❤️❤️👇👇👇

相关推荐
threejs源码翻译官13 分钟前
显微镜图像处理【部署】- pytorch模型转onnx使用GPU进行推理
后端
stark张宇15 分钟前
Linux 用户、用户组、文件权限、文件查找
后端
拉一次撑死狗21 分钟前
Python绘制数据(二)
开发语言·python·信息可视化
淦暴尼26 分钟前
用Python做数据分析:5个实战案例
python·信息可视化·数据分析
wjpwjpwjp083138 分钟前
[MySQL基础3] 数据控制语言DCL和MySQL中的常用函数
数据库·笔记·后端·学习·mysql
东边有耳41 分钟前
一文深扒银行会计科目(收藏备查)
后端·架构·产品经理
东边有耳1 小时前
银行将你的存款放大了!!!
后端
白日依山尽yy1 小时前
SpringBoot项目部署至云服务器
java·spring boot·后端
花火|1 小时前
关于pytorch虚拟环境及具体bug问题修改
人工智能·pytorch·python
斟的是酒中桃1 小时前
【学习记录】智能客服小桃(进度更新ing)
人工智能·python·学习·语言模型·langchain·agent