paddle介绍
Paddle是类似tesseract的文字识别ocr。因为tesseract-ocr的中文识别效果不好。因此才准备安装Paddle。Paddle最方便的安装方式的使用Python的包管理安装。pip3 install paddlepaddle
。但我使用了一下感觉还是用C++更加方便,QT + OpenCV + Paddle应当还不错。所以才有了下面这一篇教程。
环境说明
- 电脑系统是Ubuntu23.04
- 安装的OpenCV是使用apt安装的,不是自己编译安装的
- 因为墙的原因,直接使用的Paddle编译好的库,没有使用源码安装
安装步骤
- 确保系统中已经安装openCV
# 搜索安装opencv
sudo apt search libopencv-dev
sudo apt install libopencv-dev
# 确定pkg-config能找到opencv头文件和库文件
pkg-config --libs --cflags opencv4
- 下载Paddle库文件
这里下载。我下载的是manylinux_cpu_avx_mkl_gcc8.2
下载完成后解压。
tar zxvf paddle_inference.tgz
cd paddle_inference/
# 这个目录中就是paddle的头文件和相关库文件
# 这里的库文件需要提取出来,加入到系统搜索目录
# 使用下面的命令提取出共享库文件
mkdir paddle_lib
find . -name "*.so*" | xargs -i cp {} ./paddle_lib
# 完成后paddle_lib目录下面就会有几个动态库文件
# 下面将这些动态库加入到系统搜索目录中
cp -a paddle_lib /usr/lib
vi /etc/ld.so.conf.d/paddle.conf
# 加入搜索目录
/usr/lib/paddle_lib
# 更新
ldconfig
- 下载推理模型model和PaddleOCR
PaddleOCR类似一个Paddle的命令行命令,但这个命令需要自己编译,不像tesseract可以直接使用apt安装。这里编译PaddleOCR是从源码编译的有点麻烦,如果只是想在C++中使用Paddle可以不用编译PaddleOCR,但了解如何编译PaddleOCR可以帮助您理解paddle的编译过程。
# 使用下面命令下载PaddleOCR
git clone https://gitee.com/paddlepaddle/PaddleOCR.git
这里下载推理模型。下载时点击"推理模型"链接下载,我下载的是ch_ppocr_server_v2.0_det_infer.tar
,49.5M。下载后解压。
将解压后的文件放到PaddleOCR/PaddleOCR/deploy/cpp_infer/inference
。这里的inference目录是自己新建的,用于存放模型文件。
cd PaddleOCR/deploy/cpp_infer/
mkdir inference
cd inference
mv ~/Downloads/ch_ppocr_server_v2.0_det_infer .
编译PaddleOCR
编译之前需要修改一些配置
cd PaddleOCR/deploy/cpp_infer/
git checkout release/2.7
vi tools/build.sh
# 这里的你的opencv目录,因为我使用的apt安装的,试了几次指定opencv目录都无效
# 因为这里设置失败,所以后面我直接更改的CMakeLists.txt
OPENCV_DIR= "你的opencv安装目录"
# 下面这个就是上面下载的Paddle库文件目录
LIB_DIR=your_paddle_inference_dir
# 下面这两个是使用显卡推理使用的,这里不使用
#CUDA_LIB_DIR=your_cuda_lib_dir
#CUDNN_LIB_DIR=your_cudnn_lib_dir
BUILD_DIR=build
rm -rf ${BUILD_DIR}
mkdir ${BUILD_DIR}
cd ${BUILD_DIR}
cmake .. \
-DPADDLE_LIB=${LIB_DIR} \
-DWITH_MKL=ON \
-DWITH_GPU=OFF \
-DWITH_STATIC_LIB=OFF \
-DWITH_TENSORRT=OFF \
-DOPENCV_DIR=${OPENCV_DIR} \
# -DCUDNN_LIB=${CUDNN_LIB_DIR} \
# -DCUDA_LIB=${CUDA_LIB_DIR} \
# -DTENSORRT_DIR=${TENSORRT_DIR} \
# 根据你cpu核心数加个数字,多线编译
make -j16
# 再更改一下CMakeLists.txt第74行,这里的优化等级有问题。将-o3改为-O3
vi CMakeLists.txt
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O3 ${FLAG_OPENMP} -std= c++11")
# 改了上面配置后就可以尝试编译一下了
sh tools/build.sh
# 如果你也和我一样找不到OpenCVConfig.cmake,可以像我一样直接更改CMakeLists.txt,不用cmake自带的find_package找opencv。我也试过更改CMAKE_PREFIX_PATH,明明目录下有OpenCVConfig.cmake,还是提示找不到OpenCVConfig.cmake。因此一气之下自己改CMakeLists.txt。如果找不到OpenCV会提示以下错误:
CMake Error at CMakeLists.txt:47 (find_package):
Could not find a package configuration file provided by "OpenCV" with any
of the following names:
OpenCVConfig.cmake
opencv-config.cmake
Add the installation prefix of "OpenCV" to CMAKE_PREFIX_PATH or set
"OpenCV_DIR" to a directory containing one of the above files. If "OpenCV"
provides a separate development package or SDK, be sure it has been
installed.
# 可以更改CMakeLists.txt 49行,改为如下内容
else ()
#find_package(OpenCV REQUIRED PATHS ${OPENCV_DIR}/share/OpenCV NO_DEFAULT_PATH)
find_package(PkgConfig)
pkg_search_module(OPENCV4 REQUIRED opencv4)
link_directories(${OPENCV4_LIBRARY_DIRS})
link_libraries(${OPENCV4_LIBRARIES})
include_directories(${OPENCV4_INCLUDE_DIRS})
include_directories("${PADDLE_LIB}/paddle/include")
link_directories("${PADDLE_LIB}/paddle/lib")
endif ()
#include_directories(${OpenCV_INCLUDE_DIRS})
# 再尝试编译
sh tools/build.sh
运行PaddleOCR
./ppocr --help
# 如果不报错,而是显示支持的选项就表示成功了,PaddleOCR的命令就可以使用的
# 只是一个帮助命令完全看不出推理有什么效果因此可以使用下面命令,看下推理效果
./build/ppocr --det_model_dir=../inference/ch_ppocr_server_v2.0_det_infer/ --image_dir=./doc/imgs/cmake_step3.png --det=true --rec=false
# 如果报找不到图片,可以使用绝对路径
# 运行成功后会在output目录下生成一个cmake_step3.png的图片,这个图片中的文字都会框出来
C++中使用paddle
这里主要依照官网的教程,Paddle官网教程
- 确定已经下载Paddle库,并解压
- 这里下载ResNet50推理模型
- 下载推理示例
git clone https://gitee.com/cuizhi/Paddle-Inference-Demo.git
# 将步骤1下载的Paddle库,复制到Paddle-Inference-Demo/c++/lib/
cp -a ~/Downloads/paddle_inference/ Paddle-Inference-Demo/c++/lib/
# 将步骤2下载的推理模型复制到Paddle-Inference-Demo/c++/cpu/resnet50
cp -a ~/Downloads/resnet50 Paddle-Inference-Demo/c++/cpu/resnet50
- 修改编译选项
# 因为我的电脑没有安装CUDA,因此需要关闭GPU选项
cd Paddle-Inference-Demo/c++/cpu/resnet50
vi complie.sh
# 26行开始关闭ONNXRUNTIME,这个第三方库老是与库里要求版本不一致
WITH_MKL=ON
WITH_ONNXRUNTIME=OFF
WITH_ARM=OFF
WITH_MIPS=OFF
WITH_SW=OFF
LIB_DIR=${work_path}/../../lib/paddle_inference
cmake .. -DPADDLE_LIB=${LIB_DIR} \
-DDEMO_NAME=${DEMO_NAME} \
-DWITH_MKL=${WITH_MKL} \
-DWITH_ONNXRUNTIME=${WITH_ONNXRUNTIME} \
-DWITH_ARM=${WITH_ARM} \
-DWITH_MIPS=${WITH_MIPS} \
-DWITH_SW=${WITH_SW} \
-DWITH_STATIC_LIB=OFF
# 之后就可以编译了, 会生成resnet50_test
./compile.sh
- 运行程序
./build/resnet50_test --model_file resnet50/inference.pdmodel --params_file resnet50/inference.pdiparams
# 显示以下内容表示成功
I0310 08:20:42.485941 6242 device_context.cc:737] oneDNN v2.5.4
WARNING: Logging before InitGoogleLogging() is written to STDERR
I0310 08:20:42.643239 6242 resnet50_test.cc:76] run avg time is 157.477 ms
I0310 08:20:42.643280 6242 resnet50_test.cc:91] 0 : 0
I0310 08:20:42.643291 6242 resnet50_test.cc:91] 100 : 2.04163e-37
I0310 08:20:42.643296 6242 resnet50_test.cc:91] 200 : 2.1238e-33
I0310 08:20:42.643299 6242 resnet50_test.cc:91] 300 : 0
I0310 08:20:42.643303 6242 resnet50_test.cc:91] 400 : 1.6849e-35
I0310 08:20:42.643309 6242 resnet50_test.cc:91] 500 : 0
I0310 08:20:42.643317 6242 resnet50_test.cc:91] 600 : 1.05767e-19
I0310 08:20:42.643327 6242 resnet50_test.cc:91] 700 : 2.04094e-23
I0310 08:20:42.643334 6242 resnet50_test.cc:91] 800 : 3.85254e-25
I0310 08:20:42.643342 6242 resnet50_test.cc:91] 900 : 1.52391e-30
如果只是学习使用官方教程到这里就结束了,但我的目的是想将Paddle,openCV以及Qt一起使用,因此下面还要探索如果简单方便的将Paddle库引入到Qt中。
- 移植Paddle库到QT
Paddle库无非就是提供了头文件和库文件,要做的就是把其中的Paddle文件加入到Qt项目管理文件中,具体就是项目的.pro文件。废话不多说开造。
# 使用QT creator新建一个paddleTest项目
# paddleTest.pro文件中加入以下内容
# 这个是自己的Paddle库所在位置
PADDLE_PATH = /home/XXXXXXX/Downloads/paddle_inference/
INCLUDEPATH += \
$$PADDLE_PATH/paddle/include \
$$PADDLE_PATH/third_party/install/cryptopp/include \
$$PADDLE_PATH/third_party/install/glog/include \
$$PADDLE_PATH/third_party/install/mkldnn/include \
$$PADDLE_PATH/third_party/install/mklml/include \
$$PADDLE_PATH/third_party/install/protobuf/include \
$$PADDLE_PATH/third_party/install/xxhash/include \
$$PADDLE_PATH/third_party/install/gflags/include
LIBS += -L$$PADDLE_PATH/paddle/lib -lpaddle_inference
LIBS += -L$$PADDLE_PATH/third_party/install/gflags/lib -lgflags
LIBS += -L$$PADDLE_PATH/third_party/install/glog/lib -lglog
LIBS += -L$$PADDLE_PATH/third_party/install/mkldnn/lib -lmkldnn
LIBS += -L$$PADDLE_PATH/third_party/install/mklml/lib -liomp5 -lmklml_intel
LIBS += -L$$PADDLE_PATH/third_party/install/protobuf/lib -lprotobuf
LIBS += -L$$PADDLE_PATH/third_party/install/xxhash/lib -lxxhash
# mkldnn库名字有点问题,我的Paddle库中是libmkldnn.so.0,使用下列命令来一个软链接,其它有几个动态库也是如此都有一个版本号,也可以加一个软链接
ln -s libmkldnn.so.0 libmkldnn.so
# 新建一个main.cc,复制Paddle-Inference-Demo/c++/cpu/resnet50/resnet50_test.cc内容到main.cc
# 如果编译通过,那就没有问题了
# 最后就是运行了,将前面下载的resnet50的推理模型复制到build-paddleTest-unknown-Debug
# 下面命令运行程序, 和使前面和运行效果一致,表示成功移植
./paddleTest --model_file resnet50/inference.pdmodel --params_file resnet50/inference.pdiparams
到这里已经完成Paddle库和Qt一起使用,但还不够简单,每次加入的头文件和库文件也太多了,每次都要复制出来,太麻烦了。可以将这些文件提取出来放到固定文件,每次只需要加载这个文件就可以了。现成的方案是有的pkg-config,只需要提取出头文件,和库文件,再使用一个xxx.pc文件配置好,每次使用直接像opencv那样加载一下就完成了。库文件可以用前面提到的find . -name "*.so*" | xargs -i cp {} ./paddle_lib
方法,这次不只提取.so动态库,.a的静态库也一并提取出来。
# 进入paddle_inference目录
# 提取库文件
cd ~/Downloads/paddle_inference
mkdir paddle_lib
find . -name "*.so*" | xargs -i cp {} ./paddle_lib
find . -name "*.a" | xargs -i cp {} ./paddle_lib
# 复制头文件,因为头文件有结构要求,只能手动提取,注意这里的头文件包含第三方库的头文件
mkdir paddle_include
# 完成后将库文件复制到/usr/lib/
# 将头文件复制到/usr/include/
# 下面就是我复制完成后的头文件内容,包含paddle和第三方库所有头文件
cpu_provider_factory.h mkl_lapacke.h
crypto mkl_lapack.h
cryptopp mkl_service.h
dnnl_config.h mkl_spblas.h
dnnl_debug.h mkl_trans.h
dnnl.h mkl_types.h
dnnl.hpp mkl_version.h
dnnl_ocl.h mkl_vml_defines.h
dnnl_ocl.hpp mkl_vml_functions.h
dnnl_sycl.h mkl_vml.h
dnnl_sycl.hpp mkl_vml_types.h
dnnl_sycl_types.h mkl_vsl_defines.h
dnnl_threadpool.h mkl_vsl_functions.h
dnnl_threadpool.hpp mkl_vsl.h
dnnl_threadpool_iface.hpp mkl_vsl_types.h
dnnl_types.h oneapi
dnnl_version.h onnxruntime_c_api.h
experimental onnxruntime_cxx_api.h
gflags onnxruntime_cxx_inline.h
glog onnxruntime_run_options_config_keys.h
google onnxruntime_session_options_config_keys.h
i_malloc.h paddle2onnx
internal paddle_analysis_config.h
mkl_blas.h paddle_api.h
mkl_cblas.h paddle_infer_contrib.h
mkl_direct_blas.h paddle_infer_declare.h
mkl_direct_blas_kernels.h paddle_inference_api.h
mkl_direct_call.h paddle_mkldnn_quantizer_config.h
mkl_direct_lapack.h paddle_pass_builder.h
mkl_direct_types.h paddle_tensor.h
mkl_dnn.h provider_options.h
mkl_dnn_types.h utf8proc.h
mkl.h xxhash.h
# 最后库文件和头文件都重命名为paddle
# 完成后可以再次使用Qt的测试项目测试一下,INCLUDEPATH就只添加/usr/include/paddle,LIBS只指定一次-L选项, -l选项保留,如下:
INCLUDEPATH += /usr/include/paddle/
LIBS += -L/usr/lib/paddle
LIBS += -lpaddle_inference
LIBS += -lgflags
LIBS += -lglog
LIBS += -lmkldnn
LIBS += -liomp5 -lmklml_intel
LIBS += -lprotobuf
LIBS += -lxxhash
- 编写paddle.pc文件
pkg-config可以很方便管理头文件和库文件引用,只需要一个.pc文件。因此可以自己编写一个.pc文件,以后就可以方便的使用pkg-config引用paddle库了。
经过以上提取,paddle所有头文件和第三方头文件我们都放到了/usr/include/paddle中。所有库文件,包含动态库和静态库都放到了/usr/lib/paddle中。
cd /usr
# 查找.pc文件存放位置
find . -iname opencv4.pc
# 找到如下位置
./lib/x86_64-linux-gnu/pkgconfig/opencv4.pc
# 可以照着写一个自己的paddle.pc
# Package Information for pkg-config
prefix=/usr
exec_prefix=${prefix}
libdir=${exec_prefix}/lib/paddle
includedir=${prefix}/include/paddle
Name: Paddle
Description: Open Source Computer Vision Library
Version: 1.0.0
Libs: -L${exec_prefix}/lib/paddle -lpaddle_inference -lgflags -lglog -lmkldnn -liomp5 -lmklml_intel -lprotobuf -lxxhash
Cflags: -I${includedir}
# 完成后看下是否成功
pkg-config --cflags --libs paddle
# 输出如下,如果需要的库不在这里面,可以自己更改paddle.pc增加
-I/usr/include/paddle -L/usr/lib/paddle -lpaddle_inference -lgflags -lglog -lmkldnn -liomp5 -lmklml_intel -lprotobuf -lxxhash
# 进入paddleTest项目直接编译运行,编译通过
g++ -o main main.cc `pkg-config --cflags --libs paddle`
# 复制推理模型到当前目录,运行程序,效果与前面一致
到这里已经完成了paddle.pc文件编写,下面就可以在Qt creator中以2句简单的命令引入paddle库了.
CONFIG += link_pkgconfig
PKGCONFIG += paddle