离线部署paddldocr

完整流程(联网机器 + 离线机器)

目标
在联网机器上:

安装 Miniconda + PaddleOCR。

完整测试 OCR 功能(确保所有模型和依赖正常)。

打包 Conda 环境、pip 依赖、PaddleOCR 模型,生成离线安装包。

在离线机器上:

直接部署 Conda 环境 + 预下载模型,无需联网。

🔧 1. 在联网机器上的完整安装与测试
(1) 安装 Miniconda
bash

下载 Miniconda(Linux 64-bit)

wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh

安装 Miniconda(默认安装到 ~/miniconda3)

bash Miniconda3-latest-Linux-x86_64.sh -b

激活 conda

source ~/miniconda3/bin/activate
(2) 创建 Conda 环境并安装 PaddleOCR
bash

创建 conda 环境(Python 3.8)

conda create -n paddle_env python=3.8 -y
conda activate paddle_env

安装 PaddlePaddle(GPU 版本,若用 CPU 则替换为 paddlepaddle

pip install paddlepaddle-gpu==2.5.1 -i https://mirror.baidu.com/pypi/simple

安装 PaddleOCR

pip install paddleocr==2.7.0 -i https://mirror.baidu.com/pypi/simple

安装 OpenCV 等依赖

pip install opencv-python Pillow numpy -i https://mirror.baidu.com/pypi/simple
**(3) 📌 关键步骤:测试 PaddleOCR 是否正常工作
bash

测试1:检查 PaddlePaddle 是否能正确识别 GPU

python -c “import paddle; print(paddle.utils.run_check())”

测试2:运行 PaddleOCR 测试(自动下载模型)

python -c “from paddleocr import PaddleOCR; ocr = PaddleOCR(use_angle_cls=True); print(ocr.ocr(‘https://paddleocr.bj.bcebos.com/ppstructure/docs/table/table.jpg’))”
✅ 预期结果:

PaddlePaddle 应输出 Running verify PaddlePaddle program … PaddlePaddle works well!。

PaddleOCR 应成功识别图片中的文字。

这里需要注意一点,设置全局变量

find /root/miniconda3/envs/paddle_env -name “libssl.so.1.1”
export LD_LIBRARY_PATH=/root/miniconda3/envs/paddle_env/lib:$LD_LIBRARY_PATH

(4) 预下载 PaddleOCR 模型(避免离线机器下载)
bash

创建模型存储目录

mkdir -p paddleocr_models

下载检测、识别、分类模型

wget https://paddleocr.bj.bcebos.com/PP-OCRv4/chinese/ch_PP-OCRv4_det_infer.tar -O paddleocr_models/ch_PP-OCRv4_det_infer.tar
wget https://paddleocr.bj.bcebos.com/PP-OCRv4/chinese/ch_PP-OCRv4_rec_infer.tar -O paddleocr_models/ch_PP-OCRv4_rec_infer.tar
wget https://paddleocr.bj.bcebos.com/PP-OCRv4/chinese/ch_PP-OCRv4_cls_infer.tar -O paddleocr_models/ch_PP-OCRv4_cls_infer.tar

解压模型

cd paddleocr_models
tar -xf ch_PP-OCRv4_det_infer.tar
tar -xf ch_PP-OCRv4_rec_infer.tar
tar -xf ch_PP-OCRv4_cls_infer.tar
cd …
**(5) 📌 关键步骤:测试离线模型是否可用
bash

使用本地模型运行 OCR(不联网)

python -c "
from paddleocr import PaddleOCR;
ocr = PaddleOCR(
use_angle_cls=True,
det_model_dir=‘./paddleocr_models/ch_PP-OCRv4_det_infer’,
rec_model_dir=‘./paddleocr_models/ch_PP-OCRv4_rec_infer’,
cls_model_dir=‘./paddleocr_models/ch_PP-OCRv4_cls_infer’
);
print(ocr.ocr(‘https://paddleocr.bj.bcebos.com/ppstructure/docs/table/table.jpg’))
"
✅ 预期结果:PaddleOCR 应能正常识别文字,且不触发模型下载。

(6) 打包 Conda 环境和模型
bash

打包 conda 环境

conda pack -n paddle_env -o paddle_env.tar.gz

当时我上边这个命令无法运行,于是直接打包虚拟环境在离线机器上进行还原 tar -czvf paddle_env.tar.gz /root/miniconda3/envs/paddle_env

打包模型文件

tar -czvf paddleocr_models.tar.gz paddleocr_models

打包 pip 下载的 wheel 文件(可选,用于极端离线情况)

mkdir pip_packages
pip download paddlepaddle-gpu2.5.1 paddleocr2.7.0 opencv-python Pillow numpy -d pip_packages
tar -czvf pip_packages.tar.gz pip_packages
(7) 准备离线安装包
最终得到的文件:

Miniconda3-latest-Linux-x86_64.sh(Miniconda 安装脚本)

paddle_env.tar.gz(Conda 环境 把这个放到miniconda 下的env下边即可 能查到这个虚拟环境)

paddleocr_models.tar.gz(PaddleOCR 模型 解压到文件夹下 一会跑python程序的时候可以直接用)

pip_packages.tar.gz(pip 离线依赖包,可选 一会在离线机器上进行pip install paddlepaddle paddleocr 这两个固定版本的依赖即可)

2. 在离线机器上部署

(1) 安装 Miniconda
bash

复制 Miniconda 安装包到离线机器

bash Miniconda3-latest-Linux-x86_64.sh -b
source ~/miniconda3/bin/activate
(2) 恢复 Conda 环境
bash

解压 conda 环境

mkdir -p ~/miniconda3/envs/
tar -xzf paddle_env.tar.gz -C ~/miniconda3/envs/

激活环境

conda activate paddle_env(所有的命令都要基于这个 不进入这个虚拟环境 很多命令都识别不了)

然后查看虚拟环境 conda info --envs

(3) 加载 PaddleOCR 模型
bash

解压模型文件

tar -xzf paddleocr_models.tar.gz

然后设置全局变量

首先查找libssl的位置: find /-name “libssl.so*” 2>/dev/null

export LD_LIBRARY_PATH=/root/miniconda/envs/paddle_env/lib:$LD_LIBRARY_PATH

(如果不设置这个会报一个找不到lib)
(4) 测试离线 OCR

首先下载依赖 paddlepaddle 和 paddleocr

pip install --no-index --find-link=. paddlepaddle-2.5.1-cp38-cp38-manylinux1_x86_64.whl

pip install --no-index --find-link=. paddleocr-2.7.0.0-py3-none-any.whl

然后执行
python -c "
from paddleocr import PaddleOCR;
ocr = PaddleOCR(
use_angle_cls=True,
det_model_dir=‘./paddleocr_models/ch_PP-OCRv4_det_infer’,# 这三个模型可以换成绝对路径
rec_model_dir=‘./paddleocr_models/ch_PP-OCRv4_rec_infer’,
cls_model_dir=‘./paddleocr_models/ch_PP-OCRv4_cls_infer’
);
print(ocr.ocr(‘your_image.jpg’)) # 替换为本地图片路径
"
✅ 预期结果:OCR 应能正常运行,无需联网。

📝 最终检查清单
步骤 联网机器 离线机器

  1. 安装 Miniconda ✅ 安装并测试 ✅ 仅安装
  2. 创建 Conda 环境 ✅ 安装 PaddleOCR ✅ 解压恢复
  3. 测试 OCR ✅ 在线模型 + 本地模型 ✅ 仅本地模型
  4. 打包环境 ✅ 生成 paddle_env.tar.gz ❌ 不需要
  5. 预下载模型 ✅ 生成 paddleocr_models.tar.gz ✅ 解压使用
  6. 离线 pip 包 ✅ 可选打包 ✅ 可选安装

进阶版python文件

初始版py文件

from pdf2image import convert_from_path
from paddleocr import PaddleOCR
import os

 初始化 OCR
ocr = PaddleOCR(
    use_angle_cls=False,
    det_model_dir='./paddleocr_models/ch_PP-OCRv4_det_infer',
    rec_model_dir='./paddleocr_models/ch_PP-OCRv4_rec_infer',
    cls_model_dir='./paddleocr_models/ch_ppocr_mobile_v2.0_cls_infer',
    use_gpu=False
)

#PDF 路径
pdf_path = 'test.pdf'

#转换 PDF 每页为图像
images = convert_from_path(pdf_path, dpi=300)  # DPI 可调高保证清晰度

#处理每一页
for i, image in enumerate(images):
    image_path = f'page_{i+1}.png'
    image.save(image_path, 'PNG')  # 保存为 PNG
    result = ocr.ocr(image_path, cls=False)
    print(f'--- 第 {i+1} 页 ---')
    for line in result[0]:
        print(line[1][0])

识别边框等相关信息

import os
import sys
from pathlib import Path
from paddleocr import PaddleOCR
from pdf2image import convert_from_path
from PIL import Image

def run_ocr_on_image(image_path, ocr):
    """对单张图片执行 OCR 并返回结果"""
    result = ocr.ocr(image_path, cls=False)
    text_lines = [line[1][0] for line in result[0]]
    return text_lines

def ocr_file(input_path, ocr):
    """根据输入文件类型选择处理方式"""
    input_path = Path(input_path)
    
    if not input_path.exists():
        print(f"❌ 文件不存在:{input_path}")
        return

    if input_path.suffix.lower() == '.pdf':
        print(f"📄 正在处理 PDF 文件: {input_path}")
        images = convert_from_path(str(input_path), dpi=300)
        for idx, img in enumerate(images):
            img_path = f"temp_page_{idx+1}.png"
            img.save(img_path, 'PNG')
            print(f"\n--- 第 {idx+1} 页识别结果 ---")
            lines = run_ocr_on_image(img_path, ocr)
            for line in lines:
                print(line)
            os.remove(img_path)  # 清理临时图像
    elif input_path.suffix.lower() in ['.png', '.jpg', '.jpeg', '.bmp']:
        print(f"🖼️ 正在处理图片文件: {input_path}")
        lines = run_ocr_on_image(str(input_path), ocr)
        print("\n--- 识别结果 ---")
        for line in lines:
            print(line)
    else:
        print("❌ 不支持的文件类型,请使用 PNG / JPG / PDF。")

def main():
    if len(sys.argv) != 2:
        print("用法: python ocr_universal.py <输入文件路径>")
        return

    input_file = sys.argv[1]

    # 初始化 OCR(修改模型路径为你的本地路径)
    ocr = PaddleOCR(
        use_angle_cls=False,
        det_model_dir='./paddleocr_models/ch_PP-OCRv4_det_infer',
        rec_model_dir='./paddleocr_models/ch_PP-OCRv4_rec_infer',
        cls_model_dir='./paddleocr_models/ch_ppocr_mobile_v2.0_cls_infer',
        use_gpu=False
    )

    ocr_file(input_file, ocr)

if __name__ == '__main__':
    main()

imageandJson

import os
import sys
from pathlib import Path
from paddleocr import PaddleOCR
from pdf2image import convert_from_path
from PIL import Image, ImageDraw, ImageFont


def run_ocr_on_image(image_path, ocr):
    """对单张图片执行 OCR,返回识别文字和可视化图像"""
    result = ocr.ocr(image_path, cls=False)
    image = Image.open(image_path).convert("RGB")
    draw = ImageDraw.Draw(image)

    # 加载字体,优先使用 simfang.ttf(项目根目录),否则用默认字体
    try:
        font = ImageFont.truetype("simfang.ttf", 18)
    except:
        font = ImageFont.load_default()

    for line in result[0]:
        box = line[0]  # 边框坐标
        text = line[1][0]  # 文本
        draw.line(box + [box[0]], fill=(255, 0, 0), width=2)
        draw.text(box[0], text, fill=(0, 0, 255), font=font)

    return result[0], image


def ocr_file(input_path, ocr):
    """根据输入文件类型选择处理方式"""
    input_path = Path(input_path)

    if not input_path.exists():
        print(f"❌ 文件不存在:{input_path}")
        return

    if input_path.suffix.lower() == '.pdf':
        print(f"📄 正在处理 PDF 文件: {input_path}")
        images = convert_from_path(str(input_path), dpi=300)
        for idx, img in enumerate(images):
            img_path = f"temp_page_{idx+1}.png"
            img.save(img_path, 'PNG')
            print(f"\n--- 第 {idx+1} 页识别结果 ---")
            result, vis_img = run_ocr_on_image(img_path, ocr)
            output_img_path = f"{input_path.stem}_page{idx+1}_result.png"
            vis_img.save(output_img_path)
            print(f"✅ 结果图像已保存:{output_img_path}")
            os.remove(img_path)
    elif input_path.suffix.lower() in ['.png', '.jpg', '.jpeg', '.bmp']:
        print(f"🖼️ 正在处理图片文件: {input_path}")
        result, image_with_boxes = run_ocr_on_image(str(input_path), ocr)
        output_path = input_path.stem + "_result.png"
        image_with_boxes.save(output_path)
        print(f"✅ 已保存识别图像到:{output_path}")
    else:
        print("❌ 不支持的文件类型,请使用 PNG / JPG / PDF。")


def main():
    if len(sys.argv) != 2:
        print("用法: python ocr_universal.py <输入文件路径>")
        return

    input_file = sys.argv[1]

    # 初始化 OCR 模型
    ocr = PaddleOCR(
        use_angle_cls=False,
        det_model_dir='./paddleocr_models/ch_PP-OCRv4_det_infer',
        rec_model_dir='./paddleocr_models/ch_PP-OCRv4_rec_infer',
        cls_model_dir='./paddleocr_models/ch_ppocr_mobile_v2.0_cls_infer',
        use_gpu=False
    )

    ocr_file(input_file, ocr)


if __name__ == '__main__':
    main()

将代码封成http服务返回json

首先拉依赖

mkdir flask_offline_packages
pip download flask -d flask_offline_packages

pip install --no-index --find-links=flask_offline_packages flask

import os
import json
import tempfile
from pathlib import Path
from flask import Flask, request, jsonify, send_file
from paddleocr import PaddleOCR
from pdf2image import convert_from_path
from PIL import Image, ImageDraw, ImageFont

app = Flask(__name__)

# 初始化 OCR,只加载一次
ocr = PaddleOCR(
    use_angle_cls=False,
    det_model_dir='/root/paddleocr_models/ch_PP-OCRv4_det_infer',
    rec_model_dir='/root/paddleocr_models/ch_PP-OCRv4_rec_infer',
    cls_model_dir='/root/paddleocr_models/ch_ppocr_mobile_v2.0_cls_infer',
    use_gpu=False
)

def run_ocr_on_image(image_path, ocr):
    result = ocr.ocr(image_path, cls=False)
    image = Image.open(image_path).convert("RGB")
    draw = ImageDraw.Draw(image)

    try:
        font = ImageFont.truetype("simfang.ttf", 18)
    except:
        font = ImageFont.load_default()

    for line in result[0]:
        box = [tuple(point) for point in line[0]]
        text = line[1][0]
        draw.line(box + [box[0]], fill=(255, 0, 0), width=2)
        draw.text(box[0], text, fill=(0, 0, 255), font=font)

    return result[0], image

def save_json_data(result):
    return [
        {
            "text": line[1][0],
            "confidence": float(line[1][1]),
            "box": [list(map(float, pt)) for pt in line[0]]
        }
        for line in result
    ]

@app.route('/ocr', methods=['POST'])
def ocr_api():
    if 'file' not in request.files:
        return jsonify({"error": "No file uploaded"}), 400

    file = request.files['file']
    filename = file.filename.lower()

    with tempfile.TemporaryDirectory() as tmpdir:
        file_path = os.path.join(tmpdir, file.filename)
        file.save(file_path)

        results = []

        if filename.endswith('.pdf'):
            images = convert_from_path(file_path, dpi=300)
            for idx, img in enumerate(images):
                img_path = os.path.join(tmpdir, f"page_{idx}.png")
                img.save(img_path)
                result, vis_image = run_ocr_on_image(img_path, ocr)

                json_data = save_json_data(result)
                results.append({
                    "page": idx + 1,
                    "results": json_data
                })

        elif any(filename.endswith(ext) for ext in ['.png', '.jpg', '.jpeg', '.bmp']):
            result, vis_image = run_ocr_on_image(file_path, ocr)
            json_data = save_json_data(result)

            # 可视化图像保存并返回
            image_output_path = os.path.join(tmpdir, "result.png")
            vis_image.save(image_output_path)

            return jsonify({
                "results": json_data
            })

        else:
            return jsonify({"error": "Unsupported file type"}), 400

        return jsonify({
            "results": results
        })

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)


返回json传递给opei 有人能识别的效果

首先执行

export DEEPSEEK_API_KEY=sk-6698c77b145149f69cb0b85c197f4b9111
import os
import json
import tempfile
from flask import Flask, request, Response, jsonify
from paddleocr import PaddleOCR
from pdf2image import convert_from_path
from PIL import Image, ImageDraw, ImageFont
from openai import OpenAI  # ✅ 新 SDK 的导入方式

# 初始化 Flask 应用
app = Flask(__name__)

# 初始化 OCR(只加载一次)
ocr = PaddleOCR(
    use_angle_cls=False,
    det_model_dir='/root/paddleocr_models/ch_PP-OCRv4_det_infer',
    rec_model_dir='/root/paddleocr_models/ch_PP-OCRv4_rec_infer',
    cls_model_dir='/root/paddleocr_models/ch_ppocr_mobile_v2.0_cls_infer',
    use_gpu=False
)

# 初始化 OpenAI 客户端(支持 DeepSeek)
client = OpenAI(
    api_key=os.getenv("DEEPSEEK_API_KEY"),  # 推荐使用环境变量
    base_url="https://api.deepseek.com/v1"  # ✅ DeepSeek 的 API 地址
)

# OCR 处理函数
def run_ocr_on_image(image_path, ocr):
    result = ocr.ocr(image_path, cls=False)
    image = Image.open(image_path).convert("RGB")
    draw = ImageDraw.Draw(image)

    try:
        font = ImageFont.truetype("simfang.ttf", 18)
    except:
        font = ImageFont.load_default()

    for line in result[0]:
        box = [tuple(point) for point in line[0]]
        text = line[1][0]
        draw.line(box + [box[0]], fill=(255, 0, 0), width=2)
        draw.text(box[0], text, fill=(0, 0, 255), font=font)

    return result[0], image

# 保存 OCR 结果为 JSON 格式
def save_json_data(result):
    return [
        {
            "text": line[1][0],
            "confidence": float(line[1][1]),
            "box": [list(map(float, pt)) for pt in line[0]]
        }
        for line in result
    ]

# 构造 Prompt 给大模型
def build_prompt(ocr_json):
    text_lines = [entry["text"] for entry in ocr_json if entry["confidence"] > 0.6]
    prompt = (
        "以下是通过 OCR 识别的一段图片文字,请将它们整理成通顺、自然的中文段落,以便人类阅读:\n\n"
        + "\n".join(text_lines)
    )
    return prompt

# 使用 DeepSeek 的 Chat 接口流式生成
def stream_openai_response(prompt):
    def generate():
        response = client.chat.completions.create(
            model="deepseek-chat",  # DeepSeek 支持 deepseek-chat 或 deepseek-coder
            messages=[
                {"role": "system", "content": "你是一个擅长文字整理的助手。"},
                {"role": "user", "content": prompt}
            ],
            stream=True
        )
        for chunk in response:
            content = chunk.choices[0].delta.content
            if content:
                yield content
    return generate()

# 🔹 OCR + GPT 组合接口(流式返回)
@app.route('/ocr-chat', methods=['POST'])
def ocr_chat_api():
    if 'file' not in request.files:
        return jsonify({"error": "No file uploaded"}), 400

    file = request.files['file']
    filename = file.filename.lower()

    with tempfile.TemporaryDirectory() as tmpdir:
        file_path = os.path.join(tmpdir, file.filename)
        file.save(file_path)

        if any(filename.endswith(ext) for ext in ['.png', '.jpg', '.jpeg', '.bmp']):
            result, _ = run_ocr_on_image(file_path, ocr)
            ocr_json = save_json_data(result)
            prompt = build_prompt(ocr_json)
            return Response(stream_openai_response(prompt), content_type='text/plain; charset=utf-8')

        elif filename.endswith('.pdf'):
            return jsonify({"error": "PDF暂不支持流式返回"}), 400

        else:
            return jsonify({"error": "Unsupported file type"}), 400

# 🔹 原始 OCR 接口(JSON 输出)
@app.route('/ocr', methods=['POST'])
def ocr_api():
    if 'file' not in request.files:
        return jsonify({"error": "No file uploaded"}), 400

    file = request.files['file']
    filename = file.filename.lower()

    with tempfile.TemporaryDirectory() as tmpdir:
        file_path = os.path.join(tmpdir, file.filename)
        file.save(file_path)

        results = []

        if filename.endswith('.pdf'):
            images = convert_from_path(file_path, dpi=300)
            for idx, img in enumerate(images):
                img_path = os.path.join(tmpdir, f"page_{idx}.png")
                img.save(img_path)
                result, vis_image = run_ocr_on_image(img_path, ocr)
                json_data = save_json_data(result)
                results.append({
                    "page": idx + 1,
                    "results": json_data
                })

        elif any(filename.endswith(ext) for ext in ['.png', '.jpg', '.jpeg', '.bmp']):
            result, vis_image = run_ocr_on_image(file_path, ocr)
            json_data = save_json_data(result)
            return jsonify({"results": json_data})

        else:
            return jsonify({"error": "Unsupported file type"}), 400

        return jsonify({"results": results})

# 启动服务
if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

balance…

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值