经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
在 C++ 项目中,通过源码使用 PaddlePaddle 实现 OCR 功能
来源:cnblogs  作者:SNYang  时间:2024/3/1 8:44:18  对本文有异议

My-PaddleOCR

介绍

如何在 C++ 项目中,通过源码使用 PaddlePaddle 实现 OCR 功能。
本项目的所有源码:gitee: paddleocr

目前,官方提供使用 PaddleOcr 的方案有:

  • 在 Python 项目中,调用 paddlepaddle + paddleocr 包。

  • 在 C++项目中,调用一个可执行文件。(由编译 PaddleOCR 中的 deploy/cpp_infer 下的代码形成)

    Paddle OCR 提供了一个通过编译 deploy/cpp_infer 下的代码为 ppocr.exe,然后通过命令行调用获取 OCR 的结果。
    具体过程见: 服务器端 C++预测

其它方法:

  • 使用 Python 写一个 RESTful 服务,然后让 C++项目调用这个服务功能。

这里主要介绍一个更加直接的方法:

  • deploy/cpp_infer 的源码引入到我们的 C++项目。
  • 做适当修改后,我们就可以直接使用这些 API。
  • 当然,如果你愿意的话,也可以将这些源码形成一个新的项目,编译成一个 dll。(这里并不介绍)
    说明:
  • 下面的方法只在 release 版中有效。可能是因为paddle_inference.dll 只支持 release 版。
    如果要支持 debug 版,可能需要重新编译 PaddlePaddle。

Paddle OCR C++ 源码

Paddle OCR 的仓库,在github: PaddleOCR 或者 gitee: PaddleOCR
C++ 相关的代码在目录 deploy/cpp_infer 里。

如何引入 Paddle OCR C++ 源码

需要安装的组件

  • opencv
    我在 opencv 4.6 版本上测试通过。
    注意:opencv 4.5 版本存在一些问题,会导致功能异常。
    设置环境变量:
  1. @REM 设置opencv目录环境变量
  2. setx OPENCV_ROOT "C:\3rd\opencv4.6\build"
  • paddle_inference
    我用的是 2.6 版。
    设置环境变量:
  1. @REM 设置paddle_inference目录环境变量
  2. setx PADDLE_ROOT "C:\3rd\paddle_inference"
  • cuda (optional)
    你应该懂得。
  • cudnn (optional)
    你应该懂得。

