跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++AI算法

C++调用PaddleOCR进行图像推理

记录了在 Windows 环境下编译 PaddleOCR 源码并封装为 C++ 动态库的过程。主要步骤包括准备 CMake、OpenCV 及 Paddle Inference 库,配置 CMake GUI 解决依赖问题,编写封装接口(init、run_det、run_rec),并在 MFC 项目中调用该库进行图像文字检测与识别。文中提供了关键代码示例及编译注意事项,解决了 C++ 集成 PaddleOCR 的常见问题。

CodeArtist发布于 2026/3/29更新于 2026/10/24108 浏览

前言

本文记录了在 Windows 环境下编译 PaddleOCR 源码并封装为 C++ 动态库的过程。

准备工作

在对 paddleocr 进行编译前,需要提前准备需要的文件:

  1. CMake 4.2.1 版本较新即可
  2. OpenCv 库,官网下载最新的 Windows 安装包即可
  3. paddle_inference 库,同样的在百度飞桨官网上可以找到,也是 windows 预编译版,下载下来即可使用。地址 https://www.paddleocr.ai/latest/version3.x/pipeline_usage/OCR.html#1-ocr
  4. VS2019 及以上。

检测模型和识别模型,在 paddleocr GitHub 上可以下载到,分为服务端模型和移动端模型,如下:

开始编译

首先,在 PaddleOcr 源码 PaddleOCR-3.3.0\deploy\cpp_infer 目录下创建一个 build 目录,打开 Cmake 的 gui,将此目录下的 cmakelist 拖入其中。将编译完保存的目录改成 PaddleOCR-3.3.0\deploy\cpp_infer\build。然后点击 Configure,等执行失败后,设置 openCv 库,以及 paddle_inference 库的目录。

这里的设置千万不要错,否则后面生成的 vs 工程很多东西需要手动去改,烦的很。 设置完成后继续点击 Configure,中途可能会出现提示某些 CMake 版本较低,无需多言,根据提示手动找到对应文件的 CMakeList 将 CMake 版本标识改成 4.2.1,然后继续编译即可。 这里大致上就会显示成功,然后点击 Generate 生成对应的 VS 工程,生成的 VS 工程位于 build 目录下 ppocr.sln。打开此项目,将编译版本改为 Release X64,点击编译。中途会提示缺少某个头文件。下载 dirent.h,并拷贝到 Visual Studio 的 include 文件夹下,如 C:\Program Files (x86)\Microsoft Visual Studio\2022\Community\VC\Auxiliary\VS\include。(此头文件可以在 此地址 里面找到)。 继续点击编译,不出意外,此时会显示编译成功。 在 build\release 目录下,会生成一个 ppocr.exe 的 demo 程序。在命令行中可以验证是否编译成功。

PS F:\project\paddleOcr\deploy\cpp_infer\build\Release> ./ppocr ocr --input ./test10.jpg --save_path F:/project/paddleOcr/output --text_detection_model_dir F:/project/paddleOcr/models/PP-OCRv5_server_det --text_recognition_model_dir \F:/project/paddleOcr/models\PP-OCRv5_server_rec --use_doc_orientation_classify False --use_doc_unwarping False --use_textline_orientation False --device cpu 

相关参数很简单。执行,然后就会显示识别的内容。在此过程中如果提示缺少某某动态库,需要手动将其放置到 ppocr.exe 目录下。

封装自己的动态库

经过上面的操作,已经能够在 c++ 中进行推理识别了。但是此时是一个 ppocr.exe 的程序,用起来肯定是不方便的。我们需要将其封装成动态库,更方便我们使用。在 ppocr 项目下有个 cli.cc 文件。此程序的 main 函数就在这里面。 此时在 ppocr 项目中新建一个 myocr.h 和 myocr.cpp 文件。在里面自己封装识别的逻辑,代码如下:

