OCR技术,感觉都像是过时的技术了,现在的多模态(VL)模型那么香,什么场景还会用 OCR 呢?

VL模型确实好用,但在实际使用后也有很大的缺点。NLP 模型就已经很慢了, VL模型的推理速度更慢,token 费用还是 NLP模型的好几倍。很难在实际项目中大规模使用。

我曾今以为,VL模型就是 OCR + NLP 模型。先通过 OCR技术识别图片中的文字等元素及其坐标信息。然后在给 NLP模型去推理。实际并不是,下面是二者的介绍

1. OCR与VL模型

1.1. OCR

OCR 是一种将图片、扫描文档、手写文字等非文本信息转换成可编辑、可搜索的文本的技术。
它的核心目标是让计算机“读懂”图片里的文字,从而实现文字信息的数字化。

OCR 的工作原理

OCR 的基本流程一般包括以下几个步骤:

  1. 图像预处理

    • 去噪(Noise Reduction):去掉背景噪声,提高识别准确率。
    • 二值化(Binarization):将彩色或灰度图转为黑白,方便后续处理。
    • 纠正倾斜(Deskew):调整扫描文档的倾斜角度。
    • 对比度增强(Contrast Enhancement):提高文字与背景的区分度。
  2. 文字区域检测

    • 使用算法(如 CTPN、EAST、DBNet 等)定位图片中的文字区域。
    • 分割出每一行、每一个字符或词。
  3. 字符识别

    • 传统方法:基于模板匹配、特征提取(如投影、轮廓、笔画)+分类器(SVM、KNN)。
    • 现代方法:基于深度学习的卷积神经网络(CNN)、循环神经网络(RNN)、Transformer 等,直接端到端识别文字。
  4. 后处理

    • 拼接字符序列为完整文本。
    • 使用语言模型或词典进行纠错(如拼写修正)。
    • 格式化输出(保留段落、表格等结构)。
OCR 的分类

根据应用场景和识别对象,OCR 可以分为:

  • 印刷体 OCR:识别印刷字体(报纸、书籍、票据等)。
  • 手写 OCR:识别手写文字(笔记、表单)。
  • 多语言 OCR:支持中文、英文、日文、韩文等多种语言。
  • 特殊字符 OCR:识别公式、化学结构、乐谱等。

OCR 的应用场景:

  • 文档数字化:将纸质书籍、档案扫描成可编辑文本。
  • 票据识别:发票、收据、车票等自动录入。
  • 身份证/护照识别:自动读取证件信息。
  • 车牌识别:交通管理、停车场收费系统。
  • 图像搜索:在图片中搜索文字内容。
  • 辅助工具:帮助视障人士“读”文字信息。
常用 OCR 技术与工具
  • 开源工具

    • Tesseract OCR:Google 维护的开源 OCR 引擎,支持多语言。
    • PaddleOCR:百度飞桨的 OCR 工具,支持检测+识别一体化。
    • EasyOCR:基于 PyTorch 的轻量级 OCR。
  • 商业服务

    • Google Cloud Vision API
    • Microsoft Azure OCR
    • 百度智能云 OCR
    • 阿里云 OCR
    • 腾讯云 OCR

1.2. VL模型

VL 模型(Vision-Language Model)是 同时处理视觉信息(图片/视频)和语言信息(文本)的大模型
它的目标是让机器具备类似人类的看图理解能力。

基本架构

一个典型的 VL 模型由两部分组成:

  1. 视觉编码器(Visual Encoder)

    • 常见架构:ViT(Vision Transformer)、Swin Transformer、CLIP 的视觉部分。
    • 输入图片 → 输出一系列视觉特征向量。
    • 这些向量编码了图片的内容:物体、颜色、布局,甚至文字的形状。
  2. 语言模型(Language Model / Decoder)

    • Transformer 架构的大语言模型(LLM)。
    • 输入文字 token(或者视觉特征经过投影映射的 token)。
    • 输出文本(描述、回答、推理结果)。
  3. 跨模态对齐(Cross-Modal Alignment)

    • 视觉特征和语言特征通过投影到同一语义空间,实现信息融合。
    • 方式:Cross-Attention、多模态 Transformer、对比学习(Contrastive Learning)。
训练方式
  • 配对数据:图片 + 文本描述(caption)、视觉问答(Q&A)、OCR标注等。
  • 多任务训练:图像描述、问答、推理、文字转写、布局分析等。
  • 对比学习(如 CLIP):让图片和文本在同一语义空间靠近。
VL 模型中的“文字识别”