创建 C++项目

  • 创建一个空的 C++ 项目。

  • 在项目中创建文件:OpenCVDebug.props

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  3. <ImportGroup Label="PropertySheets" />
  4. <PropertyGroup Label="UserMacros" />
  5. <PropertyGroup />
  6. <ItemDefinitionGroup>
  7. <ClCompile>
  8. <AdditionalIncludeDirectories>$(OPENCV_ROOT)\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
  9. </ClCompile>
  10. <Link>
  11. <AdditionalLibraryDirectories>$(OPENCV_ROOT)\x64\vc15\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
  12. <AdditionalDependencies>opencv_world460d.lib;%(AdditionalDependencies)</AdditionalDependencies>
  13. </Link>
  14. </ItemDefinitionGroup>
  15. <ItemGroup />
  16. </Project>
  • 在项目中创建文件:OpenCVRelease.props
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  3. <ImportGroup Label="PropertySheets" />
  4. <PropertyGroup Label="UserMacros" />
  5. <PropertyGroup />
  6. <ItemDefinitionGroup>
  7. <ClCompile>
  8. <AdditionalIncludeDirectories>$(OPENCV_ROOT)\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
  9. </ClCompile>
  10. <Link>
  11. <AdditionalLibraryDirectories>$(OPENCV_ROOT)\x64\vc15\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
  12. <AdditionalDependencies>opencv_world460.lib;%(AdditionalDependencies)</AdditionalDependencies>
  13. </Link>
  14. </ItemDefinitionGroup>
  15. <ItemGroup />
  16. </Project>
  • 在项目中创建文件:PaddleDebug.props
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  3. <ImportGroup Label="PropertySheets" />
  4. <PropertyGroup Label="UserMacros" />
  5. <PropertyGroup />
  6. <ItemDefinitionGroup>
  7. <ClCompile>
  8. <AdditionalIncludeDirectories>./;$(PADDLE_ROOT)/paddle/include;$(PADDLE_ROOT)/third_party/install/zlib/include;$(PADDLE_ROOT)/third_party/boost;$(PADDLE_ROOT)/third_party/eigen3;$(PADDLE_ROOT)/third_party/install/mklml/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
  9. </ClCompile>
  10. <Link>
  11. <AdditionalLibraryDirectories>$(PADDLE_ROOT)/third_party/install/zlib/lib;$(PADDLE_ROOT)/third_party/install/mklml/lib;$(PADDLE_ROOT)/paddle/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
  12. <AdditionalDependencies>paddle_inference.lib;mklml.lib;libiomp5md.lib;%(AdditionalDependencies)</AdditionalDependencies>
  13. </Link>
  14. </ItemDefinitionGroup>
  15. <ItemGroup />
  16. </Project>
  • 在项目中创建文件:PaddleRelease.props
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  3. <ImportGroup Label="PropertySheets" />
  4. <PropertyGroup Label="UserMacros" />
  5. <PropertyGroup />
  6. <ItemDefinitionGroup>
  7. <ClCompile>
  8. <AdditionalIncludeDirectories>./;$(PADDLE_ROOT)/paddle/include;$(PADDLE_ROOT)/third_party/install/zlib/include;$(PADDLE_ROOT)/third_party/boost;$(PADDLE_ROOT)/third_party/eigen3;$(PADDLE_ROOT)/third_party/install/mklml/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
  9. </ClCompile>
  10. <Link>
  11. <AdditionalLibraryDirectories>$(PADDLE_ROOT)/third_party/install/zlib/lib;$(PADDLE_ROOT)/third_party/install/mklml/lib;$(PADDLE_ROOT)/paddle/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
  12. <AdditionalDependencies>paddle_inference.lib;mklml.lib;libiomp5md.lib;%(AdditionalDependencies)</AdditionalDependencies>
  13. </Link>
  14. </ItemDefinitionGroup>
  15. <ItemGroup />
  16. </Project>
  • 修改 C++项目文件:my-paddleocr.vcxproj
  1. <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
  2. <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  3. <Import Project=".\OpenCVDebug.props" />
  4. <Import Project=".\PaddleDebug.props" />
  5. </ImportGroup>
  6. <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
  7. <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  8. <Import Project=".\OpenCVRelease.props" />
  9. <Import Project=".\PaddleRelease.props" />
  10. </ImportGroup>
  11. <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
  12. <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  13. <Import Project=".\OpenCVDebug.props" />
  14. <Import Project=".\PaddleDebug.props" />
  15. </ImportGroup>
  16. <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
  17. <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  18. <Import Project=".\OpenCVRelease.props" />
  19. <Import Project=".\PaddleRelease.props" />
  20. </ImportGroup>

引入 Paddle OCR C++ 源码

  • 克隆 Paddle OCR 仓库到本地。
  • 切换到分支 release/2.6
  1. git clone https://gitee.com/paddlepaddle/PaddleOCR.git
  2. cd PaddleOCR
  3. git checkout release/2.6
  • deploy/cpp_infer 目录下的 includesrc两个目录的内容复制到我们的 C++ 项目中。
  • 修改新的 src 目录名称为 ocr
  • 删除ocr/main.cpp
  • include目录下创建ocr_flags.h文件,内容如下:

