基于yolov5和AIdLux的人流统计代码实现

        AIdlux主打的是基于 ARM 架构的跨生态(Android/鸿蒙 +Linux )一站式 AIOT应用开发平台。
用比较简单的方式理解,我们平时编写训练模型,测试模型的时候,常用的是 Linux/window系统。而实际应用到现场的时候,通常会以几种形态: GPU 服务器、嵌入式设 备(比如Android 手机、人脸识别闸机等)、边缘设备。 GPU 服务器我们好理解,而 Android 嵌入式设备的底层芯片,通常是ARM 架构。而 Linux 底层也是 ARM 架构,并且 Android 又是 基于Linux 内核开发的操作系统,两者可以共享 Linux 内核。因此就产生了从底层开发一套应 用系统的方式,在此基础上同时带来原生Android 和原生 Linux 使用体验。
基于yolov5和AIdLux的人流统计代码实现_第1张图片
基于 ARM 芯片,开发了 Aidlux 平台,可以在安卓手机上直接下载 Aidlux 使用。
目前使用 Aidlux 主要有两种方式:
(1)边缘设备的方式:阿加犀用高通芯片的 S855 ,和 S865 制作了两款边缘设备,一款提供
7T 算力,一款提供 15T 算力。
(2)手机设备的方式:没有边缘设备的情况下,也可以使用手机版本的 Aidlux ,尝试边缘设
备的所有功能。
并且目前 Aidlux 已对基本市面上所有的芯片都进行了适配,在手机上运行算法模型,也可以体
验优化的效果。
        当然在使用过程中,有个共同点,即手机设备和边缘设备采用的Aidlux 软件,都是一样的。
因此可以先尝试手机设备的方式,在后期需要更多算力的时候,使用边缘设备,就可以无缝衔
接。所以我们先下载一下手机 Aidlux APP 软件。打开安卓手机的应用商城,搜索 Aidlux 即可
下载安装 基于yolov5和AIdLux的人流统计代码实现_第2张图片

 本次项目主要⽤到⼈体检测+⼈体追踪+业务功能判断。

1.人体检测
        因为需要⼈体检测的模型,所以需要先训练⼀个检测模型,并转换成Aidlux可以部署的⽅ 式,进⾏推理测试。
        a.数据集处理
        ⼈体检测的数据集有很多,这⾥主要采⽤旷视开源的Crowdhuman的数据集。根据官网提示后,下载的数据如下所示
基于yolov5和AIdLux的人流统计代码实现_第3张图片

 由于下载后的标注文件为odgt格式,所以需要将标注⽂件odgt格式转换成xml格式,需要注意的是Crowdhuman中,有三种标注内容,vbox、fbox、hbox,分别对应:可看到的⼈体,完整 ⼈体,⼈脸。 本次训练过程中主要使⽤完整⼈体进⾏训练,因此主要⽤到fbox的标签基于yolov5和AIdLux的人流统计代码实现_第4张图片

代码运行后可以得到VOC格式的xml⽂件。

        因为本次主要采⽤Yolov5 的算法,因此我们还要将上⾯VOC格式转换成Yolov 5 可以训练的格式。还需要对 数据进行清理,以及训练集和验证集的切分,⼤家按照平时也训练Yolo 算法的⽅式来操作即可。
基于yolov5和AIdLux的人流统计代码实现_第5张图片
b. 训练⼈体检测模型

     新建person.yaml :因为训练的是⼈体检测模型,所以在yolov5_code/data⽂件夹中,新增⼀个person.yaml。不过需要注意的是,训练集和验证集的路径都要修改⼀下,此外还有类别数,以及类别标签。

基于yolov5和AIdLux的人流统计代码实现_第6张图片
        修改train.py参数 :⽽yolov5_code/train.py⽂件中,主要修改models初始化模型的路径,这⾥使⽤的yolov 5 n的模型 权重。cfg即模型对应的⽹络结构路径,data是新增的person.yaml路径。此外还有epochs训练迭代的次数,batch-size⼤⼩,当然imgsz也可以修改,这⾥默认640
基于yolov5和AIdLux的人流统计代码实现_第7张图片

        修改models/yolov5n.yaml :修改其中的类别数量,因为⼈体就⼀个类别,修改成1

        训练⼈体检测模型:因为训练的时候,需要⼀系列的库⽂件,根据提示安装正确的库后,既可以执行 python train.py进行训练。

基于yolov5和AIdLux的人流统计代码实现_第8张图片

 PC端模型测试:训练过程中,⼀般会得到两个模型,⼀个best.pt,即epoch迭代的过程中,map精度对⽐⽐较好保存的 模型。⼀个是last.pt,即迭代过程中,最后⼀次epoch保存的模型。因为实际项⽬中主要使⽤视频进⾏推理,所以加载视频,使用best.pt进⾏推理测试。

