软件杯经过了几个月的竞赛和答辩过后,总算是获得了一个相对比较满意的成绩。
我们组的名字叫P5天下第一,回过头看这个名字实在是有种说不出的感觉(索尼罪大恶极),我的P5都还在PS4里吃灰,结果后面直接上了XGP,还是P5R,只能说《Only On PlayStation For A While》。
回到正题。首先还是来讲讲数据库和后端的方案吧。
下面是整体的架构图设计
Pest-Identification-Provider
数据库其实很简单,就是一个用户表,还有害虫的目科属种的信息表,以及关联表。
后端采用spring cloud + nacos的方案。分为provider和consumer,然后通过spring gateway网关进行负载均衡。
YoloV4图像识别模块也通过gunicorn实现了负载均衡。
用户登录后台采用的是jwtToken + Spring security实现权限校验。
1 | package com.rjgc.configs; |
在spring security中添加了两个过滤器,一个Token登录过滤器,一个Token认证过滤器。
1 | package com.rjgc.filters; |
TokenLoginFilter中有一个JwtTokenUtils,当尝试登录时,将会先调用attemptAuthentication函数,对比账号和密码后将会调用successfulAuthentication函数根据用户名生成一个token,然后返回到前端。
密码采用默认的BCryptPasswordEncoder进行加密。
1 |
|
数据库采用的是MySQL + mybatis plus。
整体就是采用MVC架构,在controller中定义接口,然后在service中进行处理。
1 | package com.rjgc.controller; |
在这里定义了一个统一的返回值ResBody,这样在前端处理会更方便,并且不需要处理null值的问题。
1 | package com.rjgc.exceptions; |
项目中还使用了全局异常处理中心来对不同的异常进行处理
1 | package com.rjgc.exceptions; |
以上基本上是provider的设计方案。
Pest-Identification-Consumer
接下来在consumer端,其实就是对provider的进一步封装。通过OpenFegin来进行远程调用。
1 |
|
Pest-Identification-Gateway
网关这里其实Spring已经给出了很方便的解决方案。只需要在配置文件中配好负载均衡,在nacos就可以实现。
1 | server: |
YoloV4网络
这次竞赛有一个很大的难题,也就是图像识别的问题。这里我采用的是YoloV4框架来进行目标检测。由于这次竞赛还需要实现离线识别,因此在安卓客户端使用了YoloV5框架来实现断网情况下的识别。
首先说说YoloV4框架,在这次竞赛中,我使用了flask框架来对外提供识别api。
1 |
|
YoloV4框架采用pytorch实现。这里先贴一张YoloV4的架构图。图片来自 睿智的目标检测32——TF2搭建YoloV4目标检测平台(tensorflow2)_Bubbliiiing的博客-CSDN博客
这位Bubbliiiing真的让我学到了很多,他在B站也有关于YoloV4的教程,看了他的视频,我觉得受益匪浅。Bubbliiiing的个人空间_哔哩哔哩_bilibili
具体的介绍可以参考这里
YOLOV4 pytorch实现流程 - 知乎 (zhihu.com)
首先是实现CSPdarknet,定义MISH激活函数,以及实现基本的卷积操作,最后再实现一个完整的CSPdarknet。
这里不得不说pytorch实在是太方便了,只要继承nn.Module,然后写forward就可以了。之前TensorFlow折腾了好久,不同的backend,不同的版本居然都不兼容,坑太多了。
1 | import math |
然后再实现yolov4的框架,包括上图中的SPP和PANet,最后输出三个特征层Yolo head。
1 | from collections import OrderedDict |
搭建完成之后就是训练了。
训练采用的是实验室的TITAN RTX,这里我们小组总共找了将近1900张图片,然后手动打标签,不得不说那一周看虫子都快看吐了。
最后通过脚本扫描所有的图片,将对应的xml标记文件对应。
然后开始训练
1 | def start_train(queue=None): |
最后训练出来的效果还是很不错的。
YoloV5网络
前面说到了由于YoloV4过于庞大,无法放到安卓app中,于是我们小组还开发了YoloV5的版本。
模型也是使用pytorch实现。这里就不再赘述。
训练过程基本和上面差不多,使用相同的训练集,训练完成后获取模型即可。
比较值得记录的是如何放到安卓app上。
Android APP
安卓客户端基础功能采用vue-cli开发,制作为h5小程序,由于pytorch在安卓端必须采用Android studio引入,所以不能直接使用vue打包成apk。
因此我们小组采用capacitorJS将vue app项目转换成原生代码项目,再使用pytorch原生库加载离线识别模型文件,使用NanoHTTPD实现在本地模拟在线api,采用sqlite和okhttpClient定期同步远程数据库。
在安卓客户端拍图片之后,将会先被编码为base64,然后再上传至YoloV4网络,获取结果之后再显示。
在build.gradle中引入pytorch
1 | dependencies { |
然后把训练好的YoloV5模型放入assets文件夹中,在app打开后进行加载。
1 | /** |
然后实现predict函数
1 | /** |
以及在识别后的图片上画框的函数
1 | /** |
以及nms函数,和非极大抑制函数,计算IOU的函数
1 | /** |
然后将这个离线识别方法封装成API。
采用NanoHTTPD对外提供接口。这样在无网络的环境下只需要把服务器的ip地址更改为127.0.0.1,即可请求到本地的YoloV5识别网络,并实现离线识别。
最后放几张图片