这个文件是为了替换 google 的 gflags 库的使用。

  1. #pragma once
  2. // common args
  3. #include <string>
  4. using std::string;
  5. #define DECLARE_bool(name) extern bool FLAGS_##name;
  6. #define DECLARE_int32(name) extern int FLAGS_##name;
  7. #define DECLARE_string(name) extern string FLAGS_##name;
  8. #define DECLARE_double(name) extern double FLAGS_##name;
  9. #define DEFINE_VARIABLE(type, name, value, help) static const type FLAGS_nono##name = value; type FLAGS_##name = FLAGS_nono##name; static type FLAGS_no##name = FLAGS_nono##name;
  10. #define DEFINE_bool(name, val, txt) DEFINE_VARIABLE(bool, name, val, txt)
  11. #define DEFINE_int32(name, val, txt) DEFINE_VARIABLE(int, name, val, txt)
  12. #define DEFINE_string(name, val, txt) DEFINE_VARIABLE(string, name, val, txt)
  13. #define DEFINE_double(name, val, txt) DEFINE_VARIABLE(double, name, val, txt)
  • 修改include/args.h文件,内容如下:

不使用 gflags/gflags.h
注释行 // #include <gflags/gflags.h>
增加行 #include "ocr_flags.h"

  1. ...
  2. // #include <gflags/gflags.h>
  3. #include "ocr_flags.h"
  4. ...
  • 修改ocr/args.cpp文件,内容如下:

不使用 gflags/gflags.h
注释行 // #include <gflags/gflags.h>
增加行 #include "include/ocr_flags.h"

  1. ...
  2. // #include <gflags/gflags.h>
  3. #include "include/ocr_flags.h"
  4. ...
  • 修改include/paddleocr.cpp文件,内容如下:

不使用 auto_log/autolog.h
注释行 // #include "auto_log/autolog.h"
注释方法 PPOCR::benchmark_log 的内容。

  1. // #include "auto_log/autolog.h"
  2. ...
  3. void PPOCR::benchmark_log(int img_num) {
  4. // if (this->time_info_det[0] + this->time_info_det[1] +
  5. // this->time_info_det[2] >
  6. // 0) {
  7. // AutoLogger autolog_det("ocr_det", FLAGS_use_gpu, FLAGS_use_tensorrt,
  8. // FLAGS_enable_mkldnn, FLAGS_cpu_threads, 1,
  9. // "dynamic", FLAGS_precision, this->time_info_det,
  10. // img_num);
  11. // autolog_det.report();
  12. // }
  13. // if (this->time_info_rec[0] + this->time_info_rec[1] +
  14. // this->time_info_rec[2] >
  15. // 0) {
  16. // AutoLogger autolog_rec("ocr_rec", FLAGS_use_gpu, FLAGS_use_tensorrt,
  17. // FLAGS_enable_mkldnn, FLAGS_cpu_threads,
  18. // FLAGS_rec_batch_num, "dynamic", FLAGS_precision,
  19. // this->time_info_rec, img_num);
  20. // autolog_rec.report();
  21. // }
  22. // if (this->time_info_cls[0] + this->time_info_cls[1] +
  23. // this->time_info_cls[2] >
  24. // 0) {
  25. // AutoLogger autolog_cls("ocr_cls", FLAGS_use_gpu, FLAGS_use_tensorrt,
  26. // FLAGS_enable_mkldnn, FLAGS_cpu_threads,
  27. // FLAGS_cls_batch_num, "dynamic", FLAGS_precision,
  28. // this->time_info_cls, img_num);
  29. // autolog_cls.report();
  30. // }
  31. }
  32. ...
  • 修改include/paddlestructure.cpp文件,内容如下:

