Files
FastDeploy/docs/ARM-Linux-CPP-SDK-Inference.md
2022-06-27 18:23:21 +08:00

405 lines
17 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 简介
本文档介绍FastDeploy中的模型SDK在ARM Linux C++环境下 1推理部署步骤 2介绍模型推流全流程API方便开发者了解项目后二次开发。
其中ARM Linux Python请参考[ARM Linux Python环境下的推理部署](./ARM-Linux-Python-SDK-Inference.md)文档。
**注意**部分模型如Tinypose、OCR等仅支持图像推理不支持视频推理。
<!--ts-->
* [简介](#简介)
* [环境准备](#环境准备)
* [1. 硬件支持](#1-硬件支持)
* [2. 软件环境](#2-软件环境)
* [快速开始](#快速开始)
* [1. 项目结构说明](#1-项目结构说明)
* [2. 测试Demo](#2-测试demo)
* [2.1 预测图像](#21-预测图像)
* [2.2 预测视频流](#22-预测视频流)
* [预测API流程详解](#预测api流程详解)
* [1. SDK参数运行配置](#1-sdk参数运行配置)
* [2. 初始化Predictor](#2-初始化predictor)
* [3. 预测推理](#3-预测推理)
* [3.1 预测图像](#31-预测图像)
* [3.2 预测视频](#32-预测视频)
* [FAQ](#faq)
<!--te-->
# 环境准备
## 1. 硬件支持
目前支持的ARM架构aarch64 、armv7hf
## 2. 软件环境
1.运行二进制文件-环境要求
* gcc: 5.4 以上 (GLIBCXX_3.4.22)
* Linux下查看gcc版本命名可能因系统差异命令会不同`gcc --version`
* Linux下C++基础库GLIBCXX的命令因系统差异库路径会有不同`strings /usr/lib64/libstdc++.so.6 | grep GLIBCXX`
* glibc2.23以上
* Linux查看命令`ldd --version`
2.二次开发编译-环境要求
编译源代码时除gcc、GLIBCXX、glibc满足`1.运行二进制文件-环境要求`cmake需满足
* cmake: 3.0 以上
* Linux查看命令`cmake --version`
# 快速开始
## 1. 项目结构说明
根据开发者模型、部署芯片、操作系统需要,在图像界面[飞桨开源模型](https://ai.baidu.com/easyedge/app/openSource)或[GIthub](https://github.com/PaddlePaddle/FastDeploy)中选择对应的SDK进行下载。SDK目录结构如下
```
.EasyEdge-Linux-m43157-b97741-x86
├── RES                 # 模型资源文件夹一套模型适配不同硬件、OS和部署方式
│ ├── conf.json        # Android、iOS系统APP名字需要
│ ├── model # 模型结构文件
│ ├── params # 模型参数文件
│ ├── label_list.txt # 模型标签文件
│ ├── infer_cfg.json # 模型前后处理等配置文件
├── ReadMe.txt
├── cpp # C++ SDK 文件结构
└── baidu_easyedge_ocr_linux_cpp_aarch64_ARM_gcc5.4_v1.5.1_20220530.tar.gz #armv8架构硬件的C++包,根据自己硬件,选择对应的压缩包解压即可
├── ReadMe.txt
├── bin # 可直接运行的二进制文件
├── include # 二次开发用的头文件
├── lib # 二次开发用的所依赖的库
├── src # 二次开发用的示例工程
└── thirdparty # 第三方依赖
└── baidu_easyedge_ocr_linux_cpp_armv7l_armv7hf_ARM_gcc5.4_v1.5.1_20220530.tar.gz #armv7架构硬件的C++包,根据自己硬件,选择对应的压缩包解压即可
└── python # Python SDK 文件
```
**注意**
1. 【OCR需要编译】因为OCR任务的特殊性本次SDK没有提供bin文件夹可执行文件。开发者根据需要满足文档中gcc和cmake要求后`src/demo*`路径编译获取可执行文件,具体可参考。
2. 【OCR仅支持图像推理不支持视频流推理】
3. ARM-Linux-Python的环境要求和使用请参考[ARM Linux Python环境下的推理部署](./ARM-Linux-Python-SDK.md)文档。
## 2. 测试Demo
> 模型资源文件即压缩包中的RES文件夹默认已经打包在开发者下载的SDK包中请先将tar包整体拷贝到具体运行的设备中再解压缩使用。
SDK中已经包含预先编译的二进制可直接运行。以下运行示例均是`cd cpp/bin`路径下执行的结果。
### 2.1 预测图像
```bash
./easyedge_image_inference {模型RES文件夹路径} {测试图片路径}
```
运行效果示例:
<div align=center><img src="https://user-images.githubusercontent.com/54695910/175855351-68d1a4f0-6226-4484-b190-65f1ac2c7128.png" width="400"></div>
```bash
> ./easyedge_image_inference ../../../../RES 2.jpeg
2019-02-13 16:46:12,659 INFO [EasyEdge] [easyedge.cpp:34] 140606189016192 Baidu EasyEdge Linux Development Kit 0.2.1(20190213)
2019-02-13 16:46:14,083 INFO [EasyEdge] [paddlev2_edge_predictor.cpp:60] 140606189016192 Allocate graph success.
2019-02-13 16:46:14,326 DEBUG [EasyEdge] [paddlev2_edge_predictor.cpp:143] 140606189016192 Inference costs 168 ms
1, 1:txt_frame, p:0.994905 loc: 0.168161, 0.153654, 0.920856, 0.779621
Done
```
### 2.2 预测视频流
```
./easyedge_video_inference {模型RES文件夹路径} {video_type} {video_src_path}
```
其中 video_type 支持三种:
```
video_type : 1 // 本地视频文件
video_type : 2 // 摄像头的index
video_type : 3 // 网络视频流
```
video_src_path: 为 video_type 数值所对应的本地视频路径 、本地摄像头id、网络视频流地址
```
本地视频文件: ./easyedge_video_inference {模型RES文件夹路径} 1 /my_video_file.mp4
本地摄像头: ./easyedge_video_inference {模型RES文件夹路径} 2 1 #/dev/video1
网络视频流: ./easyedge_video_inference {模型RES文件夹路径} 3 rtmp://192.168.x.x:8733/live/src
```
注:以上路径是假模拟路径,开发者需要根据自己实际图像/视频,准备测试图像,并填写正确的测试路径。
# 预测API流程详解
本章节主要结合[2.测试Demo](#4)的Demo示例介绍推理API方便开发者学习后二次开发。更详细的API请参考`include/easyedge/easyedge*.h`文件。图像、视频的推理包含以下3个API如下代码片段`step`注释所示。
> ❗注意:<br>
> 1`src`文件夹中包含完整可编译的cmake工程实例建议开发者先行了解[cmake工程基本知识](https://cmake.org/cmake/help/latest/guide/tutorial/index.html)。 <br>
> 2请优先参考SDK中自带的Demo工程的使用流程和说明。遇到错误请优先参考文件中的注释、解释、日志说明。
```cpp
// step 1: SDK配置运行参数
EdgePredictorConfig config;
config.model_dir = {模型文件目录};
// step 2: 创建并初始化Predictor这这里选择合适的引擎
auto predictor = global_controller()->CreateEdgePredictor(config);
// step 3-1: 预测图像
auto img = cv::imread({图片路径});
std::vector<EdgeResultData> results;
predictor->infer(img, results);
// step 3-2: 预测视频
std::vector<EdgeResultData> results;
FrameTensor frame_tensor;
VideoConfig video_config;
video_config.source_type = static_cast<SourceType>(video_type); // source_type 定义参考头文件 easyedge_video.h
video_config.source_value = video_src;
/*
... more video_configs, 根据需要配置video_config的各选项
*/
auto video_decoding = CreateVideoDecoding(video_config);
while (video_decoding->next(frame_tensor) == EDGE_OK) {
results.clear();
if (frame_tensor.is_needed) {
predictor->infer(frame_tensor.frame, results);
render(frame_tensor.frame, results, predictor->model_info().kind);
}
//video_decoding->display(frame_tensor); // 显示当前frame需在video_config中开启配置
//video_decoding->save(frame_tensor); // 存储当前frame到视频需在video_config中开启配置
}
```
若需自定义library search path或者gcc路径修改对应Demo工程下的CMakeList.txt即可。
## 1. SDK参数运行配置
SDK的参数通过`EdgePredictorConfig::set_config``global_controller()->set_config`配置。本Demo 中设置了模型路径,其他参数保留默认参数。更详细的支持运行参数等,可以参考开发工具包中的头文件(`include/easyedge/easyedge_xxxx_config.h`)的详细说明。
配置参数使用方法如下:
```
EdgePredictorConfig config;
config.model_dir = {模型文件目录};
```
## 2. 初始化Predictor
* 接口
```cpp
auto predictor = global_controller()->CreateEdgePredictor(config);
predictor->init();
```
若返回非0请查看输出日志排查错误原因。
## 3. 预测推理
### 3.1 预测图像
> 在Demo中展示了预测接口infer()传入cv::Mat& image图像内容并将推理结果赋值给std::vector<EdgeResultData>& result。更多关于infer()的使用,可以根据参考`easyedge.h`头文件中的实际情况、参数说明自行传入需要的内容做推理
* 接口输入
```cpp
/**
* @brief
* 通用接口
* @param image: must be BGR , HWC format (opencv default)
* @param result
* @return
*/
virtual int infer(cv::Mat& image, std::vector<EdgeResultData>& result) = 0;
```
图片的格式务必为opencv默认的BGR, HWC格式。
* 接口返回
`EdgeResultData`中可以获取对应的分类信息、位置信息。
```cpp
struct EdgeResultData {
int index; // 分类结果的index
std::string label; // 分类结果的label
float prob; // 置信度
// 物体检测 或 图像分割时使用:
float x1, y1, x2, y2; // (x1, y1): 左上角, x2, y2): 右下角; 均为0~1的长宽比例值。
// 图像分割时使用:
cv::Mat mask; // 0, 1 的mask
std::string mask_rle; // Run Length Encoding游程编码的mask
};
```
*** 关于矩形坐标 ***
x1 * 图片宽度 = 检测框的左上角的横坐标
y1 * 图片高度 = 检测框的左上角的纵坐标
x2 * 图片宽度 = 检测框的右下角的横坐标
y2 * 图片高度 = 检测框的右下角的纵坐标
*** 关于图像分割mask ***
```
cv::Mat mask为图像掩码的二维数组
{
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
}
其中1代表为目标区域0代表非目标区域
```
*** 关于图像分割mask_rle ***
该字段返回了mask的游程编码解析方式可参考 [http demo](https://github.com/Baidu-AIP/EasyDL-Segmentation-Demo)
以上字段可以参考demo文件中使用opencv绘制的逻辑进行解析
### 3.2 预测视频
SDK 提供了支持摄像头读取、视频文件和网络视频流的解析工具类`VideoDecoding`,此类提供了获取视频帧数据的便利函数。通过`VideoConfig`结构体可以控制视频/摄像头的解析策略、抽帧策略、分辨率调整、结果视频存储等功能。对于抽取到的视频帧可以直接作为SDK infer 接口的参数进行预测。
* 接口输入
class`VideoDecoding`
```
/**
* @brief 获取输入源的下一帧
* @param frame_tensor
* @return
*/
virtual int next(FrameTensor &frame_tensor) = 0;
/**
* @brief 显示当前frame_tensor中的视频帧
* @param frame_tensor
* @return
*/
virtual int display(const FrameTensor &frame_tensor) = 0;
/**
* @brief 将当前frame_tensor中的视频帧写为本地视频文件
* @param frame_tensor
* @return
*/
virtual int save(FrameTensor &frame_tensor) = 0;
/**
* @brief 获取视频的fps属性
* @return
*/
virtual int get_fps() = 0;
/**
* @brief 获取视频的width属性
* @return
*/
virtual int get_width() = 0;
/**
* @brief 获取视频的height属性
* @return
*/
virtual int get_height() = 0;
```
struct `VideoConfig`
```
/**
* @brief 视频源、抽帧策略、存储策略的设置选项
*/
struct VideoConfig {
SourceType source_type; // 输入源类型
std::string source_value; // 输入源地址如视频文件路径、摄像头index、网络流地址
int skip_frames{0}; // 设置跳帧每隔skip_frames帧抽取一帧并把该抽取帧的is_needed置为true
int retrieve_all{false}; // 是否抽取所有frame以便于作为显示和存储对于不满足skip_frames策略的frame把所抽取帧的is_needed置为false
int input_fps{0}; // 在采取抽帧之前设置视频的fps
Resolution resolution{Resolution::kAuto}; // 采样分辨率只对camera有效
bool enable_display{false}; // 默认不支持。
std::string window_name{"EasyEdge"};
bool display_all{false}; // 是否显示所有frame若为false仅显示根据skip_frames抽取的frame
bool enable_save{false};
std::string save_path; // frame存储为视频文件的路径
bool save_all{false}; // 是否存储所有frame若为false仅存储根据skip_frames抽取的frame
std::map<std::string, std::string> conf;
};
```
| 序号 | 字段 | 含义 |
| --- | -------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| 1 | `source_type` | 输入源类型支持视频文件、摄像头、网络视频流三种值分别为1、2、3 |
| 2 | `source_value` | 若`source_type`为视频文件,该值为指向视频文件的完整路径;若`source_type`为摄像头该值为摄像头的index如对于`/dev/video0`的摄像头则index为0若`source_type`为网络视频流,则为该视频流的完整地址。 |
| 3 | `skip_frames` | 设置跳帧每隔skip_frames帧抽取一帧并把该抽取帧的is_needed置为true标记为is_needed的帧是用来做预测的帧。反之直接跳过该帧不经过预测。 |
| 4 | `retrieve_all` | 若置该项为true则无论是否设置跳帧所有的帧都会被抽取返回以作为显示或存储用。 |
| 5 | `input_fps` | 用于抽帧前设置fps |
| 6 | `resolution` | 设置摄像头采样的分辨率,其值请参考`easyedge_video.h`中的定义,注意该分辨率调整仅对输入源为摄像头时有效 |
| 7 | `conf` | 高级选项。部分配置会通过该map来设置 |
*** 注意:***
1. `VideoConfig`不支持`display`功能。如果需要使用`VideoConfig`的`display`功能需要自行编译带有GTK选项的OpenCV。
2. 使用摄像头抽帧时,如果通过`resolution`设置了分辨率调整,但是不起作用,请添加如下选项:
```
video_config.conf["backend"] = "2";
```
3. 部分设备上的CSI摄像头尚未兼容如遇到问题可以通过工单、QQ交流群或微信交流群反馈。
具体接口调用流程可以参考SDK中的`demo_video_inference`。
# FAQ
1. 如何处理一些 undefined reference / error while loading shared libraries?
> 如:./easyedge_demo: error while loading shared libraries: libeasyedge.so.1: cannot open shared object file: No such file or directory
遇到该问题时请找到具体的库的位置设置LD_LIBRARY_PATH或者安装缺少的库。
> 示例一libverify.so.1: cannot open shared object file: No such file or directory
> 链接找不到libveirfy.so文件一般可通过 export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:../../lib 解决(实际冒号后面添加的路径以libverify.so文件所在的路径为准)
> 示例二libopencv_videoio.so.4.5: cannot open shared object file: No such file or directory
> 链接找不到libopencv_videoio.so文件一般可通过 export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:../../thirdparty/opencv/lib 解决(实际冒号后面添加的路径以libopencv_videoio.so所在路径为准)
> 示例三GLIBCXX_X.X.X not found
> 链接无法找到glibc版本请确保系统gcc版本>=SDK的gcc版本。升级gcc/glibc可以百度搜索相关文献。
2. 运行二进制时,提示 libverify.so cannot open shared object file
可能cmake没有正确设置rpath, 可以设置LD_LIBRARY_PATH为sdk的lib文件夹后再运行
```bash
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../lib ./easyedge_demo
```
3. 编译时报错file format not recognized
可能是因为在复制SDK时文件信息丢失。请将整个压缩包复制到目标设备中再解压缩、编译。