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 版本存在一些问题,会导致功能异常。
设置情况变量:
- @REM 设置opencv目录环境变量
- setx OPENCV_ROOT "C:\3rd\opencv4.6\build"
复制代码
- paddle_inference
我用的是 2.6 版。
设置情况变量:
- @REM 设置paddle_inference目录环境变量
- setx PADDLE_ROOT "C:\3rd\paddle_inference"
复制代码
- cuda (optional)
你应该懂得。
- cudnn (optional)
你应该懂得。
创建 C++项目
- 创建一个空的 C++ 项目。
- 在项目中创建文件:OpenCVDebug.props
- <?xml version="1.0" encoding="utf-8"?>
- <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <ImportGroup Label="PropertySheets" />
- <PropertyGroup Label="UserMacros" />
- <PropertyGroup />
- <ItemDefinitionGroup>
- <ClCompile>
- <AdditionalIncludeDirectories>$(OPENCV_ROOT)\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
- </ClCompile>
- <Link>
- <AdditionalLibraryDirectories>$(OPENCV_ROOT)\x64\vc15\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
- <AdditionalDependencies>opencv_world460d.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- </ItemDefinitionGroup>
- <ItemGroup />
- </Project>
复制代码
- 在项目中创建文件:OpenCVRelease.props
- <?xml version="1.0" encoding="utf-8"?>
- <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <ImportGroup Label="PropertySheets" />
- <PropertyGroup Label="UserMacros" />
- <PropertyGroup />
- <ItemDefinitionGroup>
- <ClCompile>
- <AdditionalIncludeDirectories>$(OPENCV_ROOT)\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
- </ClCompile>
- <Link>
- <AdditionalLibraryDirectories>$(OPENCV_ROOT)\x64\vc15\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
- <AdditionalDependencies>opencv_world460.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- </ItemDefinitionGroup>
- <ItemGroup />
- </Project>
复制代码
- 在项目中创建文件:PaddleDebug.props
- <?xml version="1.0" encoding="utf-8"?>
- <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <ImportGroup Label="PropertySheets" />
- <PropertyGroup Label="UserMacros" />
- <PropertyGroup />
- <ItemDefinitionGroup>
- <ClCompile>
- <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>
- </ClCompile>
- <Link>
- <AdditionalLibraryDirectories>$(PADDLE_ROOT)/third_party/install/zlib/lib;$(PADDLE_ROOT)/third_party/install/mklml/lib;$(PADDLE_ROOT)/paddle/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
- <AdditionalDependencies>paddle_inference.lib;mklml.lib;libiomp5md.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- </ItemDefinitionGroup>
- <ItemGroup />
- </Project>
复制代码
- 在项目中创建文件:PaddleRelease.props
- <?xml version="1.0" encoding="utf-8"?>
- <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <ImportGroup Label="PropertySheets" />
- <PropertyGroup Label="UserMacros" />
- <PropertyGroup />
- <ItemDefinitionGroup>
- <ClCompile>
- <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>
- </ClCompile>
- <Link>
- <AdditionalLibraryDirectories>$(PADDLE_ROOT)/third_party/install/zlib/lib;$(PADDLE_ROOT)/third_party/install/mklml/lib;$(PADDLE_ROOT)/paddle/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
- <AdditionalDependencies>paddle_inference.lib;mklml.lib;libiomp5md.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- </ItemDefinitionGroup>
- <ItemGroup />
- </Project>
复制代码
- 修改 C++项目文件:my-paddleocr.vcxproj
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- <Import Project=".\OpenCVDebug.props" />
- <Import Project=".\PaddleDebug.props" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- <Import Project=".\OpenCVRelease.props" />
- <Import Project=".\PaddleRelease.props" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- <Import Project=".\OpenCVDebug.props" />
- <Import Project=".\PaddleDebug.props" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- <Import Project=".\OpenCVRelease.props" />
- <Import Project=".\PaddleRelease.props" />
- </ImportGroup>
复制代码 引入 Paddle OCR C++ 源码
- 克隆 Paddle OCR 堆栈到本地。
- 切换到分支 release/2.6。
- git clone https://gitee.com/paddlepaddle/PaddleOCR.git
- cd PaddleOCR
- git checkout release/2.6
复制代码
- 将 deploy/cpp_infer 目次下的 include、src两个目次的内容复制到我们的 C++ 项目中。
- 修改新的 src 目次名称为 ocr。
- 删除ocr/main.cpp
- 在include目次下创建ocr_flags.h文件,内容如下:
这个文件是为了替换 google 的 gflags 库的利用。- #pragma once
- // common args
- #include <string>
- using std::string;
- #define DECLARE_bool(name) extern bool FLAGS_##name;
- #define DECLARE_int32(name) extern int FLAGS_##name;
- #define DECLARE_string(name) extern string FLAGS_##name;
- #define DECLARE_double(name) extern double FLAGS_##name;
- #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;
- #define DEFINE_bool(name, val, txt) DEFINE_VARIABLE(bool, name, val, txt)
- #define DEFINE_int32(name, val, txt) DEFINE_VARIABLE(int, name, val, txt)
- #define DEFINE_string(name, val, txt) DEFINE_VARIABLE(string, name, val, txt)
- #define DEFINE_double(name, val, txt) DEFINE_VARIABLE(double, name, val, txt)
复制代码 不利用 gflags/gflags.h
表明行 // #include
增长行 #include "ocr_flags.h"- ...
- // #include <gflags/gflags.h>
- #include "ocr_flags.h"
- ...
复制代码 不利用 gflags/gflags.h
表明行 // #include
增长行 #include "include/ocr_flags.h"- ...
- // #include <gflags/gflags.h>
- #include "include/ocr_flags.h"
- ...
复制代码
- 修改include/paddleocr.cpp文件,内容如下:
不利用 auto_log/autolog.h
表明行 // #include "auto_log/autolog.h"
表明方法 PPOCR::benchmark_log 的内容。- // #include "auto_log/autolog.h"
- ...
- void PPOCR::benchmark_log(int img_num) {
- // if (this->time_info_det[0] + this->time_info_det[1] +
- // this->time_info_det[2] >
- // 0) {
- // AutoLogger autolog_det("ocr_det", FLAGS_use_gpu, FLAGS_use_tensorrt,
- // FLAGS_enable_mkldnn, FLAGS_cpu_threads, 1,
- // "dynamic", FLAGS_precision, this->time_info_det,
- // img_num);
- // autolog_det.report();
- // }
- // if (this->time_info_rec[0] + this->time_info_rec[1] +
- // this->time_info_rec[2] >
- // 0) {
- // AutoLogger autolog_rec("ocr_rec", FLAGS_use_gpu, FLAGS_use_tensorrt,
- // FLAGS_enable_mkldnn, FLAGS_cpu_threads,
- // FLAGS_rec_batch_num, "dynamic", FLAGS_precision,
- // this->time_info_rec, img_num);
- // autolog_rec.report();
- // }
- // if (this->time_info_cls[0] + this->time_info_cls[1] +
- // this->time_info_cls[2] >
- // 0) {
- // AutoLogger autolog_cls("ocr_cls", FLAGS_use_gpu, FLAGS_use_tensorrt,
- // FLAGS_enable_mkldnn, FLAGS_cpu_threads,
- // FLAGS_cls_batch_num, "dynamic", FLAGS_precision,
- // this->time_info_cls, img_num);
- // autolog_cls.report();
- // }
- }
- ...
复制代码
- 修改include/paddlestructure.cpp文件,内容如下:
不利用 auto_log/autolog.h
表明行 // #include "auto_log/autolog.h"
表明方法 PPOCR::benchmark_log 的内容。- // #include "auto_log/autolog.h"
- ...
- void PaddleStructure::benchmark_log(int img_num) {
- // if (this->time_info_det[0] + this->time_info_det[1] +
- // this->time_info_det[2] >
- // 0) {
- // AutoLogger autolog_det("ocr_det", FLAGS_use_gpu, FLAGS_use_tensorrt,
- // FLAGS_enable_mkldnn, FLAGS_cpu_threads, 1,
- // "dynamic", FLAGS_precision, this->time_info_det,
- // img_num);
- // autolog_det.report();
- // }
- // if (this->time_info_rec[0] + this->time_info_rec[1] +
- // this->time_info_rec[2] >
- // 0) {
- // AutoLogger autolog_rec("ocr_rec", FLAGS_use_gpu, FLAGS_use_tensorrt,
- // FLAGS_enable_mkldnn, FLAGS_cpu_threads,
- // FLAGS_rec_batch_num, "dynamic", FLAGS_precision,
- // this->time_info_rec, img_num);
- // autolog_rec.report();
- // }
- // if (this->time_info_cls[0] + this->time_info_cls[1] +
- // this->time_info_cls[2] >
- // 0) {
- // AutoLogger autolog_cls("ocr_cls", FLAGS_use_gpu, FLAGS_use_tensorrt,
- // FLAGS_enable_mkldnn, FLAGS_cpu_threads,
- // FLAGS_cls_batch_num, "dynamic", FLAGS_precision,
- // this->time_info_cls, img_num);
- // autolog_cls.report();
- // }
- // if (this->time_info_table[0] + this->time_info_table[1] +
- // this->time_info_table[2] >
- // 0) {
- // AutoLogger autolog_table("table", FLAGS_use_gpu, FLAGS_use_tensorrt,
- // FLAGS_enable_mkldnn, FLAGS_cpu_threads,
- // FLAGS_cls_batch_num, "dynamic", FLAGS_precision,
- // this->time_info_table, img_num);
- // autolog_table.report();
- // }
- // if (this->time_info_layout[0] + this->time_info_layout[1] +
- // this->time_info_layout[2] >
- // 0) {
- // AutoLogger autolog_layout("layout", FLAGS_use_gpu, FLAGS_use_tensorrt,
- // FLAGS_enable_mkldnn, FLAGS_cpu_threads,
- // FLAGS_cls_batch_num, "dynamic",
- // FLAGS_precision, this->time_info_layout,
- // img_num);
- // autolog_layout.report();
- // }
- }
- ...
复制代码
- 修改include/utility.cpp文件,内容如下:
不利用 dirent.h
表明行 // #include
表明方法 Utility::GetAllFiles 的内容。
[code]// #include ...// list all files under a directoryvoid Utility::GetAllFiles(const char *dir_name, std::vector &all_inputs) { // if (NULL == dir_name) { // std::cout |