不使用 auto_log/autolog.h
注释行 // #include "auto_log/autolog.h"
注释方法 PPOCR::benchmark_log 的内容。

  1. // #include "auto_log/autolog.h"
  2. ...
  3. void PaddleStructure::benchmark_log(int img_num) {
  4. // if (this->time_info_det[0] + this->time_info_det[1] +
  5. // this->time_info_det[2] >
  6. // 0) {
  7. // AutoLogger autolog_det("ocr_det", FLAGS_use_gpu, FLAGS_use_tensorrt,
  8. // FLAGS_enable_mkldnn, FLAGS_cpu_threads, 1,
  9. // "dynamic", FLAGS_precision, this->time_info_det,
  10. // img_num);
  11. // autolog_det.report();
  12. // }
  13. // if (this->time_info_rec[0] + this->time_info_rec[1] +
  14. // this->time_info_rec[2] >
  15. // 0) {
  16. // AutoLogger autolog_rec("ocr_rec", FLAGS_use_gpu, FLAGS_use_tensorrt,
  17. // FLAGS_enable_mkldnn, FLAGS_cpu_threads,
  18. // FLAGS_rec_batch_num, "dynamic", FLAGS_precision,
  19. // this->time_info_rec, img_num);
  20. // autolog_rec.report();
  21. // }
  22. // if (this->time_info_cls[0] + this->time_info_cls[1] +
  23. // this->time_info_cls[2] >
  24. // 0) {
  25. // AutoLogger autolog_cls("ocr_cls", FLAGS_use_gpu, FLAGS_use_tensorrt,
  26. // FLAGS_enable_mkldnn, FLAGS_cpu_threads,
  27. // FLAGS_cls_batch_num, "dynamic", FLAGS_precision,
  28. // this->time_info_cls, img_num);
  29. // autolog_cls.report();
  30. // }
  31. // if (this->time_info_table[0] + this->time_info_table[1] +
  32. // this->time_info_table[2] >
  33. // 0) {
  34. // AutoLogger autolog_table("table", FLAGS_use_gpu, FLAGS_use_tensorrt,
  35. // FLAGS_enable_mkldnn, FLAGS_cpu_threads,
  36. // FLAGS_cls_batch_num, "dynamic", FLAGS_precision,
  37. // this->time_info_table, img_num);
  38. // autolog_table.report();
  39. // }
  40. // if (this->time_info_layout[0] + this->time_info_layout[1] +
  41. // this->time_info_layout[2] >
  42. // 0) {
  43. // AutoLogger autolog_layout("layout", FLAGS_use_gpu, FLAGS_use_tensorrt,
  44. // FLAGS_enable_mkldnn, FLAGS_cpu_threads,
  45. // FLAGS_cls_batch_num, "dynamic",
  46. // FLAGS_precision, this->time_info_layout,
  47. // img_num);
  48. // autolog_layout.report();
  49. // }
  50. }
  51. ...
  • 修改include/utility.cpp文件,内容如下:

不使用 dirent.h
注释行 // #include <dirent.h>
注释方法 Utility::GetAllFiles 的内容。

  1. // #include <dirent.h>
  2. ...
  3. // list all files under a directory
  4. void Utility::GetAllFiles(const char *dir_name,
  5. std::vector<std::string> &all_inputs) {
  6. // if (NULL == dir_name) {
  7. // std::cout << " dir_name is null ! " << std::endl;
  8. // return;
  9. // }
  10. // struct stat s;
  11. // stat(dir_name, &s);
  12. // if (!S_ISDIR(s.st_mode)) {
  13. // std::cout << "dir_name is not a valid directory !" << std::endl;
  14. // all_inputs.push_back(dir_name);
  15. // return;
  16. // } else {
  17. // struct dirent *filename; // return value for readdir()
  18. // DIR *dir; // return value for opendir()
  19. // dir = opendir(dir_name);
  20. // if (NULL == dir) {
  21. // std::cout << "Can not open dir " << dir_name << std::endl;
  22. // return;
  23. // }
  24. // std::cout << "Successfully opened the dir !" << std::endl;
  25. // while ((filename = readdir(dir)) != NULL) {
  26. // if (strcmp(filename->d_name, ".") == 0 ||
  27. // strcmp(filename->d_name, "..") == 0)
  28. // continue;
  29. // // img_dir + std::string("/") + all_inputs[0];
  30. // all_inputs.push_back(dir_name + std::string("/") +
  31. // std::string(filename->d_name));
  32. // }
  33. // }
  34. }
  35. ...