#pragma once
#include<string>
#include<opencv2/opencv.hpp>
#define OCR_API __declspec(dllexport)
namespace ocr {
struct OCR_API Result { cv::Mat img; std::string text; float score; cv::Rect rect;};
OCR_API bool init(const std::string &det_name,const std::string& det_dir,const std::string& rec_name,const std::string&rec_dir);
OCR_API std::vector<Result> run_det(cv::Mat& input);
OCR_API void run_rec(Result& result);
}
#include"paddle_ocr.h"
#include"src/api/pipelines/ocr.h"
static std::unique_ptr<TextDetPredictor> det_Predictor;
static std::unique_ptr<TextRecPredictor> rec_Predictor;
bool ocr::init(const std::string& det_name,const std::string& det_dir,const std::string& rec_name,const std::string& rec_dir){
try{ TextDetPredictorParams det_Params; det_Params.model_name = det_name; det_Params.model_dir = det_dir; det_Predictor = std::make_unique<TextDetPredictor>(det_Params);}
catch(std::exception &e){return false;}
try{ TextRecPredictorParams rec_Params; rec_Params.model_name = rec_name; rec_Params.model_dir = rec_dir; rec_Predictor = std::make_unique<TextRecPredictor>(rec_Params);}
catch(std::exception& e){return false;}
return true;}
std::vector<ocr::Result> ocr::run_det(cv::Mat& input){
std::vector<cv::Mat>inputs ={ input };
det_Predictor->ResetResult();
det_Predictor->Process(inputs);
std::vector<TextDetPredictorResult>det_results = det_Predictor->PredictorResult();
std::vector<ocr::Result>result;
for(int i =0; i < det_results.size(); i++){
TextDetPredictorResult det_result = det_results[i];
for(int j =0; j < det_result.dt_scores.size(); j++){
ocr::Result r; r.score = det_result.dt_scores[j];
std::vector<cv::Point2f>item = det_result.dt_polys[j];
r.rect = cv::Rect(item[0], item[2]);
r.img = det_result.input_image(r.rect).clone();
result.push_back(r);
}}
return result;}
void ocr::run_rec(ocr::Result& result){
std::vector<cv::Mat>inputs ={result.img};
rec_Predictor->ResetResult();
rec_Predictor->Process(inputs);
std::vector<TextRecPredictorResult> rec_results = rec_Predictor->PredictorResult();
result.text = rec_results[0].rec_text;
result.score = rec_results[0].rec_score;}

可以根据自己的需求,随意封装,此处只为一个例子,优化的地方还很多。 可以在 cil.cc 中验证自己的封装。将里面的代码注释掉,例如添加如下代码:

#include"./build/paddle_ocr.h"
#include<Windows.h>
int main(){
SetConsoleOutputCP(CP_UTF8);
bool ret = ocr::init("PP-OCRv5_server_det","F:/project/paddleOcr/models/PP-OCRv5_server_det","PP-OCRv5_server_rec","F:/project/paddleOcr/models/PP-OCRv5_server_rec");
std::cout << "ret is" << ret << std::endl;
cv::Mat img = cv::imread("F:/project/paddleOcr/deploy/cpp_infer/build/Release/test10.png", cv::IMREAD_COLOR_BGR);
std::vector<ocr::Result>results = ocr::run_det(img);
for(int i=0;i<results.size();i++){
ocr::Result item = results[i];
ocr::run_rec(item);
std::cout << item.score << "\t["<< item.rect.x <<","<< item.rect.y <<","<< item.rect.width <<","<< item.rect.height <<"]\t"<< item.text << std::endl;
}}

用来检验自己封装的正确性。 在成功之后,在 VS 工程的配置属性中,将输出文件拓展名改成.dll,配置类型改为动态库。然后重新编译生成此项目。

如何在自己的项目中使用

以上已经完成对 paddleocr 动态库的封装,下面介绍如何使用。 首先对动态库的头文件进行稍加修改。如下:

#pragma once
// ocr_api.h
#include<string>
#include<vector>
#include<opencv2/opencv.hpp>
// 注意:这里不能用 __declspec(dllexport),而是 dllimport!
#ifdef OCR_DLL
#define OCR_API __declspec(dllexport)
#else
#define OCR_API __declspec(dllimport)
#endif
namespace ocr {
struct OCR_API Result { cv::Mat img; std::string text; float score; cv::Rect rect;};
OCR_API bool init(const std::string& det_name,const std::string& det_dir,const std::string& rec_name,const std::string& rec_dir);
OCR_API std::vector<Result> run_det(cv::Mat& input);
OCR_API void run_rec(Result& result);
}

具体原因,不多赘述。 然后在需要使用的地方进行测试,例如在 MFC 项目中:

void CPaddocrTestDlg::OnBnClickedButton1(){
//server mobile
bool ret = ocr::init("PP-OCRv5_mobile_det","F:/project/paddleOcr/models/PP-OCRv5_mobile_det","PP-OCRv5_mobile_rec","F:/project/paddleOcr/models/PP-OCRv5_mobile_rec");
CString initMsg; initMsg.Format(_T("ocr::init() 返回:%s\\n"), ret ?_T("true"):_T("false"));
OutputDebugString(initMsg);
if(!ret){
OutputDebugString(_T("OCR 初始化失败!请检查模型路径和依赖 DLL。\\n"));
return;}
cv::Mat img = cv::imread("F:/project/paddleOcr/deploy/cpp_infer/build/Release/test10.png", cv::IMREAD_COLOR);
if(img.empty()){
OutputDebugString(_T("无法加载图像 test10.png!\\n"));
return;}
std::vector<ocr::Result> results = ocr::run_det(img);
CString detMsg;
detMsg.Format(_T("检测到 %d 个文本区域\\n"),(int)results.size());
OutputDebugString(detMsg);
for(auto& r : results){
ocr::run_rec(r);
CString text = CA2T(r.text.c_str(), CP_UTF8);
CString msg;
msg.Format(_T("文本:\"%s\", 置信度:%.2f, 位置:[%d,%d,%d,%d]\\n"), text, r.score, r.rect.x, r.rect.y, r.rect.width, r.rect.height );
OutputDebugString(msg);
}}

此处同样需要对库目录的链接加载配置正确。 注:此封装的 dll 只能在 release 状态下使用,对调试有一定的限制。

目录

  1. 前言
  2. 准备工作
  3. 开始编译
  4. 封装自己的动态库
  5. 如何在自己的项目中使用

更多推荐文章

查看全部
  • 2024 大模型应用案例集:典型示范应用全解析
  • 鸿蒙金融理财全栈项目:基础架构、数据安全与用户体验
  • 数组模拟链表、栈、队列与优先队列:高效实现与性能对比
  • 算法刷题:找到字符串中所有字母异位词(滑动窗口解法)
  • FPGA 摄像头采集处理显示指南:OV5640 到 HDMI 实时显示
  • Python 接入天远劳动仲裁 API 构建企业风控体系
  • GitHub Copilot Pro 学生免费认证与 VS Code 集成指南
  • AIGC 情感化智能客服实战:降低投诉率的技术方案
  • 对抗学习原理与代码实战详解
  • 双指针算法:四数之和解题思路与实现
  • 基于 Python 的流处理与 RAG 驱动智能 ETL 框架设计
  • OpenClaw 接入自定义模型及 WebUI 智能操作指南
  • CentOS 7 源码编译安装 Nginx 完整流程
  • 26 岁后转行程序员晚吗?毕业学员分享真实经验
  • 智能家居面板实战:从原理图到嘉立创EDA成品
  • AIGC 插画生成技术解析与 Python 代码实战
  • GitHub 修改用户名与密码指南
  • 2025 年世界职业院校技能大赛人工智能赛道备赛方案
  • Java 智能自习室预约与运营管理系统
  • Python 内存管理深潜:从引用计数到 GC 机制优化

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • RSA密钥对生成器

    生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online

  • Mermaid 预览与可视化编辑

    基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online

  • 随机西班牙地址生成器

    随机生成西班牙地址(支持马德里、加泰罗尼亚、安达卢西亚、瓦伦西亚筛选),支持数量快捷选择、显示全部与下载。 在线工具,随机西班牙地址生成器在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online