安卓系统上的 YOLOv5 目标检测
软硬件环境
- yolov5
- ncnn
- android studio 4.1.2
- oneplus 8
- pytorch 1.6
- onnx
- netron
前言
前面几篇文章,我们已经详细介绍过yolov5
的检测、训练、可视化等内容,本文继续yolov5
的话题,这回我们来看看,如何在android
中去使用yolov5
来进行目标检测?
什么是ncnn
下面这段是官方的定义
ncnn
是腾讯公司开源的一个专为手机端极致优化的高性能神经网络前向计算框架。ncnn
从设计之初,就深刻考虑手机端的部署和使用,无需第三方依赖,跨平台,手机端cpu
的速度快于目前所有已知的开源框架。基于ncnn
,开发者能够将深度学习算法轻松移植到手机端高效执行,开发出人工智能APP
,将AI
带到你的指尖。
目前ncnn
已经支持大部分的CNN
网络,包括本文中用到的yolov5
- Classical CNN: VGG AlexNet GoogleNet Inception ...
- Practical CNN: ResNet DenseNet SENet FPN ...
- Light-weight CNN: SqueezeNet MobileNetV1/V2/V3 ShuffleNetV1/V2 MNasNet ...
- Face Detection: MTCNN RetinaFace ...
- Detection: VGG-SSD MobileNet-SSD SqueezeNet-SSD MobileNetV2-SSDLite MobileNetV3-SSDLite ...
- Detection: Faster-RCNN R-FCN ...
- Detection: YOLOV2 YOLOV3 MobileNet-YOLOV3 YOLOV4 YOLOV5 ...
- Segmentation: FCN PSPNet UNet YOLACT ...
- Pose Estimation: SimplePose ...
项目实操
关于基础环境部分,这里需要用到android
的开发环境,像android studio
、sdk
、ndk
等等,本文不做介绍,有问题的话,可以在留言区中留言。
我们直接拉取yolov5 for android
的源码
git clone https://github.com/nihui/ncnn-android-yolov5
然后来到ncnn
的版本发布页,下载编译好的包 github.com/Tencent/ncn…,如果你有兴趣的话,也可以通过ndk
自己去编译
下载解压后拷贝到ncnn-android-yolov5
项目的app/src/main/jni
目录下,目录结构是这样的
然后修改同级目录下的CMakeLists.txt
,将其中的ncnn_DIR
变量值修改成
set(ncnn_DIR ${CMAKE_SOURCE_DIR}/${ANDROID_ABI}/lib/cmake/ncnn)
保存后就可以进行项目的编译了。
这里使用真机进行测试,需要自己打开手机的开发者模式,允许USB
调试,APP
安装后打开,首页是这样的
界面布局非常简单,总共就三个按钮,一个选图,一个使用CPU
检测,一个使用GPU
检测。经过测试发现CPU
的速度要比GPU
慢上一倍,我的OnePlus 8
的GPU
速度也只有5fps
。
如何使用自己的模型
当我们训练了自己的检测模型后,就需要一种中介,通过它,可以实现在不同框架之间进行转换。 Open Neural Network Exchange
简称ONNX
,意思是开放神经网络交换格式,它就是我们需要的中介。
yolov5
的模型训练请参考这篇 xugaoxiang.com/2020/07/02/…,作为测试,我们也使用上文中训练出来的口罩检测模型
安装依赖库
pip install onnx coremltools onnx-simplifier
执行命令
python models/export.py --weights runs/exp2/weights/best.pt
同时在best.pt
的同级目录,还生成了best.onnx
、best.mlmodel
和best.torchscript.pt
这里需要提醒一下大家,上述的导出操作在pytorch1.7
和yolov5 v4.0
版本上会报错,我这里的环境是pytorch1.6
、yolov5 3.0
版本。报错信息如下
Converting op 143 : listconstruct
Adding op '143' of type const
Converting op 144 : listconstruct
Adding op '144' of type const
Converting op 145 : listconstruct
Adding op '145' of type const
Converting op x.2 : _convolution
Converting Frontend ==> MIL Ops: 3%|██ | 21/620 [00:00<00:00, 1350.49 ops/s]
CoreML export failure: unexpected number of inputs for node x.2 (_convolution): 13
Export complete (12.83s). Visualize with https://github.com/lutzroeder/netron.
这是coremltools
的一个bug
。相关链接请查看 github.com/ultralytics…
接下来使用工具onnx-simplifier
来简化onnx
,执行命令
python -m onnxsim runs/exp2/weights/best.onnx runs/exp2/weights/best-sim.onnx
下面开始编译ncnn
,首先准备基础环境
sudo apt install build-essential libopencv-dev cmake
编译安装protobuf
依赖库
git clone https://github.com/protocolbuffers/protobuf.git
cd protobuf
git submodule update --init --recursive
./autogen.sh
./configure
make
make install
sudo ldconfig
编译安装好以后,可以查看下protobuf
的版本号
接下来,需要编译ncnn
,目的是生成onnx
转ncnn
的命令行工具
git clone https://github.com/Tencent/ncnn.git
cd ncnn
git submodule update --init
mkdir build
cd build
cmake ..
make -j8
make install
编译安装完成后,就可以使用onnx2ncnn
工具进行转换了
cd tools/onnx
./onnx2ncnn ~/Works/weights/best-sim.onnx ~/Works/weights/model.param ~/Works/weights/model.bin
oh, no
,报错了
这是由于slice
没有被支持。为了解决这个问题,我们需要编辑生成的param
文件,使用文本工具打开即可
修改后的param
是这样的
第二行的第一个数是层数,因为我们删除了8个Crop
和1个Concat
,所以它的值是201-9=192
另外,需要修改的是Reshape
层的输出grid
,将对应的值都改成-1,这是为了解决实际中出现的多检测框的问题
可以用netron
这个工具打开查看网络结构,windows
、linux
、macos
上都有,地址 github.com/lutzroeder/…
图片中,我们要删除Split
、Concat
和8个Crop
节点,并且加入新的节点YoloV5Focus
,这个节点名称是和android
源码中的yolov5ncnn_jni.cpp
中的类名匹配的。这里可以将文本编辑器和netron
结合起来用,修改完后立刻查看。
接下来就可以替换原android
工程中assets
文件夹下的yolov5s.param
和yolov5s.bin
然后接着修改源码文件yolov5ncnn_jni.cpp
,修改2个Permute
节点的output
最后,修改class names
重新编译工程,连上手机,安装apk
并运行
最后的检测效果如下
FAQ
这里列出了几个常见问题,供大家参考。
Could not install Gradle distribution from 'https://services.gradle.org/distributions/gradle-5.4.1-all.zip'.
关闭android studio
,手动从站点 services.gradle.org/distributio… 下载压缩包,然后进入文件夹C:\Users\Administrator.gradle\wrapper\dists\gradle-5.4.1-all\3221gyojl5jsh0helicew7rwx
,将原有的内容全部删除,将下载的压缩包拷贝进来,再次打开android studio
,点击右上角的Sync Project with Gradle Files
Cause: jcenter.bintray.com:443 failed to respond
这个问题可能跟代理相关,在File
--> Settings
--> HTTP Proxy
,关闭代理
或者编辑文件~.gradle\gradle.properties
,将proxy
相关的语句注释掉
另一个错误,是在编译ncnn
的时候,出现tiff
相关的错误信息
这里主要是anaconda
的环境导致,我的做法是完全退出anaconda
环境
conda deactivate
unset LD_LIBRARY_PATH
最后一个问题,模型转换经常碰到的错误
这个错误是yolov5ncnn_jni.cpp
中的output
没有和实际模型匹配起来导致的
源码下载
百度网盘链接:pan.baidu.com/s/1U4XfNSeM…
提取码:x8oi
参考资料
- 官方github
- 4.0更新了啥?
- 如何训练模型
- ncnn
- 模型训练可视化
- Android studio gradle构建失败的解决方法
- github.com/daquexian/o…
- github.com/protocolbuf…
- github.com/Tencent/ncn…
推荐阅读
-
事实上,安卓系统本来就是为数码相机设计的!
-
抖音的新版抓包程序,绕过sslpinning直接修改所以抓取https数据包--一般需要抓取https数据包,只需要在电脑上安装抓包工具如fiddler、charles。然后在手机上安装代理,保证手机和电脑在同一个网络上,再在手机上安装证书抓包工具,基本上就可以抓https包了。(安卓版本控制在6.0想兼容,高于6.0就不能抓https数据包了,因为谷歌在安卓N(24)及以上版本中改变了安全行为,系统默认不再信任用户app或系统自定义添加的证书)。
-
如何辨别火奴鲁鲁系统上运行的安卓应用程序
-
安卓系统上的高刷新率渲染
-
在安卓系统中读取 NFC 标签卡上的 ID
-
Android 开发中 nodpi、xhdpi、hdpi、mdpi、ldpi 的概念 - 术语和概念 屏幕尺寸 屏幕的物理尺寸,基于屏幕的对角线长度(如 2.8 英寸、3.5 英寸)。 简而言之,安卓系统将所有屏幕尺寸简化为三大类:大、普通和小。 程序可以为这三种屏幕尺寸提供三种不同的布局选项,然后系统会以合适的方式将布局选项呈现到相应的屏幕上,这个过程不需要程序员用代码进行干预。 屏幕纵横比 屏幕的物理长度与物理宽度之比。程序只需使用系统提供的资源分类器 long(长)和 notlong(不长),就能为具有特定长宽比的屏幕提供配制材料。 分辨率 屏幕的像素总数。请注意,分辨率并不意味着长宽比,尽管在大多数情况下,分辨率表示为 "宽度 x 长度"。在安卓系统中,程序一般不直接处理分辨率。 密度 根据屏幕分辨率,沿屏幕宽度和长度排列的像素数量。 密度较低的屏幕在长度和宽度方向上的像素都相对较少,而密度较高的屏幕通常会在同一区域内排列很多甚至非常非常多的像素。屏幕的密度非常重要;例如,一个界面元素(如按钮)的长度和宽度以像素为单位,在低密度屏幕上会显得很大,但在高密度屏幕上就会显得很小。 独立于密度的像素(DIP)是指程序用来定义界面元素的抽象意义上的像素。它作为一个与实际密度无关的单位,帮助程序员构建布局方案(界面元素的宽度、高度和位置)。 与密度无关的像素在逻辑上与像素密度为 160 DPI 的屏幕上的像素大小相同,而 160 DPI 是安卓平台默认的显示设备。在运行时,平台会以目标屏幕的密度为基准,"透明 "地处理所有所需的 DIP 缩放操作。要将与密度无关的像素转换为屏幕像素,可以使用一个简单的公式:像素 = DIP * (密度 / 160)。例如,在 240 DPI 的屏幕上,1 个 DIP 等于 1.5 个物理像素。强烈建议使用 DIP 来定义程序界面的布局,因为这样可以确保用户界面在所有分辨率的屏幕上都能正常显示。 为了简化程序员在面对各种分辨率时的麻烦,也为了让各种分辨率的平台都能直接运行这些程序,Android 平台将所有屏幕以密度和分辨率作为分类方式,分别分为三类:- 三大尺寸:大、普通、小;- 三种不同密度:高(hdpi)、中(mdpi)和低(ldpi)。DPI 表示 "每英寸点数",即每英寸的像素数。如果需要,程序可以为不同的屏幕尺寸提供不同的资源(主要是布局),为不同的屏幕密度提供不同的资源(主要是位图)。除此之外,程序无需对屏幕尺寸或密度进行任何额外处理。执行时,平台会根据屏幕本身的尺寸和密度特性自动加载相应的资源,并将其从逻辑像素(DIP,用于定义界面布局)转换为屏幕上的物理像素。
-
安卓系统上的 YOLOv5 目标检测
-
基于 YOLOv8/YOLOv7/YOLOv6/YOLOv5 的体育赛事目标检测系统(Python+PySide6 接口+培训代码)-5。体育赛事目标检测系统实现
-
如何在Windows 11上安装并运用Android子系统来运行安卓应用的简易指南
-
安卓子系统在华为 MateBook E Go 上的安装指南