目录
- 完整流程(联网机器 + 离线机器)
- 在离线机器上:
- 下载 Miniconda(Linux 64-bit)
- 安装 Miniconda(默认安装到 ~/miniconda3)
- 激活 conda
- 创建 conda 环境(Python 3.8)
- 安装 PaddlePaddle(GPU 版本,若用 CPU 则替换为 `paddlepaddle`)
- 安装 PaddleOCR
- 安装 OpenCV 等依赖
- 测试1:检查 PaddlePaddle 是否能正确识别 GPU
- 测试2:运行 PaddleOCR 测试(自动下载模型)
- 创建模型存储目录
- 下载检测、识别、分类模型
- 解压模型
- 使用本地模型运行 OCR(不联网)
- 打包 conda 环境
- 打包模型文件
- 打包 pip 下载的 wheel 文件(可选,用于极端离线情况)
- 2. 在离线机器上部署
- 进阶版python文件
- 将代码封成http服务返回json
- 返回json传递给opei 有人能识别的效果
完整流程(联网机器 + 离线机器)
目标
在联网机器上:
安装 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 应能正常运行,无需联网。
📝 最终检查清单
步骤 联网机器 离线机器
- 安装 Miniconda ✅ 安装并测试 ✅ 仅安装
- 创建 Conda 环境 ✅ 安装 PaddleOCR ✅ 解压恢复
- 测试 OCR ✅ 在线模型 + 本地模型 ✅ 仅本地模型
- 打包环境 ✅ 生成 paddle_env.tar.gz ❌ 不需要
- 预下载模型 ✅ 生成 paddleocr_models.tar.gz ✅ 解压使用
- 离线 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)