AIdlux系统是基于ARM架构的跨生态(Android/鸿蒙+Linux)一站式AIOT应用开发平台。实际应用到现场的时候,通常会以几种形态:GPU服务器、嵌入式设 备(比如Android手机、人脸识别闸机等)、边缘设备。GPU服务器等,而Android 嵌入式设备的底层芯片,通常是ARM架构。而Linux底层也是ARM架构,并且Android又是 基于Linux内核开发的操作系统,两者可以共享Linux内核。因此就产生了从底层开发一套应用系统的方式,在此基础上同时带来原生Android和原生Linux使用体验。所以在基于Linux系统和ARM架构上,我们可以在安卓手机上直接下载Aidlux软件,使用安卓手机充当边缘设备,进行代码的调试。
图1
安卓手机打开应用市场搜索AidLux软件并下载,这里需要满足以下的条件:
●Android 版本≥6.0.1(目前只有安卓系统兼容,鸿蒙3.0系统设置需要在AidLux在 Android12/鸿蒙3 服务进程被杀解决方案- AidLux开发者社区查看,大家有任何问题都可以在社区留言的,会有工程师来帮助解决。)
●cpu 支持arm64-v8a架构
●手机存储空间充足
●1.0以上版本需要安装空间>600M
●初始化空间>1.7G
下载完成后–>使用自己的手机号进行注册(图2)–>系统开始初始化–>进入登录界面–>使用cloud_ip中的网址进行映射到电脑网页(注意:安卓手机和电脑要在同一个局域网下,并且注意网站别输错,比如http://192.164.42.42:8000,这里的http后没有s,如果不行的话,换成手机热点连接。)–>输入网站进入电脑端(初始密码为aidlux)–>–>
图2手机端注册
图3手机端页面
VScode 在官网https://code.visualstudio.com/点击download进行下载,官网下载可能速度会很慢,解决办法看这篇文章vscode下载方法,下载完成后,按照提示步骤一直进行完成安装就可以了。
图5 VScode安装
1.安装本地版的python与opencv,点击extensions,进入搜索栏输入python,点击install,等待下载完成即可。
再下载一个Remote-SSH,在后面连接手机端会用到。
图6 本地python的安装
2.安装opencv,在深度学习中,opencv是图像界面的非常重要的软件,我们这里打开软件左上方菜单栏的Terminal终端,点击New Terminal ,然后输入pip install opencv-python -i https://pypi.tuna.Tsinghua.edu.cn/simple进行包的下载。
3.测试
创建一个python文件video_pc.py,在同一个文件夹下放入检测文件,我这里是jiankong.mp4,之后点击RUN->RUN without debugging进行运行,运行正常,页面会出现你的监控文件的画面。
#此代码用于测试本地的环境是否配置完成
#导入库
import cv2
cap = cv2.VideoCapture("jiankong.mp4") #这里输入检测文件
frame_id = 0
while cap.isOpened():
ok, image = cap.read()
if not ok:
print("Camera cap over!")
continue
frame_id += 1
if not int(frame_id) % 5 == 0: continue
image = cv2.resize(image,(900,600))
cv2.imshow("image",image)
cv2.waitKey(5) #调整读帧速度
在第一节中我们完成了基本的手机端与PC端的环境的应用,接下来我们就是使用PC端作为主要的窗口来对Aidlux进行远程的代码编写与调试。
之前已经在本地下载了Remote-SSH,接下来我们点击Remote Explorer,如图7,点击左下角的“Open a Remote Window”(图8),再选择“Open SSH Configuration file”(图9)
图7
图8
图9
针对跳出的弹窗,再选择第一个config(图10)。
图10
##配置config
# Read more about SSH config files: https://linux.die.net/man/5/ssh_config
Host AidLux #服务器别名一般不需要改动
HostName 192.168.43.43 #这是你的cloud_ip地址
Port 9022 #这里将8000改为9022
User root #远程登录的用户名,一般默认即可
保存,之后在左侧框里会生成一个SSH服务器,鼠标放在上面,他的右侧会出现一个文件夹一样的图标,点击它,然后会弹出框,选择Linux,点击选择“Continue”,再输入密码,aidlux,回车。当左下角出现SSH AidLux是表示与手机端连接成功。
图11
![在这里插入图片描述](https://img-blog.csdnimg.cn/ce86757b61ea4bc392a8078495d6a50b.png
图12
到这里,电脑端VScode与手机的Aidlux已经连接好了,下面就是开始执行并实现我们的案例了。
医院出入口的人流量统计可以分为⼈体检测+⼈体追踪+人流统计三个方面进行串联实现。
在本次的案例中,我们使用的是旷视的Crowdhuamn数据集,官网http://www.crowdhuman.org/去下载,Crowdhuman数据集,总共包含三个子数据集:15000张的训练数据集,4370张的验证数据集,5000张的测试数据集。其中训练集和验证集都是有标注信息的,测试集没有标注信息。
图13
1.数据集格式的转换:
在本次的案例中,我们选用了4370张的val数据集来做为训练集,我们知道在不同的代码中进行检测是需要将数据集的格式转换为所选训练模型对应的格式,这里Crowhuman数据集的val数据集的标注为annotation_val.odgt,接下来我们需要进行数据集格式的转换(我们这里先将其转换为VOC格式,在将其转换为txt格式),这里,为了节约时间,我们可以直接关注“”AidLux“”公众号,回复lesson3,获得了lesson3资料包的连接之后进入百度网盘进行下载。下载后如图14
图14
在VScode中点击"File",然后点击“open Folder”,点击下载好的lesson3进入lesson3_codes文件夹,在进入data_prepare_code打开data_code.py文件。
from xml.dom import minidom
import cv2
import os
import json
from PIL import Image
#将这里的路径改为自己的对应文件路径
roadlabels = "E:/360MoveData/Users/26337/Desktop/Lesson3/lesson3_data/Crowdhuman_data/Annotations"
roadimages = "E:/360MoveData/Users/26337/Desktop/Lesson3/lesson3_data/Crowdhuman_data/JPEGImages"
fpath = "E:/360MoveData/Users/26337/Desktop/Lesson3/lesson3_data/Crowdhuman_data/annotation_val.odgt"
........
之后运行,生成一系列的xml文件
图15
在lesson3_data下新建一个文件夹train_data,,在其中再新建一个train和test文件夹,将之前的数据集中的val验证集和Annotations,分别复制到train_data下的train文件夹中分别命名为JPEGImages和Annotations
图16
打开data_prepare_code下的train_data_split.py,我们分阶段运行代码,会在train_data中分别保存了train文件以及test文件,train_txt以及test_txt。如图17
##按照下面的步骤一个阶段一个阶段依次执行
def get_image_txt(opt):
##分阶段运行,不要全部一起运行,不运行时将其与功能的代码注释掉
## 阶段一:对于数据集进行清洗梳理
# 第一步:根据images_label_split中的图像删除多余的xml
print("V1")
compare_image_label_remove_xml(opt.train_data)
# # # 第二步:根据images_label_split中的图像删除多余的image
print("V2")
compare_image_label_remove_image(opt.train_data)
# # 第三步:将各个文件夹中的xml不满足条件的文件删除
print("V3")
remove_not_satisfied_xml(opt.train_data)
# # 第四步:查找xml是否为空,空的话删除xml,也删除对应的image
print("V4")
remove_image_null_xml(opt.train_data,label_list)
# # 第五步:对照image和xml中数据,显示图片看画得框是否正确
show_label(opt.train_data,label_list)
## 阶段二:将数据按照一定比例分成训练和验证集
# 将train和test随机分开,将image和xml分别保存到train和test所在的文件夹中
# 根据前面可以得到xml和image,每个场景下选择10%的数据,作为验证集, 生成train和test两个文件夹
#yolov3_get_train_test_file(opt.train_data,0.2)
## 阶段三:将train和test的xml,转换成txt
# 第一步:将train和test中的xml文件生成txt文件,都放到image_txt文件夹中
#yolov3_get_txt(opt.train_data,label_list)
# # 第二步:将所有的image文件一起移动到image_txt中
#yolov3_move_image(opt.train_data)
# # 第三步:将train/Annotations和test/Annotations的xml自动生成train.txt和test.txt文件,并保存到train_test_txt中
#yolov3_get_train_test_txt(opt.train_data)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
#修改自己数据集所在的文件夹,可以直接找到文件夹复制其文件地址
parser.add_argument('--train_data', type=str, default='E:/360MoveData/Users/26337/Desktop/Lesson3/lesson3_data/train_data', help='data dir')
opt = parser.parse_args()
get_image_txt(opt)
将train_data数据集和yolov5_code包进行打包发送到服务器的云端,对其一些文件的配置进行修改
1.打开yolov5_code包中的person.yaml
```python
```python
# Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..]
path: ./lesson3_data/train_data # dataset root dir
train: image_txt # train images (relative to 'path')
val: image_val_txt # val images (relative to 'path')
#test: test-dev2017.txt
# Classes
nc: 1 # number of classes
names: ['person'] # class names
2.打开yolov5s.yaml
修改其中的类别数量,因为人体就⼀个类别,修改成1
3.打开train.py,并进行修改,我们这里使用情轻量级的yolov5s.pt进行训练进行,需要提前去下载,(yolov5s权重 下载https://github.com/ultralytics/yolov5)修改数据路径,设置epoch为100
def parse_opt(known=False):
parser = argparse.ArgumentParser()
parser.add_argument('--weights', type=str, default=ROOT / 'yolov5s.pt', help='initial weights path')
parser.add_argument('--cfg', type=str, default='models/yolov5s.yaml', help='model.yaml path')
parser.add_argument('--data', type=str, default=ROOT / 'data/person.yaml', help='dataset.yaml path')
parser.add_argument('--hyp', type=str, default=ROOT / 'data/hyps/hyp.scratch-low.yaml', help='hyperparameters path')
parser.add_argument('--epochs', type=int, default=100)
parser.add_argument('--batch-size', type=int, default=16, help='total batch size for all GPUs, -1 for autobatch')
parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='train, val image size (pixels)')
parser.add_argument('--rect', action='store_true', help='rectangular training')
.....
4.输入命令行:python train.py
5.可能会报一些没有库的错,(因为我的已经装好了),可以先输入pip install -r requirements.txt,再运行看看。
实在没有的,去清华镜像寻找https://pypi.tuna.tsinghua.edu.cn/simple
6.运行结束后会在runs/train/exp/weights/best.pt,将它下载下来,放入VScode的lesson3_code中的models文件夹下
由于在Aidlux中主要运⾏的是tflite的⽅式,所以我们需要将pt转化为tflite,打开lesson3_code中的eport.py
#修改如下
def parse_opt():
parser = argparse.ArgumentParser()
parser.add_argument('--data', type=str, default=ROOT / 'data/person.yaml', help='dataset.yaml path')
parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'models/best.pt', help='model.pt path(s)')
parser.add_argument('--imgsz', '--img', '--img-size', nargs='+', type=int, default=[640, 640], help='image (h, w)')
...
输入命令:pip3 install tensorflow -i https://pypi.tuna.Tsinghua.edu.cn/simple,
下载完成后,执行 python export.py,在models⽂件夹下⾯,可以看到⽣成的best-fp16.tflite⽂件。
连接SSH,导入lesson3_code,将models文件夹下的best-fp16.tflite拖到aidlux文件夹中,修改aidlux中的model路径
# Aidlite模型路径
model_path = '/home/lesson3_codes/yolov5_code/aidlux/yolov5n_best-fp16.tflite'
修改视屏读取路径,
# 读取视频进行推理
cap = cvs.VideoCapture("/home/lesson3_codes/yolov5_code/aidlux/jiankong.mp4")
点击RUN,会看到手机上会出现人体检测视屏。
目标追踪算法包括单目标追踪和多目标追踪,多目标追踪主要针对的是多个目标的运动轨迹,而单目标追踪主要 针对的某⼀个目标的运动轨迹。目前用的较多的是多目标追踪算法,多目标追踪算法包括(1)sort多目标算法(2)deepsort多目标算法(3)Bytetrack多目标追踪算法。该实例中我们使用Bytetrack多目标追踪算法,会尽量的减少人物之间的遮挡而带来的目标的丢失。
# 实现目标追踪相关功能函数,tracker函数接口可以在公众号Aidlux里回复lesson4获取
det = [] #给予检测一个空间
# Process predictions
for box in pred[0]: # per image
box[2] += box[0]
box[3] += box[1]
det.append(box) det.append()表示将这个数组写入det中
if len(det):
# Rescale boxes from img_size to im0 size
online_targets = tracker.update(det, [frame.shape[0], frame.shape[1]])
online_tlwhs = []
online_ids = []
online_scores = []
# 取出每个目标的追踪信息
for t in online_targets:
# 目标的检测框信息
tlwh = t.tlwh
# 目标的track_id信息
tid = t.track_id
online_tlwhs.append(tlwh)
online_ids.append(tid)
online_scores.append(t.score)
# 针对目标绘制追踪相关信息
res_img = plot_tracking(res_img, online_tlwhs, online_ids, 0,0)
cvs.imshow(res_img)
由于该监控图像是正对着出入口的,我们以检测目标的头部为验证对象,所以我们在选择点的时候需要考虑到摄像机的视角与角度问题。如图18中所示,我们以检测框的上边中心点为越界识别点。
### 越界单边识别功能实现 ###
# 1.绘制越界监测区域
#下面的坐标代表直线的两端的坐标
line = [[167,541],[1191,539]]
cv2.line(res_img,(167,541),(1191,539),(255,255,0),3)
# 2.计算得到人体下方中心点的位置(人体检测监测点调整),
# (x,y,w,h)->(tlwh[0],tlwh[1],tlwh[2],tlwh[3])
pt = [tlwh[0]+1/2*tlwh[2],tlwh[1]] #越界识别点
# 3. 人体和违规区域的判断(人体状态追踪判断)
track_info = is_passing_line(pt, lines)
if tid not in track_id_status.keys():
track_id_status.update( {tid:[track_info]})
else:
if track_info != track_id_status[tid][-1]:
track_id_status[tid].append(track_info)
# 4. 判断是否有track_id越界,有的话保存成图片
# 当某个track_id的状态,上一帧是-1,但是这一帧是1时,说明越界了
if track_id_status[tid][-1] == 1 and len(track_id_status[tid]) >1:
# 判断上一个状态是否是-1,是否的话说明越界,为了防止继续判别,随机的赋了一个3的值
if track_id_status[tid][-2] == -1:
track_id_status[tid].append(3)
#cv2.imwrite("overstep.jpg",res_img)
count_person +=1 #前面记得count_person初始化
###再判断当前一个状态为1,后一个状态为-1时的情况
if track_id_status[tid][-1] == -1 and len(track_id_status[tid]) >1:
# 判断上一个状态是否是1,是否的话说明越界,为了防止继续判别,随机的赋了一个3的值
if track_id_status[tid][-2] == 1:
track_id_status[tid].append(3)
#cv2.imwrite("overstep.jpg",res_img)
count_person += 1
图20
2.喵提醒
搜索公众号“喵提醒”,使用手机进行注册登录,再点击“提醒”再 新建,之后会有生成一个“喵码”,将其填到下面的id中。
# 越界识别+喵提醒
# 填写对应的喵码
id = 'tP48aP'
# 填写喵提醒中,发送的消息,这里放上前面提到的图片外链
text = "医院出入口人流量统计:"
ts = str(time.time()) # 时间戳
type = 'json' # 返回内容格式
request_url = "http://miaotixing.com/trigger?"
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.67 Safari/537.36 Edg/87.0.664.47'}
result = requests.post(request_url + "id=" + id + "&text=" + text + "&ts=" + ts + "&type=" + type,headers=headers)
运行后出现如下图
左上角标注人数流量统计结果为23(只考虑了-1到1),并通过微信公众号喵提醒进行提示(图21和图23)。
左上角标注人数流量统计结果为28(考虑了-1到1,以及1到-1两个方向的情况,更加的贴合实际),并通过微信公众号喵提醒进行提示(图22和图24)。
图23
# aidlux相关
#下面的utils函数包和track函数包要到公众号“AidLUx”上回复lesson5
from cvs import *
import aidlite_gpu
from utils import detect_postprocess, preprocess_img, draw_detect_res, scale_coords,process_points,is_in_poly,is_passing_line
import cv2
# bytetrack
from track.tracker.byte_tracker import BYTETracker
from track.utils.visualize import plot_tracking
import requests #库的引用
import time
# 加载模型
model_path = '/home/lesson4_codes/aidlux/best-fp16.tflite'
in_shape = [1 * 640 * 640 * 3 * 4]
out_shape = [1 * 25200 * 6 * 4]
# 载入模型
aidlite = aidlite_gpu.aidlite()
# 载入yolov5检测模型
aidlite.ANNModel(model_path, in_shape, out_shape, 4, 0)
#初始化文件
tracker = BYTETracker(frame_rate=30)
track_id_status = {}
cap = cvs.VideoCapture("/home/lesson4_codes/aidlux/jiankong.mp4")
frame_id = 0
count_person = 0
while True:
frame = cap.read()
if frame is None:
print("Camera is over!")
# 填写对应的喵码
id = 'ti184WH'
# 填写喵提醒中,发送的消息,这里放上前面提到的图片外链
text = "医院进出口人流统计:"+str(count_person)
ts = str(time.time()) # 时间戳
type = 'json' # 返回内容格式
request_url = "http://miaotixing.com/trigger?"
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.67 Safari/537.36 Edg/87.0.664.47'}
result = requests.post(request_url + "id=" + id + "&text=" + text + "&ts=" + ts + "&type=" + type,headers=headers)
break
frame_id += 1
if frame_id % 3 != 0:
continue
# 预处理
img = preprocess_img(frame, target_shape=(640, 640), div_num=255, means=None, stds=None)
# 数据转换:因为setTensor_Fp32()需要的是float32类型的数据,所以送入的input的数据需为float32,大多数的开发者都会忘记将图像的数据类型转换为float32
aidlite.setInput_Float32(img, 640, 640)
# 模型推理API
aidlite.invoke()
# 读取返回的结果
pred = aidlite.getOutput_Float32(0)
# 数据维度转换
pred = pred.reshape(1, 25200, 6)[0]
# 模型推理后处理
pred = detect_postprocess(pred, frame.shape, [640, 640, 3], conf_thres=0.4, iou_thres=0.45)
# 绘制推理结果
res_img = draw_detect_res(frame, pred)
# 目标追踪相关功能
det = []
# Process predictions
for box in pred[0]: # per image
box[2] += box[0]
box[3] += box[1]
det.append(box)
if len(det):
# Rescale boxes from img_size to im0 size
online_targets = tracker.update(det, [frame.shape[0], frame.shape[1]])
online_tlwhs = []
online_ids = []
online_scores = []
# 取出每个目标的追踪信息
for t in online_targets:
# 目标的检测框信息
tlwh = t.tlwh
# 目标的track_id信息
tid = t.track_id
online_tlwhs.append(tlwh)
online_ids.append(tid)
online_scores.append(t.score)
# 针对目标绘制追踪相关信息
res_img = plot_tracking(res_img, online_tlwhs, online_ids, 0,0)
#1.绘制统计人流线
lines =[[167,541],[1191,539]]
cv2.line(res_img,(167,541),(1191,539),(255,255,0),3)
# 2.计算得到人体下方中心点的位置(人体检测监测点调整)
pt = [tlwh[0]+1/2*tlwh[2],tlwh[1]]#以人头为识别点
#3人体和违规线的判断(状态追踪)
track_info = is_passing_line(pt, lines)
if tid not in track_id_status.keys():
track_id_status.update( {tid:[track_info]})
else:
if track_info != track_id_status[tid][-1]:
track_id_status[tid].append(track_info)
# 4.判断是否有track_id越界,有的话保存成图片
# 当某个track_id的状态,上一帧是-1,但是这一帧是1时,说明越界了
if track_id_status[tid][-1] == 1 and len(track_id_status[tid]) >1:
# 判断上一个状态是否是-1,是否的话说明越界,为了防止继续判别,随机的赋了一个3的值
if track_id_status[tid][-2] == -1:
track_id_status[tid].append(3)
#cv2.imwrite("overstep.jpg",res_img)
count_person += 1 #之前已经定义count_person=0,不然会报未定义的错
#5.再判断当前一个状态为1,后一个状态为-1时的情况
if track_id_status[tid][-1] == -1 and len(track_id_status[tid]) >1:
# 判断上一个状态是否是1,是否的话说明越界,为了防止继续判别,随机的赋了一个3的值
if track_id_status[tid][-2] == 1:
track_id_status[tid].append(3)
#cv2.imwrite("overstep.jpg",res_img)
count_person += 1
cv2.putText(res_img,"Pereson_count in the gate of Hospital:"+ str(count_person), (50,50), cv2.FONT_HERSHEY_SIMPLEX, 1 ,(255, 0, 255), 3)
cvs.imshow(res_img)
通过本次的案例学习,非常感谢江大白老师的讲解,学会了通过手机端的Aidlux平台来尝试AI智能场景的部署,进一步加深了对深度学习以及分布式AIOT开发的了解,在今后的学习中会继续了解与学习这方面的知识。