基于yolov5和AIdLux的人流统计代码实现_第9张图片

c.Aidlux端模型推理测试
        在PC端测试完之后,我们主要是在边缘端Aidlux上进⾏使⽤,在前⾯我们也知道,Aidlux主要针对推理 部分,在底层进⾏了加速优化。因此想要将pt模型移植到Aidlux上使⽤,还要进⾏转换模型,修改推理代 码的操作。
pt模型转换成tflite模型 :模型转换的⽂件是export.py⽂件,在Aidlux中主要运⾏的是tflite的⽅式,a安装需要的依赖包后运⾏export.py⽂件,在models⽂件夹下⾯,可以看到⽣成的yolov 5 nfp 16 .tflite⽂件。

 Aidlux视频推理:将训 练好的tflite放到aidlux⽂件夹中。 其中包含了很多Aidlux专属的函数接⼝,⼤家可以在https://docs.aidlux.com/#/intro/ai/ai-aidlite,查 看下相关的函数说明。 

模型初始化及加载 :其中主要⽤到两个函数接⼝,⼀个是aidlite_gpu.aidlite()和aidlite.ANNMode()。

基于yolov5和AIdLux的人流统计代码实现_第10张图片

 视频读取&模型推理:

基于yolov5和AIdLux的人流统计代码实现_第11张图片

代码复制到Aidlux中 ,通过SSH远程连接Aidlux软件,在vscode终端中运行代码即可基于yolov5和AIdLux的人流统计代码实现_第12张图片

2.目标跟踪

        本项目使用Bytetrack多⽬标追踪算法,算法内容比较复杂,不在讲述,详细内容可以参考一下资料 ByteTrack: Multi-Object Tracking by Associating Every Detection Box阅读笔记
https://zhuanlan.zhihu.com/p/ 421264325

 基于yolov5和AIdLux的人流统计代码实现_第13张图片

每个⼈体框上⽅⽩⾊的字体,是⼈体检测框的分数。
蓝⾊的字体,是每个⼈体track_id的值。当然,前⾯说到⽬标追踪整体的算法相对⽐较复杂,针对不同的 场景,其实需要修改不同的参数。
基于yolov5和AIdLux的人流统计代码实现_第14张图片
3.人流统计
        首先我们要画出监测线的位置,然后通过判断目标框的位置与线的位置进行判断,判断逻辑如下:以图像左上角为原点建立坐标系,通过函数y = ax+b,判断点与线的关系,当点在线的上方时,输出状态为1,在下方时输出状态为-1,通过判断没个目标ID的当前状态与上一状态来判断运动方向以及是否越线。
基于yolov5和AIdLux的人流统计代码实现_第15张图片

最终结果如下: 

 最后附代码:

# aidlux相关
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/yolov5n_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/video.mp4")
frame_id = 0
count = 0 #记录越界人数
count1 = 0 #记录越界人数
while True:
    frame = cap.read()
    if frame is None:
        continue
    frame_id += 1
    if frame_id % 3 != 0:
        continue
    # print(frame.shape)
     # 预处理
    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.绘制越界监测区域
            #points = [[593,176],[904,243],[835,323],[507,259]]
            #points = [[593,176],[904,243],[835,323],[507,259]]
            points = [[123,276],[1280,276]]
            color_light_green=(255, 0, 0)  ##浅绿色 RGB
            res_img = process_points(res_img,points,color_light_green)

            # 2.计算得到人体下方中心点的位置(人体检测监测点调整)
            pt = [tlwh[0]+1/2*tlwh[2],tlwh[1]+tlwh[3]]
            pt1 = [tlwh[0]+1/2*tlwh[2],tlwh[1]]
            
            # 3. 人体和违规区域的判断(人体状态追踪判断)
            #track_info = is_in_poly(pt, points)
            track_info = is_passing_line(pt, points)
            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时,说明越界了 B->A
            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 += 1
                    print("count = %d" % count)

            if track_id_status[tid][-1] == -1 and len(track_id_status[tid]) >1:  #A->B 
               # 判断上一个状态是否是-1,是否的话说明越界,为了防止继续判别,随机的赋了一个3的值
                if  track_id_status[tid][-2] == 1:
                    track_id_status[tid].append(3)
                    # cv2.imwrite("overstep.jpg",res_img)
                    count1 += 1
                    print("count1 = %d" % count1)
              
    cv2.putText(res_img, "B->A person:" +str(count), (100, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
    cv2.putText(res_img, "A->B person:" +str(count1), (100, 80), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)
    cv2.putText(res_img, "A", (600, 250), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 3)
    cv2.putText(res_img, "B", (600, 320), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 3)
    cvs.imshow(res_img)

你可能感兴趣的:(人工智能,目标检测,计算机视觉,边缘计算)