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

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

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

1.人体检测
        因为需要⼈体检测的模型,所以需要先训练⼀个检测模型,并转换成Aidlux可以部署的⽅ 式,进⾏推理测试。
        a.数据集处理
        ⼈体检测的数据集有很多,这⾥主要采⽤旷视开源的Crowdhuman的数据集。根据官网提示后,下载的数据如下所示

 由于下载后的标注文件为odgt格式,所以需要将标注⽂件odgt格式转换成xml格式,需要注意的是Crowdhuman中,有三种标注内容,vbox、fbox、hbox,分别对应:可看到的⼈体,完整 ⼈体,⼈脸。 本次训练过程中主要使⽤完整⼈体进⾏训练,因此主要⽤到fbox的标签

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

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

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

        修改train.py参数 :⽽yolov5_code/train.py⽂件中,主要修改models初始化模型的路径,这⾥使⽤的yolov 5 n的模型 权重。cfg即模型对应的⽹络结构路径,data是新增的person.yaml路径。此外还有epochs训练迭代的次数,batch-size⼤⼩,当然imgsz也可以修改,这⾥默认640

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

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

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

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()。

 视频读取&模型推理:

代码复制到Aidlux中 ,通过SSH远程连接Aidlux软件,在vscode终端中运行代码即可

2.目标跟踪

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

 

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

最终结果如下: 

 最后附代码:

# 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)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值