该项目中的QT设计代码,也支持其它平台下QT的运行——但需要保证各平台下拥有opencv的编译库(动态链接库与头文件(include)库),以及正常编译得到的动态链接库(*.a 或 *.so).
项目文档目录:
jetson_build.sh编译参数CMakeList.txt参数yaml.cmake参数model_infer.cpp文件CMakeList.txt文件jetson_build.sh编译QDebug实现运行日志输出在新版本的PaddleX中,对于CPP的部署代码方式做了非常大的变化:
下面我们具体以Jetson Xavier系统为例,基于PaddleX的这套CPP(deploy/),说明一下如何实现QT的部署
项目使用基本环境说明:
查看Jetpack版本:
cat /usr/local/cuda/include/cudnn.h | grep CUDNN_MAJOR -A 2(4.3可以使用4.4版本的预测库)查看QT版本:
qmake -v查看CUDA版本:
cat /usr/local/cuda/version.txt查看Cudnn版本:
cat /usr/include/cudnn_version.h | grep CUDNN_MAJOR -A 2
下载QT:
sudo apt-get install qt5-default qtcreator -y
下载PaddleX+PaddleInference预测库:
可查看文档:
cmake -version保证版本大于3.5即可,如小于,可尝试安装
cmake3.10.2。
QT-Creater的启动,可以通过应用搜索,输入QT,在出现的应用图标中选中QTCreater,点击即可启动!
如果已经查看
Jetson环境编译文档后,并已经成功编译出可执行程序后,可跳过该部分的deploy/cpp/scripts/jetson_build.sh、deploy/cpp/CMakeList.txt以及deploy/cpp/cmake/yaml.cmake的修改说明.以下3部分的修改完全同基于PaddleInference的推理-Jetson环境编译一样,可前往参阅。
jetson_build.sh编译参数根据自己的系统环境,修改PaddleX/deploy/cpp/script/jetson_build.sh脚本中的参数,主要修改的参数为以下几个
| 参数 | 说明 |
| :------------ | :----------------------------------------------------------------------------------- |
| WITH_GPU | ON或OFF,表示是否使用GPU,当下载的为CPU预测库时,设为OFF |
| PADDLE_DIR | 预测库所在路径,默认为PaddleX/deploy/cpp/paddle_inference目录下 |
| CUDA_LIB | cuda相关lib文件所在的目录路径 -- 请注意jetson预装的cuda所在路径(如:/usr/local/cuda/lib64) |
| CUDNN_LIB | cudnn相关lib文件所在的目录路径 -- 请注意jetson预装的cuda所在路径(如:/usr/lib/aarch64-linux-gnu) |
| WITH_TENSORRT | ON或OFF,表示是否使用开启TensorRT |
| TENSORRT_DIR | TensorRT 的路径,如果开启TensorRT开关WITH_TENSORRT,需修改为您实际安装的TensorRT路径 |
| WITH_ENCRYPTION | ON或OFF,表示是否开启加密模块 |
| OPENSSL_DIR | OPENSSL所在路径,解密所需。默认为PaddleX/deploy/cpp/deps/penssl-1.1.0k目录下 |
要注意相关参数路径不要有误——特别是CUDA_LIB以及CUDNN_LIB,如果需要启动TensorRt,也需指定当前的路径。
不需要添加oepncv路径,在jetson中编译可直接使用环境本身预装的opencv进行deploy编译——具体配置在Step4中。
CMakeList.txt参数该修改仅适合Jetson系统的部署编译。
根据自己的系统环境,修改PaddleX/deploy/cpp/CMakeLists.txt脚本中的参数,主要修改的参数为以下几个:位于其中注释#OPENCV之后的部分
| 参数 | 说明 |
| :------------ | :----------------------------------------------------------------------------------- |
| set(OpenCV_INCLUDE_DIRS "/usr/include/opencv") | 配置Jetson预置opencv的include路径 |
| file(GLOB OpenCVLIBS /usr/lib/libopencv${CMAKE_SHARED_LIBRARY_SUFFIX}) | 配置opencv动态链接库.so |
替换具体如下:(xavier为例)
/usr/include/opencv --> /usr/include/opencv4
具体路径,以部署环境中opencv的include路径为准。 opencv4 中包含: opencv, opencv2
/usr/lib/libopencv_${CMAKE_SHARED_LIBRARYSUFFIX} --> /usr/lib/libopencv${CMAKE_SHARED_LIBRARY_SUFFIX}
具体路径,以部署环境中opencv的*.so路径为准, 主要修改libopencv_前的路径。
yaml.cmake参数由于Jetson环境下编译还需要yaml,所以这里需要手动下载yaml包,保证编译的正常运行。
- 点击下载yaml依赖包,无需解压
- 修改
PaddleX/deploy/cpp/cmake/yaml.cmake文件,将URL https://bj.bcebos.com/paddlex/deploy/deps/yaml-cpp.zip中网址替换为第3步中下载的路径,如改为URL /Users/Download/yaml-cpp.zip
这里yaml存放路径为了确保使用最好保证全英文路径 eg:
其它支持的加密操作以及TensorRT,可参考Linux环境编译指南.
该部分需要修改两个地方,以保证动态链接库的正常生成。
接下来的操作,请在执行以下命令正常生成可执行程序后再往下继续配置,以确保修改前的工作是正确可执行的。
sh script/jetson_build.sh编译时,如果存在cmake多线程问题——请前往
jetson_build.sh末尾,将make -j8改为make或者小于8.编译后会在
PaddleX/deploy/cpp/build/demo目录下生成model_infer、multi_gpu_model_infer和batch_infer等几个可执行二进制文件.
model_infer.cpp文件接下来我们需要在QT中去调用动态链接库,所以原有的deploy/cpp/demo/model_infer.cpp文件生成的可执行文件不能支持QT去进行调用,所以需要对其进行一定的修改。
现已将修改后满足需求的文件放于本文档处,即——将当前文件的model_infer.cpp用于替换deploy/cpp/demo/model_infer.cpp即可.
该model_infer.cpp仅支持使用一个模型——用于单线程调用
如需多线程推理,同时创建多个模型用于预测推理,可以参考该项目下cpp的实现: PaddleDeploy在C#端的多线程推理demo
模型初始化接口: InitModel(const char* model_type, const char* model_filename, const char* params_filename, const char* cfg_file, bool use_gpu, int gpu_id, char* paddlex_model_type)
目标检测推理接口: Det_ModelPredict(const unsigned char* img, int nWidth, int nHeight, int nChannel, float* output, int* nBoxesNum, char* LabelList)
语义分割推理接口: Seg_ModelPredict(const unsigned char* img, int nWidth, int nHeight, int nChannel, unsigned char* output)
图像识别推理接口: Cls_ModelPredict(const unsigned char* img, int nWidth, int nHeight, int nChannel, float* score, char* category, int* category_id)
实例分割推理接口: Mask_ModelPredict(const unsigned char* img, int nWidth, int nHeight, int nChannel, float* box_output, unsigned char* mask_output, int* nBoxesNum, char* LabelList)
模型销毁接口: DestructModel()
详细说明,请查看
model_infer.cpp的实现.
CMakeList.txt文件以上完成了model_infer.cpp的修改后,需要修改当前目录下的CMakeList.txt文件,位于: deploy/cpp/demo/CMakeList.txt.
需要修改的内容,如图所示:
用ADD_library那句脚本替换下划线那句脚本即可,也可直接使用本项目提供的CMakeList.txt进行替换deploy/cpp/demo/CMakeList.txt.
jetson_build.sh编译运行以下命令行, 编译完成即可获得所需推理接口的动态链接库(libmodel_infer.so)
sh script/jetson_build.sh
运行完成,会在PaddleX/deploy/cpp/build/lib中生成libmodel_infer.so动态链接库。
以下步骤请确保QT安装完成,且可以正常启动QT桌面项目。
Qtcreator,新建项目,取名为Deploy_infer,选择项目路径为自己所熟悉的路径即可,然后一直顺着往下不必多设置或者勾选什么,直到finished。如果存在多个编译环境供QT使用,请确保QT使用的编译环境与前边生成动态链接库的编译环境一致——或者至少保证生成的所有库都允许相互调用,即避免出现32位与64位不兼容等情况。
进入QT崭新的工程项目后,工程项目中会存在*.pro,Headers,Sources,Forms四个主要组件,其中后三个为项目分支(目录)
右键点击项目,选择Add New, 进入子界面选择c++,选中Class, 点击choise.
在新出来的子界面中,输入InferThread作为Class name, 然后一直往下生成即可.
将本项目Deploy_infer中的inferthread.cpp与inferthread.h中的内容分别复制过去即可.
然后,再将本项目Deploy_infer中的mainwindow.cpp与mainwindow.h中的内容也复制过去.
最后,将本项目的mainwindow.ui替换新建的QT-GUI项目的ui文件.
此时,QT项目的移植就完成了——之所以新建项目,看起来比较复杂,是为了避免直接移植导致的QT版本不匹配,发生一些意料之外的问题。
此时QT项目中,会出现标红的错误,原因可能如下:
- 1. 还未导入动态链接库
- 2. 还未导入opencv的编译好的库
- 因此,现在暂时不用担心标红的问题
在创建的QT项目文件夹下新建infer_lib文件夹,将生成的libmodel_infer.so文件移入其中即可。
然后打开Qtcreator, 打开项目选择本QT项目启动,可观察到QT工程目录结构如图所示:
双击mainwindow.cpp进入,确保第一个函数中,导入的动态链接库绝对路径无误!
此时QT项目中,会出现标红的错误,原因可能如下:
- 1. 还未导入opencv的编译好的库
- 因此,现在暂时不用担心标红的问题
请保证编译opencv的编译环境与当前QT使用的编译环境一致,否则可能无法导入opencv中的函数.
该部分主要配置两个部分: Include Path 和 Lib Path.
双击Deploy_infer.pro进入,按照如图所示写入当前环境下系统原装预编译的Opencv路径:
INCLUDEPATH : 表示opencv的头文件所在路径,包含头文件根目录,opencv子目录以及opencv2子目录LIBS : 表示opencv的动态链接库so文件所在路径,这里使用正则匹配,自动匹配路径下的所有opencv.so文件在本测试Jetson环境上,预编译opencv由于没有同ffmpeg一同编译,因此不支持视频流的处理与预测(无法打开视频文件,如mp4,avi等)
如有需要可在此时另外编译opencv,不覆盖原预编译的opencv版本,仅用于QT程序进行图像/视频的读取和简单处理。
此时编译的新opencv,在编译时要选择编译参数使其支持QT、GL以及ffmpeg.(ffmpeg可能需要自行编译)
该方案的编译指导,可参考网上的
linux下opencv与ffmpeg联合编译资料。因此,本QT的Demo在
Jetson Xavier上,使用原生opencv,仅支持图片以及连续图片的预测,视频预测需要自行编译新的opencv,以支持视频读取——只要opencv编译成功,以上编译动态链接库的opencv路径仅需相应修改即可(记得更改后重新编译生成),同时修改QT导入的opencv库路径就可以正常使用该可视化Demo了。此时QT项目中,标红的错误应该会消失——可以稍微等一下QT项目更新项目缓存,记得保存修改!
PS:
在运行项目时,请注意,如果报cv::xxx未定义,可能为以下情况:
"",而非<>.LIBS有误,显示没有该文件(No Such File or Path)等报错,请查看opencv动态链接库是否配置正确.英文路径,因此在使用中文路径时如遇报错,请换成英文路径重新导入.
Jetson下仅测试了英文路径,Windows上中英文路径均无误。
启动后界面如下:
GPU下加载MaskRCNN进行实例分割可视化推理,需选择模型: maskCPU推理
GPU推理
一些方便大家修改Demo界面源码,以实现一些适配工作。
QDebug实现运行日志输出首先在mainwindow.cpp中导入#include <QDebug>,以支持QT程序运行过程中输出一些人为添加的日志输出。
实例代码:
输出如下:
工程目录:
推理子线程 —— 包含具体的推理执行函数的实现,以及运行控件状态信号的发出(比如,更新图片显示,与控件的使能与关闭)主线程 —— 包含界面布局控制的实现,推理文件加载(也包含动态链接库)的实现,以及推理线程的启动与中止信号的发出(比如,启动推离线程)由于QT可视化界面可能用于不同的系统,因此对于可分配运行内存而言是有一定的考量的,因此对于读取的图片在进行推理以及显示前进行一定的缩放,能够减少内存的消耗。
不过,显示时要保证图像宽高均可被4整除,否则控件图片显示可能有误。
每一个具体推理的函数里,都有以下操作,对推理前的图片进行缩放:
不要直接使用子线程对主线程控件进行控制,避免导致线程报错,线程问题不易debug——因此,多用信号与槽来实现交互。
实现思路:
具体实现流程:
PS: 子线程信号声明如下:
主线程槽声明如下:
1.进入inferthread.h与mainwindow.h中,使用typdef定义函数指针,按照函数参数格式进行定义。
即:model_infer.cpp中函数怎么定义的,这边就构建一个相同定义支持的函数指针。
2.inferthread.h中的定义展示:
3.mainwindow.h中的定义展示:
本项目只需要导入一个自己定义的动态链接库,因此使用QLibrary进行导入,该方法不适用于多动态库的导入,容易代码量多导致混淆。
该项目的导入如下:
运行环境改变时,注意运行环境对编译的库的影响,配置正确的opencv路径以及编译器版本
避免QT版本移植问题,先创建一个新的项目,然后拷贝已有的旧项目中的ui、cpp与h文件到新项目,同时修改pro文件中的配置一致即可完成跨版本跨平台的移植。
注意deploy编译所需的流程,可参考PaddleX模型推理部署deploy在Linux以及Windows上的编译指南.
注意区分不同平台上,动态链接库的命名区别: windows-.a , linux/jetson-.so
CMakeList.txt与model_infer.cpp替换原文件,然后按照linux编译方法进行编译)去自行生成。