VL 模型可以“直接从像素识别文字”,它的文字识别过程不是传统 OCR 的分离式模块,而是融合在视觉编码器 + 语言模型的联合训练中

  • 视觉编码器会捕捉到文字的形状特征(例如字母的笔画、汉字的结构)。
  • 语言模型部分在训练中学会将这些视觉特征映射到对应的字符 token。
  • 推理时,模型在回答问题或生成描述时,可以直接输出图片中的文字,而无需调用外部 OCR。

例子

输入:一张街景图
任务:问“这家店的名字是什么?”
模型:视觉编码器提取整张图的特征,语言模型根据特征直接生成店名。

1.3. 区别

传统 OCR 流程:

  1. 检测文字区域(Text Detection):用专门的检测网络(如 EAST、DBNet)找出图片中有文字的地方。
  2. 裁剪这些区域,送到识别网络(如 CRNN)逐个识别字符。
  3. 输出结构化文本。

端到端 VL 模型(例如 GPT-4V、Kosmos-2、Qwen-VL):

  • 没有显式的“检测”步骤,也不会裁剪。
  • 视觉编码器直接接收整张图片的像素,并输出一组向量。
  • 语言模型通过这些向量在推理时“自己”找出文字的位置并识别,因为它在训练时已经学会了这个能力。
举个类比

你可以把它想成一个人:

  • 传统 OCR:先用眼睛扫描文字位置,放大局部,逐个认字。
  • 端到端 VL 模型:你看整张照片的时候,就能在脑中同时看到文字和图像,并且直接理解它写的是什么,无需额外“找字”步骤。
VL模型识字的核心:视觉编码器 + 文本解码器联合训练

(1)视觉编码器

  • 常见是 ViT(Vision Transformer) 或 CNN+Transformer。
  • 把图片切成小块(patches),每个 patch 转成向量(embedding)。
  • 这些向量包含了局部的颜色、形状、纹理等信息。
  • 对于有文字的区域,这些向量会包含字符的形状信息。

(2)跨模态对齐

  • 模型训练时,会输入图片和它对应的文本描述(caption)、文字转写(OCR标签)、或视觉问答答案。
  • 损失函数会引导模型让视觉特征和文字输出对齐。
  • 例如:训练数据可能是图片+“这张图片上的牌子写着 STOP”,模型必须学会从像素中找到对应的字母形状并生成“STOP”。

(3)解码文字

  • 语言模型部分(Transformer解码器)接收视觉编码器输出的向量。
  • 当模型需要输出文字时,它会从视觉特征中“取出”对应的形状信息并映射到字母/汉字的token。
  • 因为模型的词表里有字母、汉字等符号,视觉特征被训练成可以激活对应的token概率。

1.4. 适用于不同业务场景

  • OCR 是一种单模态视觉任务,目标是精准提取图片中的文字,通常输出纯文本+坐标。
  • VL 模型是多模态 AI 系统,文字识别只是它的一项能力,它更关注文字与视觉、语言的融合与推理。
  • 工业应用中常用混合方案

    • 用 OCR 提供高精度文字和位置信息
    • 用 VL 模型做语义理解、推理、生成
OCR
  • 优势

    • 精度高,尤其是小字、低分辨率、复杂字体
    • 可输出精确位置坐标
    • 结构化输出(适合文档、表格)
  • 劣势

    • 不理解文字与图像的语境
    • 需要额外 NLP 才能做推理
    • 对非文字视觉任务(如物体识别)无能为力
VL 模型
  • 优势

    • 同时理解文字和视觉内容
    • 能做跨模态推理(例如“图中写的折扣信息对应哪种商品?”)
    • 可端到端完成任务(不依赖外部 OCR)
  • 劣势

    • 小字或特殊字体识别精度可能不如专用 OCR
    • 输出坐标、版面结构的能力弱(除非特别训练)
    • 训练成本和数据需求大
应用场景的区别
场景推荐 OCR推荐 VL 模型
扫描文档电子化✅ 精准提取文本❌ 不擅长结构化输出
发票/票据录入✅ 高精度文字识别❌ 推理不必要
场景文字理解(招牌、广告)OCR 提取文字 + NLP✅ 可直接理解文字与场景关系
图文问答
图表数据问答OCR 提取数值 + LLM✅ 端到端理解图表内容

1.5. VL模型的Agent记忆与OCR

前面说: VL模型 不等于 OCR + NLP模型,但这不是绝对的。

大模型Agent设计中,记忆是实现多轮对话的根基。无论是长期记忆,还是短期记忆,都需要将历史模型识别结果存下来。NLP模型好办,直接存文本即可,那么 VL模型 的识别结果存什么呢?

基于一张图片的识别结果,这轮可能想分析图片中某个内容,下一轮想分析图片的内容又不一样,不能每轮对话都将历史的图片重新识别一遍。

