本科毕设做的,记录一下

1:功能分析

行人检测系统通过移植在PC端训练的神经网络模型,在移动平台实现行人检测功能。用户登录系统后可进行本地图像识别以及摄像头实时检测,识别的同时并且需要标记出画面中行人具体位置,提供检测结果保存本地的功能,方便日后查看。本节针对系统进行需求分析,下图显示了系统的用户用例图。

系统提供2种方式进行检测,用户可选择本地图片进行检测,检测并标记画面中行人位置,并且提供检测图片保存本地功能。也可选择采用摄像头进行实时检测,检测并标记画面中行人位置,提供行人计数功能,要体现出实时性。

2:总体设计

界面设计:

针对功能模块设计系统界面原型图,后续系统实现根据此原型图基础上进行。如图所示,系统主界面原型图,具体分为三块,主界面1,主界面2,主界面3。每个界面分别为检测模块入口,文件管理模块入口,设置模块入口。

图1与图2分别为检测模块与文件管理模块的设计原型图。检测模块分为两类,分别为图片检测以及摄像头实时检测,在检测中,提供检测模型切换功能,以及CPU/GPU切换功能,保证更好的检测效果,图片检测可以将检测结果保存下来,方便查看。在摄像头检测中,不仅可以切换模型,还提供更多样的交互体验,例如转换前后摄像头,设置NMS值,设置置信度等等。

在文件管理界面,是一个图片列表,上下滑动可以实现本地图片浏览功能,每一层显示图片以及图片的相应信息。

检测界面设计:

3:基于nanodet行人检测模型建立

要想实现最终的检测任务,离不开一个好的检测模型,考虑到要部署在移动端,就要对模型提出几点要求:

(1)模型必须轻量级

由于手机端计算能力有限,对模型的Flops要求要低,以满足实时检测要求。

(2)模型精度要能满足要求

最终的检测结果要能满足大部分场景需求。

(3)模型容易部署

得到最终的模型要能转化到移动端运行。

在此基础上,选择nanodet检测模型进行训练,经过模型转化后在手机端用ncnn部署模型。

nanodet架构图:

ncnn简介:

NCNN是腾讯优图实验室第一个开源项目,是一个为手机端极致优化的高性能神经网络前向计算框架。其在2017年7月正式开源。NCNN作为腾讯优图最“火”的开源项目之一,是一个高性能神经网络前向计算框架,在设计之初便将手机端的特殊场景融入核心理念,是业界首个为移动端优化的开源神经网络推断库。能实现无第三方依赖,跨平台操作,在手机端CPU运算速度在开源框架中处于领先水平。基于该平台,开发者能够轻松将深度学习算法移植到手机端,输出高效的执行,进而产出人工智能APP,将AI技术带到用户指尖。

目前为止,NCNN已经在腾讯的多款应用中落地使用,如 QQ,微信,天天P图等。

模型训练过程省略。。。。。。

模型转换

经过训练最终得到nanodet.ckpt文件,但是这种格式在手机上是无法识别的,所以我们要对模型进行转化。 ckpt->onnx->ncnn

得到.bin和.param文件。这样就得到了最终能部署到手机的模型文件.

4:系统实现

主要讲一下怎么在安卓平台部署模型

该模块为整个系统核心模块,在前面已经得到了训练好的模型文件.ckpt并转化为了.bin和.param,现在需要编写整个神经网络在移动端的后处理模块,给网络一个图片输入,经过计算后得到输出结果,在这个输出的基础上得到最后想要的目标。