编写调用程序

  • 在项目中创建文件:paddle_util.h
    内容如下:
  1. #pragma once
  2. using namespace std;
  3. #include <include/paddleocr.h>
  4. class PaddleUtil {
  5. public:
  6. PaddleUtil();
  7. public:
  8. static PaddleUtil &get();
  9. static void init();
  10. void rec_image(const string &imageFile);
  11. private:
  12. PaddleOCR::PPOCR ocr;
  13. };
  • 在项目中创建文件:paddle_util.cpp
    内容如下:
  1. #include "opencv2/core.hpp"
  2. #include "opencv2/imgcodecs.hpp"
  3. #include "opencv2/imgproc.hpp"
  4. #include <iostream>
  5. #include <vector>
  6. #include "paddle_util.h"
  7. #include <include/args.h>
  8. using namespace PaddleOCR;
  9. PaddleUtil::PaddleUtil() {}
  10. PaddleUtil &PaddleUtil::get() {
  11. static PaddleUtil self;
  12. return self;
  13. }
  14. void PaddleUtil::init() {
  15. FLAGS_det = true;
  16. FLAGS_rec = true;
  17. FLAGS_cls = false;
  18. FLAGS_use_angle_cls = false;
  19. FLAGS_det_model_dir = "model/whl/det/en/en_PP-OCRv3_det_infer";
  20. FLAGS_rec_model_dir = "model/whl/rec/en/en_PP-OCRv4_rec_infer";
  21. FLAGS_rec_char_dict_path = "model/en_dict.txt";
  22. }
  23. void PaddleUtil::rec_image(const string &imageFile) {
  24. if (FLAGS_benchmark) {
  25. ocr.reset_timer();
  26. }
  27. cv::Mat img = cv::imread(imageFile, cv::IMREAD_COLOR);
  28. if (!img.data) {
  29. std::cerr << "[ERROR] image read failed! image path: " << imageFile
  30. << std::endl;
  31. return;
  32. }
  33. std::vector<OCRPredictResult> ocr_result =
  34. ocr.ocr(img, FLAGS_det, FLAGS_rec, FLAGS_cls);
  35. Utility::print_result(ocr_result);
  36. if (FLAGS_visualize && FLAGS_det) {
  37. std::string file_name = Utility::basename(imageFile);
  38. Utility::VisualizeBboxes(img, ocr_result, FLAGS_output + "/" + file_name);
  39. }
  40. }
  • 在项目中创建主程序文件:my-paddleocr.cpp
    内容如下:
  1. #include <iostream>
  2. #include "paddle_util.h"
  3. int main() {
  4. PaddleUtil::init();
  5. PaddleUtil::get().rec_image("model/254.jpg");
  6. std::cout << "Done!\n";
  7. }

编译运行

  • 在 Visual Studio 中使用 Release 版本编译。
  • 运行 copy_paddle_dll.bat,复制 paddle_inference.dll 到输出目录。
  1. @REM copy dll to Release
  2. copy /Y %PADDLE_ROOT%\paddle\lib\paddle_inference.dll .\x64\Releasecopy /Y %PADDLE_ROOT%\third_party\install\mkldnn\lib\mkldnn.dll .\x64\Releasecopy /Y %PADDLE_ROOT%\third_party\install\mklml\lib\mklml.dll .\x64\Releasecopy /Y %PADDLE_ROOT%\third_party\install\mklml\lib\libiomp5md.dll .\x64\Releasecopy /Y %PADDLE_ROOT%\third_party\install\paddle2onnx\lib\paddle2onnx.dll .\x64\Releasecopy /Y %PADDLE_ROOT%\third_party\install\onnxruntime\lib\onnxruntime.dll .\x64\Release

原文链接:https://www.cnblogs.com/steven-yang/p/18042992

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号