常见方案根据要识别的图片类型来。如果是一只猫的图片,OCR起不到什么作用,还是交给 实现VL模型的嵌入模型来采集特征,将特征存储向量库,后续想要获取的特征信息("猫的颜色"、"猫的品种")都基于向量检索。

但如果是基于文本的图片,例如:演讲稿、车票等照片。还是更适合直接使用 OCR工具来,将图片中的文字、坐标等信息转换成文本存储下来。基于文本的记忆就很容易实现了。

2. PaddleOCR

2.1. 介绍

PaddleOCR 是由 百度飞桨(PaddlePaddle)团队开源的 OCR(Optical Character Recognition,光学字符识别)全流程解决方案。
它的目标是:

提供从数据准备、模型训练、评估,到推理、部署的端到端 OCR 工具库,支持多语言、多场景。

首个版本在 2020 年推出,至今已经迭代到 PP-OCRv5,并形成了一个庞大的开源社区。

技术特点
  • 全流程支持:训练 + 推理 + 部署。
  • 多语言多场景:适合全球化应用。
  • 轻量化模型:PP-OCR 系列适合移动端。
  • 社区活跃:有丰富的教程和预训练模型。
适用场景
  • 需要从零训练或微调模型。
  • 需要版面分析、表格识别等高级功能。
  • 部署环境能接受 PaddlePaddle 框架的体积和依赖。
  • 研究和教学用途。
核心功能
  1. 文字检测

    • 定位图片中的文字区域。
    • 支持多种检测模型:DBNet、EAST、SAST、PSE 等。
    • 支持旋转文本检测。
  2. 文字识别

    • 将检测到的文字区域转为可读文本。
    • 支持多语言(80+种),包括中文、英文、日文、韩文、阿拉伯文等。
    • 常用识别模型:CRNN、SVTR、RARE、Rosetta 等。
  3. 方向分类

    • 检测文字方向(如 0°、90°、180°、270°),自动矫正。
  4. 版面分析

    • 对复杂文档进行版面结构解析(Layout Analysis)。
    • 表格识别、公式识别、印章检测等。
  5. 模型训练与优化

    • 支持自定义数据集训练。
    • 提供数据增强、迁移学习、蒸馏、量化等优化方法。
  6. 多平台部署

    • 支持 Python、C++、Paddle Lite(移动端)、Paddle Serving(服务端)、Docker 等。

2.2. 安装

使用 PaddleOCR,需要先安装 Paddle 飞桨框架,虽然官方命令简单,但要处理本地电脑的各类环境版本问题。

如果只是体验,建议直接安装 Docker 版本,参考官方文档:Paddle 安装文档

参考其中 基于 Docker 安装飞桨 部分,没有 GPU 条件,就选择 CPU 即可。

也可以参考以下脚本:

#!/bin/bash
# 启动 PaddleOCR 容器(后台运行且保持不退出,并自动安装 paddleocr)

CONTAINER_NAME="paddleocr"
IMAGE="ccr-2vdh3abv-pub.cnc.bj.baidubce.com/paddlepaddle/paddle:3.0.0"

# 如果容器已经存在,则先删除
if [ "$(docker ps -aq -f name=$CONTAINER_NAME)" ]; then
    echo "删除已有容器 $CONTAINER_NAME..."
    docker rm -f $CONTAINER_NAME
fi

echo "启动容器 $CONTAINER_NAME..."
docker run --name $CONTAINER_NAME \
    --platform linux/amd64 \
    -v "$PWD":/paddle \
    -p 8080:8080 \
    --shm-size=8G \
    -d \
    $IMAGE \
    tail -f /dev/null

# 等容器启动稳定
sleep 3

echo "在容器中安装 paddleocr..."
docker exec $CONTAINER_NAME python -m pip install paddleocr

echo "容器 $CONTAINER_NAME 已启动并安装完成"
echo "进入容器请执行:docker exec -it $CONTAINER_NAME /bin/bash"

安装完成后,既可以通过 paddle 的 cli 执行命令训练、推理。

CLI 测试命令,并且将可视化结果图片存在 ./output 目录。

paddleocr ocr -i ./1.jpg \
    --use_doc_orientation_classify False \
    --use_doc_unwarping False \
    --use_textline_orientation False \
    --save_path ./output \
    --device gpu:0 

当然,最方便的方式是通过 HTTP 方式调用 OCR 推理服务。

官网也提供了启动 HTTP 服务端的文档:服务化部署

脚本中映射 8080 端口,就是为了宿主机能直接方法 HTTP 服务端。

调用 HTTP API 参数文档:API 请求参数说明

上传图片方式限制

通过看API文档可见,上传图片/PDF时,仅支持两种方式:

  • 文件 URL
  • BASE64 编码

默认不支持文件流传输,这两种方式都会限制上传图片速度。

3. RapidOCR