首先,要实现检测功能,需要知道网络的输出是什么,表示的含义是什么,原图经过预处理之后形成一个固定大小的图片作为nanodet网络的输入,经过forward前向计算后会得到1/8,1/16,1/32这三种尺度的特征图向量,每个分支分为类别置信度和检测框偏移量,例如一张320*320的图片输入后,经过网络计算得到6个输出矩阵,分别为40*40的特征图得到的结果(1600,1)和(1600,32),20*20的特征图得到的结果(400,1)和(400,32),10*10的特征图得到的结果(100,1)和(100,32)。每个分支的第一个结果矩阵表示该特征图尺寸下每个像素点在待预测类别里的每个类的置信度,例如(1600,1)表示在40*40这个尺寸上每个像素点在行人这1个类别上的置信度,而第二个结果则表示每个像素点的检测框的预测偏移量,例如(1600,32)表示40*40这1600个像素点上每个像素点预测边框的偏移量有4个,每个长度为8,因此为32。

知道了输入输出的含义后,进行神经网络移植手机端的后处理模块,这部分代码使用C++完成,主要分为detect检测模块和draw画框模块。

detect模块检测

流程图如下图所示

在检测模块中,目的在于输入一张图片得到检测结果,因此整体流程按照上图所示。输入一张图片,首先进行预处理,将图片调整到先前训练的模型输入尺寸大小,按照长边等比例放缩,然后边缘进行填充,紧接着对图片进行归一化处理,接着按照ncnn框架流程进行,调用load_model()方法加载之前生成的.bin文件,调用load_param()方法加载.parrm文件,再确定输入输出网络的名称,也就是前文提到的input,1以及cls_pred_stride,即可得到网络推理结果向量。将输出向量结果转化为自己设定的结构体保存,包括预测框四个坐标位置,标签以及置信度。将得到的结构体数组进行NMS(非极大值抑制)处理,去除重复框。最终得到结果

draw模块

得到图片预测框信息后,紧接着就是输出这些信息,这些在draw模块实现,画框采用OpenCV-mobile实现,输入原始图片和detect生成的预测框信息,采用cv::rectangle()方法画出框,用cv::puText()方法输出类别和置信度。

本地图片

现在得到了检测结果,按照项目需求需要进行本地图片检测,以及手机摄像头实时检测。首先针对本地图片检测,整体流程图如下图

摄像头采集画面

本地检测图片好解决,现在的问题是由于检测算法都在C++中进行,要在java端调用图片,然后传入C++中,得到结果再传回去,如果只是检测单张图片,可能耗时还能接受,但是使用摄像头的话,每一帧通过JNI传入处理则会消耗过多时间,导致帧数降低,影响检测体验。因此放弃使用java层的Camera,转用NDK camera,下图展示了使用NDK camera的流程。

NDK camera使用相对比较复杂,首先需要在java层创建一个SurfaceView展示界面,使用getHolder().addCallback(this)回调函数,在创建,销毁改变时触发相应回调,可用于改变前后摄像头。在C++层创建ANativeWindow用作画布,在得到画面后,通过JNI将画面输送到java层中的容器SurfaceView中,因此C++层要做的就是初始化和设置相机,创建 AImageReader 做预览回调,得到相机预览画面帧,转换格式为RGB,再调用之前的检测模块和画框模块,将处理后的画面输送到ANativeWindow buffer缓冲中,不断重复这个过程,请求图像并处理,从而实现实时检测。

采用Native Camera相较于Camera2传统实现流程,主要有以下优势,每帧的处理循环完全用 C++ 实现,从而有效避免JNI与java api的数据传输造成的消耗,使用ncnn优化的yuv420sp旋转,转RGB函数实现,更高效,使用opencv-mobile画框画字,更高效,ANativeWindow buffer 到屏幕的缩放由硬件完成。

从而配合这样高效的android应用层实现,将nanodet网络的轻量级优势更好的体现出来。

最终实现的检测效果:

文件管理界面

总结

本文以实现移动平台的行人检测系统为课题,通过研究行人检测任务中常用的方法以及结合移动平台算力的限制,得到本文行人检测问题的思路,选取了nanodet轻量目标检测算法进行模型训练,再通过端侧神经网络前向推理工具ncnn移植到移动端。最终设计并实现了行人检测系统。