C++示例
-
1.2 detection示例目录结构
1.3 yolov3示例目录结构
- 连接设备
-
3.1 本地图片预测
3.2 摄像头视频预测
-
4.1 FPGA预处理接口
4.2 预测库接口
-
5.1 python接口目录结构
5.2 安装和使用
5.3 本地图片预测示例
示例介绍
PaddleMobile示例仅在软核1.4.0及以下版本可用,1.5.1及以上版本请使用相对应的PaddleLite示例工程。
下载对应版本的示例工程请点击升级软核说明。
EdgeBoard系列硬件产品提供丰富的深度学习示例,用户在掌握EdgeBoard软核基本框架以后通过示例可以了解EdgeBoard中模型部署的基本流程,以及在示例中运行自己的模型,实现模型快速部署,加速项目落地。EdgeBoard系统自带的示例工程路径为:home/root/workspace/sample
系统包含的示例列表如下:
| 示例名称 | 说明 |
|---|---|
| classification | 图像分类模型示例工程,可以实现图片预测和usb摄像头视频预测 |
| detection | 物体检测模型示例工程,可以实现图片预测和usb摄像头视频预测 |
| yolov3 | yolov3网络模型示例工程,可以实现图片预测和usb摄像头视频预测 |
| sample_video | 视频预测示例工程,可以使用usb/mipi/bt1120接口摄像头、以及压缩的视频文件(EdgeBoardFZ5产品支持H264/H265视频压缩,其他型号不支持视频压缩)进行模型预测,缺点:支持模型单一,目前仅支持mobilenetssd网络模型。 |
| script | EdgeBoard内部视频通道配置脚本,默认为bt1120视频输入方式,如果使用mipi摄像头,需要将视频通道切换为mipi视频输入方式 |
| ebvideo | 视频源库,集成项目开发中常用的视频源操作工具,如gstreamer、SDK等,提供统一接口 |
classification示例目录结构
1├── CMakeLists.txt // cmake 工程配置文件。
2├── include
3│ └── io // paddle_mobile 头文件目录
4│ | ├── paddle_inference_api.h
5│ | ├── type_define.h
6│ | └── types.h
7| ├── commom.h
8| ├── float16.h
9| ├── image_preprocess.h //图像预处理头文件
10| ├── preprocess_conf.hpp
11| └── zynqmp_api.h
12|
13├── configs // 配置文件目录
14│ ├── Inceptionv2
15│ │ └─ zebra.json //Inceptionv2配置文件(万分类-预置斑马识别)
16│ ├── Inceptionv3
17│ │ └─ zebra.json //Inceptionv3配置文件(千分类-预置斑马识别)
18│ ├── mobilenetv1
19│ │ └─ zebra.json //mobilenetv1配置文件(千分类-预置斑马识别)
20│ └── resnet50
21│ └─ drink.json //resnet50配置文件(三分类-预置矿泉水识别)
22├── lib
23| ├── ln.sh //建立预测库软链接脚本文件
24│ └── libpaddle-mobile.so.1.5.0 //paddlemobile预测库
25├── models // 模型文件目录
26│ ├── Inceptionv2
27│ ├── Inceptionv3
28│ ├── mobilenetv1
29│ └── resnet50
30│── src
31│ ├── json.hpp // json 解析库
32│ ├── video_detection.cpp // 视频推理示例(cpu预处理)
33| ├── video_detection_fpga_preprocess.cpp // 视频推理示例(FPGA预处理)
34| ├── image_detection.cpp // 图片推理示例(CPU预处理)
35│ └── image_detection_fpga_preprocess.cpp // 图片推理示例(FPGA预处理)
36└── README.md
detection示例目录结构
1├── CMakeLists.txt // cmake 工程配置文件。
2├── include
3│ └── io // paddle_mobile 头文件目录
4│ | ├── paddle_inference_api.h
5│ | ├── type_define.h
6│ | └── types.h
7| ├── commom.h
8| ├── float16.h
9| ├── image_preprocess.h //图像预处理头文件
10| ├── preprocess_conf.hpp
11| └── zynqmp_api.h
12|
13├── configs // 配置文件目录
14│ ├── mobilenet-ssd
15│ │ └─ screw.json //mobilenetssd_300配置文件(螺丝螺母检测)
16│ ├── mobilenet-ssd-640
17│ │ └─ screw.json //mobilenetssd_640配置文件(螺丝螺母检测)
18│ └── vgg-ssd
19│ └─ screw.json //vggssd_300配置文件(螺丝螺母检测)
20|
21├── lib
22| ├── ln.sh //建立预测库软链接脚本文件
23│ └── libpaddle-mobile.so.1.5.0 //paddlemobile预测库
24|
25├── models // 模型文件目录
26│ ├── mobilenet-ssd
27│ ├── mobilenet-ssd-640
28│ └── vgg-ssd
29│── src
30│ ├── json.hpp // json 解析库
31│ ├── video_detection.cpp // 视频推理示例(cpu预处理)
32| ├── video_detection_fpga_preprocess.cpp // 视频推理示例(FPGA预处理)
33| ├── image_detection.cpp // 图片推理示例(CPU预处理)
34│ └── image_detection_fpga_preprocess.cpp // 图片推理示例(FPGA预处理)
35└── README.md
yolov3示例目录结构
1├── CMakeLists.txt // cmake 工程配置文件。
2├── include
3│ └── io // paddle_mobile 头文件目录
4│ | ├── paddle_inference_api.h
5│ | ├── type_define.h
6│ | └── types.h
7| ├── commom.h
8| ├── float16.h
9| ├── image_preprocess.h //图像预处理头文件
10| ├── preprocess_conf.hpp
11| └── zynqmp_api.h
12|
13├── configs // 配置文件目录
14│ ├── config.json //yolov3_608配置文件(车辆检测)
15│ └── config_easydl_416.json //yolov3_416模型配置文件(车辆检测)
16│
17├── lib
18| ├── ln.sh //建立预测库软链接脚本文件
19│ └── libpaddle-mobile.so.1.5.0 //paddlemobile预测库
20|
21├── models // 模型文件目录
22│ ├── easydl_yolov3
23│ └── easydl_yolov3_416
24│── src
25│ ├── json.hpp // json 解析库
26│ ├── video_detection.cpp // 视频推理示例(cpu预处理)
27| ├── video_detection_fpga_preprocess.cpp // 视频推理示例(FPGA预处理)
28| ├── image_detection.cpp // 图片推理示例(CPU预处理)
29│ └── image_detection_fpga_preprocess.cpp // 图片推理示例(FPGA预处理)
30└── README.md
sample_video示例目录结构
1├── CMakeLists.txt // cmake 工程配置文件
2├── include //头文件目录
3|
4├── image // 预测图片目录
5|
6├── lib
7| ├── ln.sh //建立预测库软链接脚本文件
8│ └── libpaddle-mobile.so.1.5.0 //paddlemobile预测库
9|
10├── models // 模型文件目录(预置vggssd模型)
11|
12│── src
13│ ├── capturer.cpp
14│ ├── dev_hw.hpp
15│ ├── main.cpp
16│ ├── paddle_interface.cpp
17│ ├── protocol.cpp
18│ └── ssd_detect.cpp
19└── README.md
连接设备
连接设备前需了解设备的外设接口,请依据设备型号参考对应的硬件介绍
连接设备步骤:
- 保证配套的系统TF卡已经插到设备SD卡槽;
- 使用配套电源给EdgeBoard供电,启动EdgeBoard。启动详情请参考启动关机和重启。
- 插入网线或者配套的串口调试线,EdgeBoard支持两种调试方式,网络调试和串口调试,EdgeBoard出厂默认的静态IP为192.168.1.254,login:root,password:root,推荐使用网络SSH连接方式调试更加方便快捷,设备连接方式详情请参考[网口连接设备通讯](串口连接设备通讯
运行示例
考虑到简单通用性,EdgeBoard示例运行方法基本统一,即为每个模型提供配置文件(json文件),从配置文件中读取模型和图片信息,加载并执行。每个实例工程内有对应的配置文件目录,所以运行示例时需要指定相应的配置文件。
配置文件内容示例
1{
2 "model":"../models/vgg-ssd",
3 "combined_model":true,
4 "input_width":224,
5 "input_height":224,
6 "image":"../models/vgg-ssd/screw.jpg",
7 "mean":[104,117,124],
8 "scale":1,
9 "format":"BGR"
10 "threshold":0.5
11}
配置文件参数说明
| key | value |
|---|---|
| model | 模型目录存放的位置 |
| combined_model | 是否为融合的模型,只有两个文件的是融合模型 |
| input_width | 输入网络的图片尺寸 输入图片会缩放到该大小 |
| input_height | 输入网络的图片尺寸 |
| image | 进行分类的图片输入 |
| mean | 平均值 |
| scale | 输入网络前预算处理为 ( x - mean ) * scale |
| format | 网络所需要的格式,OpenCV默认是BGR |
| threshold | 信心值阈值 |
本地图片预测
图片预测的步骤如下:
1、连接设备
2、加载驱动,系统启动后加载一次即可(系统默认已自启动,此步骤可省略)
3、示例工程lib中添加预测库(系统已添加的可省略)
4、编译示例
5、执行图片预测可执行文件
classification模型本地图片预测
classification模型本地图片预测步骤如下:
1、连接设备
2、加载驱动,系统启动后加载一次即可(系统默认已自启动,此步骤可省略)
1insmod /home/root/workspace/driver/fpgadrv.ko
3、示例工程lib中添加预测库(系统已添加的可省略)
例如:使用samba工具或者ftp工具拷贝libpaddlemobile.so.1.5.0和ln.sh拷贝到classification示例工程的lib目录home/root/workspace/sample/classification/lib,并执行脚本
1在lib目录中执行脚本
2sh ln.sh
4、进入classification示例工程,编译示例
1//进入classification工程目录
2cd /home/root/workspace/sample/classification/
3// 如果没有build目录,创建一个
4mkdir build
5//打开build目录
6cd build
7// 调用cmake 创建 Makefile
8cmake ..
9// 编译工程。
10make
编译完成,build目录下会出现image_classify和video_classify两个可执行文件,图片预测运行image_classify文件
注意:使用系统自带的sample,已默认编译,用户可直接进入build目录使用对应的可执行文件
5、执行示例
1cd /home/root/workspace/sample/classification/build
1./image_classify {json文件路径}
2// image_classify 使用cpu预处理, image_classify_fpga_preprocess使用fpga预处理
例如:
a、使用cpu预处理调用resnet模型进行图片预测
1./image_classify ../configs/resnet50/drink.json
执行结果:
b、使用fpga预处理调用resnet50模型进行图片预测
1./image_classify_fpga_preprocess ../configs/resnet50/drink.json
执行结果:
detection模型本地图片预测
detection模型本地图片预测步骤如下:
1、连接设备
2、加载驱动,系统启动后加载一次即可(系统默认已自启动,此步骤可省略)
1insmod /home/root/workspace/driver/fpgadrv.ko
3、示例工程lib中添加预测库(系统已添加的可省略)
例如:使用samba工具或者ftp工具拷贝libpaddlemobile.so.1.5.0和ln.sh拷贝到detection示例工程的lib目录home/root/workspace/sample/detection/lib,并执行脚本
1在lib目录中执行脚本
2sh ln.sh
4、进入示例工程,编译示例
1//进入yolov3工程目录
2cd /home/root/workspace/sample/detection
3// 如果没有build目录,创建一个
4mkdir build
5//打开build目录
6cd build
7// 调用cmake 创建 Makefile
8cmake ..
9// 编译工程。
10make
5、执行示例
1cd /home/root/workspace/sample/detection/build
1// image_detection 使用cpu预处理, image_detection_fpga_preproces使用fpga预处理
2./image_detect {json文件路径}
例如:
a、使用cpu预处理调用vgg-ssd模型进行图片预测
1./image_detect ../config/vgg-ssd/screw.json
执行结果:
b、使用fpga预处理调用vgg-ssd模型进行图片预测
1./image_detect_fpga_preprocess ../config/vgg-ssd/screw.json
执行结果:
结果图片:
yolov3模型本地图片预测
yolov3模型本地图片预测步骤如下:
1、连接设备
2、加载驱动,系统启动后加载一次即可(系统默认已自启动,此步骤可省略)
1insmod /home/root/workspace/driver/fpgadrv.ko
3、示例工程lib中添加预测库(系统已添加的可省略)
例如:使用samba工具或者ftp工具拷贝libpaddlemobile.so.1.5.0和ln.sh拷贝到yolov3示例工程的lib目录home/root/workspace/sample/yolov3/lib,并执行脚本
1在lib目录中执行脚本
2sh ln.sh
4、进入示例工程,编译示例
1//进入yolov3工程目录
2cd /home/root/workspace/sample/yolov3
3// 如果没有build目录,创建一个
4mkdir build
5//打开build目录
6cd build
7// 调用cmake 创建 Makefile
8cmake ..
9// 编译工程。
10make
5、执行示例
1cd /home/root/workspace/sample/yolov3/build
1// image_detection 使用cpu预处理, image_detection_fpga_preprocess使用fpga预处理
2./image_detect {json文件路径}
例如:使用cpu预处理调用yolov3模型进行图片预测
1./image_detect ../configs/config.json
执行结果:
结果图片:
摄像头视频预测
使用USB摄像头
使用USB摄像头预测步骤如下:
1、USB摄像头和显示器连接EdgeBoard,USB摄像头和显示器注意事项请参考视频输入和输出,相关系统工具请参考tools工具。
2、连接设备
3、系统启动后,进入系统命令窗口,打开显示器桌面
1//打开显示器命令
2startx
4、加载驱动,系统启动后加载一次即可(系统默认已自启动,此步骤可省略)
1insmod /home/root/workspace/driver/fpgadrv.ko
5、示例工程lib中添加预测库(系统已添加的可省略)
例如:使用samba工具或者ftp工具拷贝libpaddlemobile.so.1.5.0和ln.sh拷贝到示例工程的lib目录(例如classification目录home/root/workspace/sample/classification/lib),并执行脚本
1在lib目录中执行脚本
2sh ln.sh
6、编译示例(如在图片预测时已全部编译,可忽略)
7、运行示例
图片分类模型视频预测:
1cd /home/root/workspace/sample/classification/build
1./video_classify {json文件路径}
2// video_classify 使用cpu预处理, video_classify_fpga_preproces使用fpga预处理
例如:调用resnet50模型进行视频预测
1./video_classify ../configs/resnet50/drink.json
物体检测模型视频预测:
1cd /home/root/workspace/sample/detection/build
1./video_detection {json文件路径}
2// video_detection 使用cpu预处理, video_dection_fpga_preproces使用fpga预处理
例如:调用vgg-ssd模型进行视频预测
1./video_detection ../configs/vgg-ssd/screw.json
使用BT1120摄像头
*BT1120仅EdgeBoard软核1.4.0及以下版本支持,1.5.0不支持
使用BT1120摄像头预测步骤:
1、BT1120摄像头和显示器连接EdgeBoard,BT1120摄像头和显示器注意事项请参考视频输入和输出,相关系统工具请参考tools工具。
2、连接设备
3、系统启动后,进入系统命令窗口,打开显示器桌面
1//打开显示器命令
2startx
4、加载驱动,系统启动后加载一次即可(系统默认已自启动,此步骤可省略)
1insmod /home/root/workspace/driver/fpgadrv.ko
5、确保vdma视频设备配置正确,有些版本的系统镜像可能需要对其初始配置,使用如下命令
1media-ctl -v --set-format '"a0010000.v_tpg":0 [RBG24 1920x1080 field:none]'
6、示例工程lib中添加预测库和视频源库
a、使用samba工具或者ftp工具拷贝libpaddlemobile.so.1.4.0和ln.sh拷贝到示例工程的lib目录(home/root/workspace/sample_video/lib),并执行脚本
1在lib目录中执行脚本
2sh ln.sh
b、编译视频源库ebvideo,将生成的libebvideo.so放入sample_video的lib目录
1mkdir build
2cd build
3cmake ..
4make
7、编译示例
1# 在本工程目录下建立build目录
2mkdir build
3# 进入build目录
4cd build
5# 编译
6cmake ..
7make
8、运行示例,
调用BT1120摄像头并做预测,将结果显示到桌面显示屏上
1./paddle_edgeboard -c 0 -i /dev/video1 -s
更多使用,请参考help
1./paddle_edgeboard -h
使用mipi摄像头
使用mipi摄像头预测步骤:
1、mipi摄像头和显示器连接EdgeBoard,mipi摄像头和显示器注意事项请参考视频输入和输出,相关系统工具请参考tools工具。
2、连接设备
3、系统启动后,进入系统命令窗口,打开显示器桌面
1//打开显示器命令
2startx
4、加载驱动,系统启动后加载一次即可(系统默认已自启动,此步骤可省略)
1insmod /home/root/workspace/driver/fpgadrv.ko
5、切换视频输入
由于EdgeBoard默认video1视频输入为BT1120,所以使用mipi需切换视频输入。拷贝script文件到EdgeBoard,执行./video_config.sh
1//切换为mipi视频输入
2./video_config.sh 2
脚本执行截图如下:
6、确保vdma视频设备配置正确,有些版本的系统镜像可能需要对其初始配置,使用如下命令
1media-ctl -v --set-format '"a0010000.v_tpg":0 [RBG24 1920x1080 field:none]'
7、示例工程lib中添加预测库和视频源库
a、使用samba工具或者ftp工具拷贝libpaddlemobile.so.1.4.0和ln.sh拷贝到示例工程的lib目录(home/root/workspace/sample_video/lib),并执行脚本
1在lib目录中执行脚本
2sh ln.sh
b、编译视频源库ebvideo,将生成的libebvideo.so放入sample_video的lib目录
1mkdir build
2cd build
3cmake ..
4make
8、编译示例
1// 在本工程目录下建立build目录
2mkdir build
3// 进入build目录
4cd build
5//
6cmake ..
7make
9、运行示例,
调用mipi摄像头并做预测,将结果显示到桌面显示屏上
1./paddle_edgeboard -c 0 -i /dev/video1 -s
更多使用,请参考help
1./paddle_edgeboard -h
C++接口调用
FPGA预处理接口
预处理接口主要是使用FPGA完成图片的缩放、颜色空间转换和mean/std操作。头文件位于include/image_preprocess.h
图像缩放:支持小于等于1080p的图片缩放,超过1080p需要使用opencv cpu进行缩放
颜色空间转换:YUV422, RGB, BGR相互转换
mean/std操作:使用FPGA运算,比cpu快2~5倍,同时支持变种mean‘和scale操作,转换公式为
具体接口
1 /**
2 * 判断输入图像是否是wc 16对齐
3 * width 输入图像宽度
4 * channel 输入图像高度
5 **/
6 bool img_is_align(int width, int channel);
7
8 /**
9 * 对齐后的大小
10 * width 输入图像宽度
11 * channel 输入图像高度
12 **/
13 int align_size(int width, int channel);
14
15 /**
16 * 分配存放图片的内存,析构函数会自动释放 (目前支持BGR->RGB RGB->BGR YUV422->BGR YUV->RGB) 图像最大分辨率支持1080p
17 * height 输入图像的框
18 * width 输入图像宽度
19 * in_format 输入图像格式 参考image_format
20 * return uint8_t* opencv Mat CV_8UC3
21 **/
22 uint8_t* mem_alloc(int img_height, int img_width, image_format in_format);
23
24 /**
25 * 如果传入的图片使用new或fpga_malloc申请的内存,手动释放输入图片内存
26 * data 需要释放的内存,比如申请的图像数据
27 **/
28 void freeImage(void* data);
29
30 /**
31 * 根据setImage设置进行图像缩放、输出数据进行减mean、乘scale 图像最大分辨率支持1080p
32 * input_width 输出图像宽,进入网络宽度
33 * input_height 输出图像高,进入网高度
34 * out_format 输出图像格式 参考image_format
35 * means 图像数据预处理减均值
36 * scales 图像数据预处理 乘scale
37 **/
38 void image2Tensor(int input_width, int input_height,
39 image_format out_format, float means[], float scales[], PaddleTensor* tensor);
40
41 /**
42 * 进行图像缩放、输出数据进行减mean、乘scale, 并wc(宽和通道)对接到16。只支持3通道图像数据输入
43 * (目前支持BGR->RGB RGB->BGR YUV422->BGR YUV->RGB) 图像最大分辨率支持1080p
44 * in 输入数据,uint_8, opencv Mat CV_8UC3
45 * in_width 输入图像宽
46 * in_height 输入图像高
47 * out_width 输出图像宽
48 * out_height 输出图像高
49 * in_format 输入图像格式 参考image_format
50 * out_format 输出图像格式 参考image_format
51 * means 图像数据预处理减均值
52 * stds 图像数据预处理 除std
53 * tensor 网络输入PaddleTensor
54 **/
55 void image2TensorStd(int input_width, int input_height, image_format out_format,
56 float means[], float stds[], PaddleTensor* tensor);
57
58 /**
59 * 进行图像缩放、输出数据进行减mean、乘scale, 并wc(宽和通道)对接到16。(
60 * 目前支持BGR->RGB RGB->BGR YUV422->BGR YUV->RGB) 图像最大分辨率支持1080p
61 * in 输入数据,uint_8, opencv Mat CV_8UC3
62 * in_width 输入图像宽
63 * in_height 输入图像高
64 * out 输出图像数据 float16
65 * input_width 输出图像宽,进入网络宽度
66 * input_height 输出图像高,进入网高度
67 * in_format 输入图像格式 参考image_format
68 * out_format 输出图像格式 参考image_format
69 * means 图像数据预处理减均值
70 * scales 图像数据预处理 乘scale
71 **/
72 void resize_preprocess_align(uint8_t* in, int in_width, int in_height, float16* out, int input_width, int input_height,
73 image_format in_format, image_format out_format, float means[], float scales[]);
74
75
76 /**
77 * 进行图像缩放、输出数据进行减mean、乘scale, 并wc(宽和通道)对接到16。只支持3通道图像数据输入
78 * in 输入数据,uint_8, opencv Mat CV_8UC3
79 * in_width 输入图像宽
80 * in_height 输入图像高
81 * out 输出图像数据 float16
82 * out_width 输出图像宽
83 * out_height 输出图像高
84 * in_format 输入图像格式 参考image_format
85 * out_format 输出图像格式 参考image_format
86 * means 图像数据预处理减均值
87 * scales 图像数据预处理 除std
88 **/
89 void resize_preprocess_std_align(uint8_t* in, int in_width, int in_height, float16* out, int out_width, int out_height,
90 image_format in_format, image_format out_format, float means[], float stds[]);
91
92 /**
93 * 进行图像颜色空间转换,目前支持BGR->RGB RGB->BGR YUV422->BGR YUV->RGB 图像最大分辨率支持1080p
94 * in 输入数据,uint_8, opencv Mat CV_8UC3
95 * in_width 输入图像宽
96 * in_height 输入图像高
97 * out_width 输出图像宽
98 * out_height 输出图像高
99 * in_format 输入图像格式 参考image_format
100 * out_format 输出图像格式 参考image_format
101 *
102 **/
103 void color_transfer(uint8_t* in, int in_width, int in_height, uint8_t* out, image_format in_format, image_format out_format);
104
105 /**
106 * 进行图像缩放及颜色空间转换(目前支持BGR->RGB RGB->BGR YUV422->BGR YUV->RGB) 图像最大分辨率支持1080p
107 * in 输入数据,uint_8, opencv Mat CV_8UC3
108 * in_width 输入图像宽
109 * in_height 输入图像高
110 * out 输出图像数据 float
111 * out_width 输出图像宽
112 * out_height 输出图像高
113 * in_format 输入图像格式 参考image_format
114 * out_format 输出图像格式 参考image_format
115 *
116 **/
117 void resize(uint8_t* in, int in_width, int in_height, float* out, int out_width, int out_height,
118 image_format in_format, image_format out_format);
119
FPGA预处理使用步骤
1、初始化FPGA预处理的输入输出图像格式
1 static paddle_mobile::zynqmp::image_format in_format = paddle_mobile::zynqmp::BGR;
2 static paddle_mobile::zynqmp::image_format out_format = paddle_mobile::zynqmp::BGR;
3
4 std::string format = value["format"];
5 std::transform(format.begin(), format.end(),format.begin(), ::toupper);
6 if (format == "RGB") {
7 out_format = paddle_mobile::zynqmp::RGB;
8 }
2、构建mean/std 或mean‘/scale,这里以mean’/scale为例
1 std::vector<float> mean = value["mean"];
2 float scale = value["scale"];
3
4 means[0] = mean[0];
5 means[1] = mean[1];
6 means[2] = mean[2];
7 scales[0] = scale;
8 scales[1] = scale;
9 scales[2] = scale;
3、构建预处理对象,传入输出的图片格式,mean/std 或mean‘/scale,网络模型输入对象 PaddleTensor。由于FPGA预处理输入数据要求WC(width和channel)乘积是16的倍数,所以我们先计算wc对齐的大小, 再算出wc需要跳跃多少个数mod。image2Tensor调用完成后,预处理的数据填充到PaddleTensor中,以HWC和float16格式存储。
1 int width = mat.cols;
2 int height = mat.rows;
3 int channel = 3;
4 image_shape[0] = height;
5 image_shape[1] = width;
6 // 如果图片的输入大于1080p,我们可以先把图片缩放到网络模型输入的尺寸大小,在进行FPGA预处理。
7 if (width * height > 1920*1080) {
8 float fx = mat.cols / input_width;
9 float fy = mat.rows / input_height;
10 Mat resize_mat;
11 resize(mat, resize_mat, Size(input_width, input_height), fx, fy);
12 mat = resize_mat;
13 height = mat.rows;
14 width = mat.cols;
15 std::cout << "read_image resize" << std::endl;
16 }
17
18 paddle_mobile::zynqmp::ImagePreprocess imagePreprocess;
19
20 int align_size = imagePreprocess.align_size(mat.cols , 3);
21 uchar* img = (uchar *) imagePreprocess.mem_alloc(height, width, in_format);
22
23 int mod = align_size - width * channel;
24 int count = width * channel;
25 for (int i = 0; i < height; i++) {
26 uchar* data = mat.ptr<uchar>(i);
27 uchar* dst = img + i * (width * channel + mod);
28 memcpy(dst, data, count * sizeof(uchar));
29 }
30 // 一步完成图像缩放、颜色空间转换和mean/scale操作
31 imagePreprocess.image2Tensor(input_width, input_height, out_format, means, scales, tensor);
32
CPU预处理使用步骤
FPGA预处理为1.5.0新增功能,以前版本采用CPU预处理
1 auto image = value["image"];
2 Mat img = imread(image);
3 image_shape[0] = img.rows;
4 image_shape[1] = img.cols;
5
6 std::string format = value["format"];
7 std::transform(format.begin(), format.end(),format.begin(), ::toupper);
8
9 input_width = value["input_width"];
10 input_height = value["input_height"];
11 std::vector<float> mean = value["mean"];
12 float scale = value["scale"];
13
14 auto start_time = time();
15 Mat img2;
16 float fx = img.cols / input_width;
17 float fy = img.rows / input_height;
18 resize(img, img2, Size(input_width, input_height), fx, fy);
19
20 Mat sample_float;
21 img2.convertTo(sample_float, CV_32FC3);
22
23 int index = 0;
24 for (int row = 0; row < sample_float.rows; ++row) {
25 float* ptr = (float*)sample_float.ptr(row);
26 for (int col = 0; col < sample_float.cols; col++) {
27 float* uc_pixel = ptr;
28 float b = uc_pixel[0];
29 float g = uc_pixel[1];
30 float r = uc_pixel[2];
31
32 if (format == "RGB") {
33 data[index] = (r - mean[0]) * scale ;
34 data[index + 1] = (g - mean[1]) * scale ;
35 data[index + 2] = (b - mean[2]) * scale ;
36 } else {
37 data[index] = (b - mean[0]) * scale ;
38 data[index + 1] = (g - mean[1]) * scale ;
39 data[index + 2] = (r - mean[2]) * scale ;
40 }
41 ptr += 3;
42 index += 3;
43 }
44 }
45}
预测库接口
预测库接口主要完成模型的初始化、输入参数构造、预测和结果获取。位于include/io/
具体接口
PaddleMobileConfig接口用初始化
CreatePaddlePredictor接口用于构建预测接口PaddlePredictor
PaddlePredictor用于进行预测
PaddleTensor输入输出参数
预测库使用步骤
1、模型初始化,构建预测对象
1 std::unique_ptr<paddle_mobile::PaddlePredictor> g_predictor;
2 PaddleMobileConfig config;
3 std::string model_dir = j["model"];
4 config.precision = PaddleMobileConfig::FP32;
5 config.device = PaddleMobileConfig::kFPGA;
6 config.prog_file = model_dir + "/model";
7 config.param_file = model_dir + "/params";
8 config.thread_num = 4;
9 g_predictor = CreatePaddlePredictor<PaddleMobileConfig,
10 PaddleEngineKind::kPaddleMobile>(config);
2、输入输出参数
1 std::vector<PaddleTensor> paddle_tensor_feeds;
2 PaddleTensor tensor;
3 tensor.shape = std::vector<int>({1, 3, input_height, input_width});
4 tensor.data = PaddleBuf(input, sizeof(input));
5 tensor.dtype = PaddleDType::FLOAT32;
6 paddle_tensor_feeds.push_back(tensor);
7
8 PaddleTensor tensor_imageshape;
9 tensor_imageshape.shape = std::vector<int>({1, 2});
10 tensor_imageshape.data = PaddleBuf(image_shape, 1 * 2 * sizeof(float));
11 tensor_imageshape.dtype = PaddleDType::FLOAT32;
12 paddle_tensor_feeds.push_back(tensor_imageshape);
13
14 PaddleTensor tensor_out;
15 tensor_out.shape = std::vector<int>({});
16 tensor_out.data = PaddleBuf();
17 tensor_out.dtype = PaddleDType::FLOAT32;
18 std::vector<PaddleTensor> outputs(1, tensor_out);
3、预测
1 g_predictor->Run(paddle_tensor_feeds, &outputs);
4、获取结果
1 float *data = static_cast<float *>(outputs[0].data.data());
2 int size = outputs[0].shape[0];