3.1. 介绍

RapidOCR 是一个轻量级 OCR 推理库,由国内开发者开源,核心理念是:

只做 OCR 推理,不负责训练,简化部署和集成,让 OCR 模型可以在不同平台快速运行。

它本质上是一个精简版推理工具,可以直接加载 PaddleOCR 训练好的模型(或其他兼容模型),并在多种推理后端运行。

技术特点
  • 轻量化:去掉训练、数据处理等复杂功能。
  • 启动快:不加载完整深度学习框架。
  • 灵活后端:可根据硬件选择最佳推理引擎。
  • 易集成:适合嵌入到 C++ 项目、移动应用等。
适用场景
  • 只做推理,不需要训练。
  • 需要在移动端、嵌入式设备部署。
  • 对启动速度和资源占用敏感。
  • 希望减少依赖,简化部署流程。
核心功能
  1. 模型加载与推理

    • 支持检测模型 + 识别模型的加载。
    • 输入图片,输出文字识别结果。
  2. 多推理后端支持

    • ONNX Runtime(跨平台)
    • NCNN(移动端 / 嵌入式)
    • Paddle Inference(原生 Paddle 推理)
    • OpenCV DNN(轻量推理)
  3. 跨平台运行

    • Windows / Linux / macOS / Android / iOS / 嵌入式设备。
  4. 简洁 API

    • 几行代码即可完成 OCR 推理。

3.2. 安装

Rapid OCR 的官方文档参考:RapidOCR文档

通常安装 rapidocr 即可实现图片推理,有通过官方提供的配置参数,可以自定义不同场景的配置。

就包括使用的模型,可以直接配置 paddleocr 最新的 v5 模型。当然,推荐使用基于 ONNX 引擎的模型格式。

也可以通过安装 rapidocr_web 实现功能更丰富的 WEB 服务。rapidocr_web是基于rapidocr库封装的web版OCR程序。它可以让小伙们快速在本地启动OCR服务,支持剪贴板、拖拽和选择图像文件上传识别,同时具有一键复制识别文本功能

如果更方便的安装,并且只需要 HTTP API,可以通过 rapidocr_api 安装。该包是将rapidocr库做了API封装,采用FastAPI + uvicorn实现。

这里也推荐 Docker 快速安装的法子。这次官网的文档不是很准确,仓库已经更新为RapidOCRAPI,但文档依然是 RapidOCR。踩过坑,推荐自己构建镜像再运行。

RapidOCRAPI - releases 中拉取最新 releases 的代码下来,在项目根目录有 Dockerfile 文件,直接基于该 Dockerfile 构建镜像,然后安装文档指令运行即可。

目前最新 releases 是 0.2.0,但项目的 Dockerfile 有个坑。

  • FROM python:3.10.11-slim-buster 已经过时了,可以改成
    FROM python:3.10-slim-bullseye
  • 如果是在mac电脑构建的镜像,默认是 arm64架构,linux 环境运行会有问题。如果希望制定构建成功 amd64架构,可以改成 FROM --platform=linux/amd64 python:3.10-slim-bullseye

容器启动时,HTTP 服务器即自动启动了。可以在容器内修改模型文件等配置。这里的 API 就支持基于文件流上传,而且感觉推理速度也比 PaddleOCR快。

3.3. 安装建议

虽然前面说有 rapidocr_webrapidocr_api,但都是首页介绍的,属于快速上手的工具。
但这些工具只是为了让你快速体验,看到效果,可靠性不高。

在看了几个项目的git代码后,总结:

  • rapidocr_api:只是基于引入了 FastAPIuvicorn的包,写了一个 python 启动API的文件,代码里面直接调用 rapidocr
  • rapidocr_web:在 rapidocr_api 的基础上再套一个前端页面。

实际使用,还是建议直接用 rapidocr,就一个 python 脚本咱自己写就好了,也不难,后期想再修改、增加API都容易。

而且 rapidocr 是他们核心应用,更新维护的更频繁。rapidocr_apirapidocr_web 不仅仅是版本落后,而且官网的WIKI文档和实际仓库的代码很多都对不上。

如果你基于 rapidocr 开发API,提供定制化的OCR接口。建议把 RapidOCR Git仓库 的代码拉下来,看看哪些类、方法可用,看不明白的让AI来辅助分析。

rapidocr 虽然是他们的核心项目,但一旦涉及到开发阶段,官网的文档啥也没有。和同时期在看 YOLO 的官网文档差远了,不明白国内的公司怎么都这样。

RapidOCR 提供 API示例

Dockerfile

FROM --platform=linux/amd64 python:3.11.13-slim-bullseye

ENV DEBIAN_FRONTEND=noninteractive

# 设置工作目录
WORKDIR /rapidocr

