15

前沿科技探索家 · 2021年12月09日

如何基于Flutter和Paddle Lite实现实时目标检测

80.jpg
很早之前接触到了飞桨(PaddlePaddle)以及PaddleDetection工具,被他们的简单易用吸引,同时,这些工具极大降低了训练模型的门槛并减少了所需时间,非常适合新手入门。在很多实际应用场景也有不俗的表现。

在端侧部署方面,Paddle Lite是飞桨产品栈中用于端侧高性能轻量化AI应用部署的推理引擎,给了移动端等场景更多可能。这款引擎允许我们在很多硬件平台上实现轻量化的高效预测,进行一次预测耗时较短,也不需要太多的计算资源。

那么如果我们想开发一款既能在本地进行预测又能在Android和iOS上面有一致体验的App的话,Flutter无疑是一个好选择。其作为开源移动UI框架已然成为跨平台移动开发一大趋势,在开发时可以保留状态进行热重载,内置许多令人眼前一亮的组件和漂亮的动画,同时还能保证性能达到和原生应用一样。也正因为这样,不少公司开始把自己的应用向Flutter迁移,有许多我们耳熟能详的App其实已经是基于Flutter开发。假如你已经对安卓原生开发十分熟悉的话,不妨去试试。

这次我们就基于Flutter来开发一个实时目标检测程序,这也得益于Flutter支持访问iOS和Android上的原生系统功能和系统SDK。

我们项目的GitHub地址:

https://github.com/KernelErr/...

其中内置了水果识别模型,下载下来就能直接编译体验。约定:

Flutter端:Flutter项目主目录。
Android端:项目的Android子目录,原生安卓。

开发环境

我们在开发的时候环境如下:

Flutter version 1.12.13+hotfix.8
Dart version 2.7.0
Android Studio (version 3.6)
Android toolchain - develop for Android devices (Android SDK version 29.0.3)
Flutter在更新的同时加入了越来越多新的特性,网上一些基于老版本的实现方法已经不太实用,我们需要进行一些修改。

准备模型

Paddle Lite需要通过opt工具生成其支持的轻量化模型,如果你手上已经有PaddleDetection训练出来的模型,那么你需要先在PaddleDetection导出模型,然后通过opt工具进行转换。
81.jpg
如果你有其他框架训练出来的模型,如caffe、tensorflow、onnx等,可以利用X2Paddle来转换。

假设我们已经得到了两个文件:

model.nb - 基于Yolov3 Tiny训练且已经通过opt优化好的模型
label - 模型预测一一对应的标签

如何在Flutter中支持Paddle Lite?

我们只需要通过Android Studio创建一个新的Flutter项目,这里我们假设名字是realtime_od。

准备Paddle Lite的预测库和模型文件

由于我们使用的是安卓原生代码,所以我们需要在Android端进行开发,而不是Flutter端。我们在Paddle Lite提供的预编译预测库里面下载需要的预编译库,放到Android端的相应文件夹内,和原生安卓的目录类似。之后我们继续在android文件夹内放置模型文件,在realtime_od/android/app/src/main/下面新建assets文件夹,并分别把模型和标签放到models和labels子文件夹内。这时候你的目录结果应该是这样:
82.png
我们使用口罩模型作为样例,模型位置是:models/mask/model.nb,标签位置是:labels/mask_label_list。因此你需要在MainActivity里面赋值:
83.png
禁用压缩

在生成APK的时候,我们的模型会被压缩,所以我们需要修改build.gradle配置文件来禁用assets文件夹的压缩。
84.png
提供原生安卓支持

如果为了Flutter的支持,给Paddle Lite专门写一套Dart调用代码是工作巨大的,所以我们不妨直接基于官方的Demo进行修改。在Android端,我们直接使用了官方Demo中的代码,并在MainActivity内注册了Channel。
85.jpg
由于Flutter中加入了进程安全机制,我们使用了一个MethodResultWrapper保证在主进程里面返回result。新版Flutter中你需要使用configureFlutterEngine而不是onCreate来注册组件。

使用实时影像

让我们来给Flutter提供来自摄像头的实时影像!添加一下Flutter的camera插件,Dart 已经有很多现成的包给我们使用:
86.png
同时需要确保项目的最低Android SDK版本在21以上。在官方提供的Demo中,图片输入使用的是Bitmap图片,但是我们从插件得到的格式是android.graphics.ImageFormat.YUV_420_888,在Predictor类的最下面我们进行了相应的转换,转换代码的使用已经联系原作者获得授权。我们在其中使用了RenderScript进行高效计算,避免延迟过高。

显示实时图像并标注

大量的工作都花在了Android端上面,下面让我们来Flutter端做些工作。

在main.dart和object_detector.dart里面你可以发现我们调用Android端提供的方法,即loadModel以及detectObject。同时在DrawObjects类里面提供了标注目标的功能,代码相对比较简单,利用得到的预测结果进行画图。

Let’s run it!

这里使用的是群友提供的口罩模型,label文件里面只有两行,分别是戴口罩和未带口罩。我们在Android 9设备上面用PaddlePaddle官方示例图片测试一下。
87.jpg
从日志上面可以看出Paddle Lite预测的时间是接近700 ms。
88.png
更改模型和优化方案

如何使用其他模型

我们是参考群友的解决方案(参考链接里面给出)适配的YOLO v3,主要的修改在Predictor内的模型输入以及MainActivity的初始化。因为官方使用的是其他模型,输入的Shape和我们不一样,我们的是320。

如果你需要使用其他模型,请同步修改输入处的:
89.png
以及输出处的:
90.png
标注函数处也需要做相应修改,修改main.dart:
91.png
怎么更快

实际上我们的模型还不够快,选择合适的模型,可以把预测时间缩短到更短。具体还是看自己的需要,Paddle Lite支持许多主流的模型,大家可以进行选用。
Trouble Shooting
记录的问题包括Flutter开发过程中遇到的和Paddle Lite使用中遇到的:

  1. Methods marked with @UiThread must be executed on the main thread.

这是因为Flutter引入了进程安全,不能直接在子进程里面返回result,需要在主进程里面返回,网上现在有很多解决办法,我们的也是来自GitHub。

  1. 错误: 不兼容的类型: MainActivity无法转换为FlutterEngine

很可能你看的教程是旧版本,请直接参考官方文档写原生安卓。我们在原生安卓开发的时候指定了v2。

  1. Paddle Lite出现库错误

一开始以为是官方的问题,但是自己手动编译一次库就能解决。我已经内置了arm64的无问题的库。

  1. 其他问题

官方文档 -> GitHub -> 搜索引擎 -> Paddle Lite官方QQ群(696965088),一般都能解决。:)

参考链接
Paddle Lite Github地址:https://github.com/PaddlePadd...

Paddle Lite中文文档:https://paddle-lite.readthedo...

Paddle Lite 安卓端部署:https://www.ralphlu.top/artic...

Real-Time Object Detection with Flutter, TensorFlow Lite and Yolo -Part 1:https://blog.francium.tech/re...

Writing custom platform-specific code:https://flutter.dev/docs/deve...

PaddleDetection地址:https://github.com/PaddlePadd...

飞桨官网地址:https://www.paddlepaddle.org.cn

飞桨开源框架项目地址:

GitHub: https://github.com/PaddlePadd...

Gitee:https://gitee.com/paddlepaddle/

推荐阅读
关注数
12971
内容数
325
带你捕获最前沿的科技信息,了解最新鲜的科技资讯
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息