# 安装vim,如果不需要临时修改容器文件,此步骤可以删
RUN apt-get update && \
    apt-get install -y --no-install-recommends vim && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

# 安装Python依赖
RUN pip install --no-cache-dir \
    requests \
    fastapi \
    uvicorn[standard] \
    python-multipart \
    pillow \
    numpy \
    rapidocr \
    onnxruntime \
    -i https://mirrors.aliyun.com/pypi/simple && \
    pip uninstall -y opencv-python && \
    pip install --no-cache-dir opencv-python-headless -i https://mirrors.aliyun.com/pypi/simple

COPY ocr.py .

CMD ["uvicorn", "ocr:app", "--host", "0.0.0.0", "--port", "9103", "--workers", "2"]

基于实际流量需求和CPU核心数,设置 --workers 数量。

提供API 的 ocr.py 代码

import base64
import io
import cv2
import numpy as np
from typing import Dict, Optional
from fastapi import FastAPI, Form, UploadFile
from fastapi.responses import Response, StreamingResponse
from PIL import Image
from rapidocr import RapidOCR
from rapidocr.utils.vis_res import VisRes


class OCRProcessor:
    """OCR 处理器类"""
    
    def __init__(self):
        """
        初始化 OCR 引擎
        支持通过环境变量自定义模型路径
        """
        self.ocr_engine = RapidOCR()
        # 初始化可视化工具
        self.vis_tool = VisRes(text_score=0.5)
        # self.ocr_engine = RapidOCR(
        #     params={
        #         "Det.engine_type": EngineType.ONNXRUNTIME,
        #         "Det.lang_type": LangDet.CH,
        #         "Det.model_type": ModelType.SERVER,
        #         "Det.ocr_version": OCRVersion.PPOCRV5,
        #         "Rec.engine_type": EngineType.ONNXRUNTIME,
        #         "Rec.lang_type": LangRec.CH,
        #         "Rec.model_type": ModelType.SERVER,
        #         "Rec.ocr_version": OCRVersion.PPOCRV5,
        #         }
        #     )

    
    def process_image(
        self, 
        image: Image.Image, 
        use_det: Optional[bool] = True,
        use_cls: Optional[bool] = False,
        use_rec: Optional[bool] = True
    ) -> Dict:
        """
        处理图像并返回 OCR 结果
        
        Args:
            image: PIL Image 对象
            use_det: 是否使用文本检测
            use_cls: 是否使用文本方向分类
            use_rec: 是否使用文本识别
            
        Returns:
            包含 OCR 结果的字典
        """
        # 将 PIL Image 转换为 numpy 数组
        img_array = np.array(image)
        
        # 执行 OCR (新版本返回 RapidOCROutput 对象)
        ocr_output = self.ocr_engine(
            img_array,
            use_det=use_det,
            use_cls=use_cls,
            use_rec=use_rec
        )
        
        # 处理 RapidOCROutput 对象
        # RapidOCROutput 有 boxes, txts, scores 属性
        if ocr_output.boxes is None or ocr_output.txts is None or len(ocr_output) == 0:
            return {}
        
        boxes_list = ocr_output.boxes
        txts_list = ocr_output.txts
        scores_list = ocr_output.scores
        
        output = {}
        for idx, (boxes, txt, score) in enumerate(zip(boxes_list, txts_list, scores_list)):
            output[idx] = {
                "rec_txt": txt,
                "dt_boxes": boxes.tolist() if isinstance(boxes, np.ndarray) else boxes,
                "score": float(score)
            }
        return output
    
    def visualize_image(
        self, 
        image: Image.Image, 
        use_det: Optional[bool] = True,
        use_cls: Optional[bool] = False,
        use_rec: Optional[bool] = True,
        return_format: str = "image"
    ):
        """
        处理图像并返回可视化结果
        
        Args:
            image: PIL Image 对象
            use_det: 是否使用文本检测
            use_cls: 是否使用文本方向分类
            use_rec: 是否使用文本识别
            return_format: 返回格式,"image" 或 "base64"
            
        Returns:
            可视化后的图片(numpy 数组)或 base64 字符串
        """
        # 将 PIL Image 转换为 numpy 数组
        img_array = np.array(image)
        
        # 执行 OCR
        ocr_output = self.ocr_engine(
            img_array,
            use_det=use_det,
            use_cls=use_cls,
            use_rec=use_rec
        )
        
        # 如果没有检测到文本,返回原图
        if ocr_output.boxes is None or ocr_output.txts is None or len(ocr_output) == 0:
            if return_format == "base64":
                # 转换为 base64
                _, buffer = cv2.imencode('.png', cv2.cvtColor(img_array, cv2.COLOR_RGB2BGR))
                img_base64 = base64.b64encode(buffer).decode('utf-8')
                return img_base64
            return img_array
        
        # 使用 VisRes 可视化结果
        vis_img = self.vis_tool(
            img_array,
            ocr_output.boxes,
            ocr_output.txts,
            ocr_output.scores
        )
        
        if return_format == "base64":
            # 转换为 base64
            _, buffer = cv2.imencode('.png', vis_img)
            img_base64 = base64.b64encode(buffer).decode('utf-8')
            return img_base64
        
        return vis_img


app = FastAPI()
ocr_processor = OCRProcessor()


@app.get("/")
def root():
    return {"message": "Welcome to RapidOCR API Server!"}


@app.post("/ocr")
def ocr(
    image_file: Optional[UploadFile] = None,
    image_data: str = Form(None),
    use_det: bool = Form(True),
    use_cls: bool = Form(False),
    use_rec: bool = Form(True),
):
    if image_file:
        img = Image.open(image_file.file)
    elif image_data:
        img_bytes = str.encode(image_data)
        img_b64decode = base64.b64decode(img_bytes)
        img = Image.open(io.BytesIO(img_b64decode))
    else:
        raise ValueError(
            "When sending a post request, data or files must have a value."
        )
    ocr_res = ocr_processor.process_image(
        img, use_det=use_det, use_cls=use_cls, use_rec=use_rec
    )
    return ocr_res


@app.post("/ocr/image")
def ocr_visualize(
    image_file: Optional[UploadFile] = None,
    image_data: str = Form(None),
    use_det: bool = Form(True),
    use_cls: bool = Form(False),
    use_rec: bool = Form(True),
    return_base64: bool = Form(False),
):
    """
    OCR 可视化接口
    
    Args:
        image_file: 上传的图片文件
        image_data: base64 编码的图片数据
        use_det: 是否使用文本检测
        use_cls: 是否使用文本方向分类
        use_rec: 是否使用文本识别
        return_base64: 是否返回 base64 格式(True)还是图片流(False)
        
    Returns:
        如果 return_base64=True: 返回 JSON {"image": "base64_string"}
        如果 return_base64=False: 返回图片文件流(PNG 格式)
    """
    # 解析图片
    if image_file:
        img = Image.open(image_file.file)
    elif image_data:
        img_bytes = str.encode(image_data)
        img_b64decode = base64.b64decode(img_bytes)
        img = Image.open(io.BytesIO(img_b64decode))
    else:
        raise ValueError(
            "When sending a post request, data or files must have a value."
        )
    
    # 获取可视化结果
    if return_base64:
        # 返回 base64 格式
        vis_result = ocr_processor.visualize_image(
            img, 
            use_det=use_det, 
            use_cls=use_cls, 
            use_rec=use_rec,
            return_format="base64"
        )
        return {"image": vis_result}
    else:
        # 返回图片流
        vis_img = ocr_processor.visualize_image(
            img, 
            use_det=use_det, 
            use_cls=use_cls, 
            use_rec=use_rec,
            return_format="image"
        )
        
        # 将 numpy 数组转换为字节流
        _, buffer = cv2.imencode('.png', vis_img)
        img_bytes = io.BytesIO(buffer.tobytes())
        
        return StreamingResponse(
            img_bytes, 
            media_type="image/png",
            headers={"Content-Disposition": "inline; filename=ocr_result.png"}
        )

4. 二者对比

在 RapidOCR 上可以使用 PaddleOCR 多版本的模型 rapidOCR模型列表

很多人在初学 PaddleOCR 和 RapidOCR 的时候都会有同样的疑惑:
“既然 RapidOCR 也是用 PaddleOCR 的模型,那直接用 PaddleOCR 推理不就好了?为什么还要用 RapidOCR?”

4.1. 二者对比

直接运行 PaddleOCR 的特点
  • 优点

    1. 功能非常全面:除了推理,还能训练、评估、版面分析、多语言支持等。
    2. 官方维护,文档和社区活跃。
    3. 支持 PaddlePaddle 的全套生态(Paddle Lite、Paddle Serving 等)。
    4. 直接使用预训练模型,简单命令即可完成 OCR。
  • 缺点

    1. 依赖多:需要安装 PaddlePaddle(深度学习框架),体积较大。
    2. 启动慢:第一次加载模型和框架初始化时间较长。
    3. 跨平台部署复杂:在 Android/iOS/嵌入式设备上部署 PaddlePaddle 推理库相对麻烦。
    4. 集成成本高:如果你只是想在一个小工具里做推理,PaddleOCR 的代码和依赖会显得“笨重”。
RapidOCR 的特点
  • 优点

    1. 轻量化:只保留推理部分,代码和依赖精简很多。
    2. 跨平台方便:支持 ONNX Runtime、NCNN、OpenCV 等多种后端,适合在 Windows/Linux/macOS/Android/iOS/嵌入式设备部署。
    3. 启动快:不需要加载完整的 Paddle 框架,推理引擎初始化速度快。
    4. 集成简单:API 很精简,几行代码就能跑通。
    5. 多后端选择:可以根据硬件选择最佳推理引擎(例如在 GPU 用 TensorRT,在移动端用 NCNN)。
    6. 依赖可控:比如你用 ONNX Runtime 推理,只需要安装 onnxruntime 库,不必安装 PaddlePaddle。
  • 缺点

    1. 不能训练模型。
    2. 功能比 PaddleOCR 少(比如版面分析、表格识别等高级功能不内置)。
    3. 文档和社区规模比 PaddleOCR 小。
对比结论
需求/特性PaddleOCRRapidOCR
功能范围全流程(训练+推理+分析)仅推理(检测+识别)
依赖体积大(需要 PaddlePaddle)小(可选 ONNX/NCNN 等)
跨平台部署相对复杂非常方便
启动速度较慢较快
集成成本高(代码量大)低(API 简单)
适合场景研究、训练、功能全面部署轻量化部署、移动端、嵌入式

4.2. 什么场景适用使用

什么时候选 PaddleOCR,什么时候选 RapidOCR?
  • 选 PaddleOCR

    • 需要自己训练模型。
    • 需要版面分析、表格识别等高级功能。
    • 部署环境可以接受 PaddlePaddle 的体积和依赖。
    • 开发阶段,需要快速测试各种模型和参数。
  • 选 RapidOCR

    • 只做推理,不需要训练。
    • 目标平台是移动端、嵌入式设备、跨平台应用。
    • 需要轻量化部署,减少依赖和启动时间。
    • 想要灵活选择推理后端(ONNX Runtime、NCNN、TensorRT 等)。
    • 对集成简洁性要求高(比如嵌入到一个 C++ 项目或小型工具里)。
一句话总结
  • PaddleOCR 是一个功能全面的“工厂”,适合生产和测试模型;
  • RapidOCR 是一个轻量化的“收银机”,适合快速、低成本地部署现成模型。
  • 如果你只需要跑模型,RapidOCR 会更轻、更快、更好集成。

5. ONNX

PaddleOCR 模型能在 RapidOCR 上运行,就是因为转换成 ONNX格式。包括后续还有文章介绍 Yolo 模型,也是要转换成 ONNX 格式才会有更多部署平台。

好的,我们来系统、详细地介绍一下 ONNX(Open Neural Network Exchange),包括它的背景、作用、技术细节、生态、优缺点、使用场景,以及它与 PaddleOCR/RapidOCR 的关系。

5.1. 定义

ONNX 全称 Open Neural Network Exchange,是一个 开放的深度学习模型交换格式跨框架推理生态
它由 微软(Microsoft)Facebook(Meta) 在 2017 年联合推出,后来得到了 AWS、NVIDIA、Intel、AMD 等众多厂商的支持。

核心目标

提供一个统一的中间表示(Intermediate Representation, IR),让不同深度学习框架之间的模型可以互相转换和运行,从而避免“框架锁定”。
  • ONNX = 深度学习模型的“通用语言”,让模型可以跨框架、跨平台运行。
  • 它解决了训练框架和部署环境之间的“语言不通”问题。
  • 在 OCR 场景下,ONNX 让 PaddleOCR 的模型可以用 RapidOCR 在各种设备上运行。
解决痛点

在深度学习应用中,常见的痛点是:

  • 跨框架问题:模型在 PyTorch 中训练,但部署环境只支持 TensorFlow 或 C++。
  • 跨平台问题:需要在移动端、嵌入式设备上运行模型,但原框架不适合直接部署。
  • 硬件优化问题:希望在不同硬件(CPU / GPU / NPU / FPGA)上快速切换推理引擎。

ONNX 就像一个通用适配器

  • 训练时用你喜欢的框架(PyTorch、TensorFlow、PaddlePaddle 等)。
  • 导出成 ONNX 格式。
  • 部署时用任何支持 ONNX 的推理引擎(ONNX Runtime、TensorRT、OpenVINO、NCNN 等)。

5.2. ONNX 的核心组成

ONNX 模型格式
  • 文件后缀 .onnx
  • 基于 Protocol Buffers 存储。
  • 包含:

    • 计算图结构(Graph)
    • 算子定义(Operators)
    • 模型权重(Weights)
  • 结构化且跨平台可解析。
ONNX 算子集(Operator Set)
  • 定义了标准算子(如 Conv、Relu、MatMul、Softmax 等)。
  • 每个算子有版本号(opset version),保证不同版本间的兼容性。
  • 框架在导出时会选择合适的 opset 版本。
ONNX Runtime
  • 由微软开源的高性能推理引擎。
  • 支持多种硬件后端:

    • CPU(默认)
    • GPU(CUDA)
    • TensorRT
    • DirectML(Windows GPU)
    • OpenVINO(Intel CPU/FPGA)
  • 提供多语言 API:Python、C、C++、C#、Java、JavaScript 等。
ONNX 的工作流程

一个典型的 ONNX 使用流程:

  1. 训练模型

    • 在 PyTorch / TensorFlow / PaddlePaddle / MXNet 等框架中训练。
  2. 导出 ONNX 模型

    • PyTorch:

      torch.onnx.export(model, input_data, "model.onnx", opset_version=11)
    • TensorFlow:

      python -m tf2onnx.convert --saved-model ./model --output model.onnx
    • PaddlePaddle(PaddleOCR):

      python tools/export_model.py --output_dir ./inference --export_onnx True
  3. 加载并推理

    • 使用 ONNX Runtime(或其他支持 ONNX 的引擎):

      import onnxruntime as ort
      session = ort.InferenceSession("model.onnx")
      outputs = session.run(None, {"input": input_array})
  4. 部署到目标平台

    • Windows / Linux / macOS / Android / iOS / 嵌入式设备等。
ONNX 的常见使用场景
  1. 跨框架部署

    • 在 PyTorch 训练 → 转 ONNX → 在 TensorRT 推理。
  2. 移动端 / 嵌入式部署

    • 转 ONNX → 用 NCNN/MNN/OpenVINO 等运行。
  3. 云端推理服务

    • 用 ONNX Runtime 部署到云端,支持多语言调用。
  4. 模型优化

    • ONNX Runtime 支持图优化、算子融合、量化等。

5.3. 优缺点

ONNX 的优点
  1. 跨框架

    • 支持 PyTorch、TensorFlow、PaddlePaddle、MXNet 等互转。
  2. 跨平台

    • 同一个 ONNX 模型可在不同操作系统和硬件上运行。
  3. 高性能

    • ONNX Runtime 针对不同硬件有深度优化。
  4. 生态丰富

    • TensorRT、OpenVINO、NCNN、MNN 等均支持 ONNX。
  5. 开放标准

    • 由社区维护,透明可扩展。
ONNX 的缺点 / 限制
  1. 算子兼容性问题

    • 不同框架���某些自定义层可能无法直接转换,需要自己实现。
  2. 版本问题

    • ONNX 模型的 opset 版本不匹配时可能会报错。
  3. 动态图支持有限

    • 对部分动态图功能支持不如原框架灵活。

5.4. 与 PaddleOCR/RapidOCR的关系

  • PaddleOCR

    • 可将训练好的检测模型和识别模型导出为 ONNX 格式。
    • 方便跨平台部署,不依赖 PaddlePaddle。
  • RapidOCR

    • 内置 ONNX Runtime 后端。
    • 可以直接加载 PaddleOCR 导出的 ONNX 模型进行推理。
    • 这样就能在没有 PaddlePaddle 框架的环境中运行 OCR(例如移动端或嵌入式)。

简单来说
ONNX 是模型的通用格式,RapidOCR 是一个能读取 ONNX 模型并运行的轻量化推理工具。

5.5. Java项目可运行ONNX模型

  • ONNX 本身是一种通用的模型文件格式(.onnx),不依赖具体的编程语言。
  • 要在 Java(包括 Spring Boot)中运行 ONNX 模型,需要一个支持 ONNX 格式的推理引擎。
  • ONNX Runtime 是官方提供的高性能推理引擎,它有 Java API,可以在 JVM 环境中直接加载 .onnx 模型并运行。
  • 因此,在 Spring 项目中,你可以:

    1. 把 ONNX 模型文件放在项目资源目录或本地路径。
    2. 使用 ONNX Runtime Java API 加载模型。
    3. 在业务代码中调用推理方法获得结果。

在 Maven 项目的 pom.xml 中添加 ONNX Runtime 依赖:

<dependency>
    <groupId>com.microsoft.onnxruntime</groupId>
    <artifactId>onnxruntime</artifactId>
    <version>1.15.1</version> <!-- 版本可根据需要选择 -->
</dependency>

如果需要 GPU(CUDA)推理,可以用:

<dependency>
    <groupId>com.microsoft.onnxruntime</groupId>
    <artifactId>onnxruntime_gpu</artifactId>
    <version>1.15.1</version>
</dependency>

没错,Java项目中,你可以本地直接运行 PaddleOCR 的模型文件, 前提是和 RapidOCR 一样,先转成 ONNX 格式。


KerryWu
679 声望171 粉丝

保持饥饿