人流统计和越界识别在现实中的实际应用(基于aidlux系统)

0.主要工作

​ 在之前因为跑过人流统计的代码,用到了⼈体检测+⼈体追踪+业务功能 。这周主要是对人流统计进行一个偏实际化的应用,在AI现场应用中,都是通过摄像头采集视频图像,再利用算力设备的算力,进行算法分析处理,进而得到处理结果。算力设备主要分为GPU服务器、边缘设备、端侧嵌入式设备。而本文则是将安卓手机当作一个端侧嵌入式设备,因为内部都有一个AI算力芯片,可以进行一些简单轻量级的AI算法模型处理,但只能处理一路视频流。

​ 主要完成了yolov5在服务器上进行完整的一次训练过程。并利用Windows上的VS软件的远程连接,通过跨平台应用系统Aidlux在安卓手机或平板上进行进行Python版本的AI模型开发和移植,并通过喵提醒公众号将结果发到手机上。利用这个逻辑实现了越界识别和人流统计的功能。

1.VS远程连接

​ 在Aidlux中,首先下载手机版的Aidlux软件,然后打开Cloud_ip,获取id,将这个id输入到电脑浏览器上,显示内容与手机上的一样,通过这个id映射到电脑上,来操纵这个编程,当然在手机上也可但是麻烦。

​ 在VS中,首先下载安装本地版的python和Opencv,然后安装Remote SSH。调节远程config参数

在这里插入图片描述

这里的HostName就是Aidlux的Cloud_ip

​ 在成功完成VS与Aidlux的远程连接后进行运行时,遇到了一个问题,就是提示需要一个python解释器,搜索了多种解决方案,进行了多次尝试后,经历了多达一天的调试后仍未解决,最后在群里同学的提醒下,终于解决了这个问题,即选择手机中环境的路径/usr/bin/python

2.yoloV5的训练和部署

2.1数据集的准备

2.1.1标注信息转化

​在这里选择Crowdhuman数据集,总共包含三个⽅⾯:15000张的训练数据集,4370张的验证数据集,5000张的测试数据集。本来想选完整的数据集,但我选择了val数据集4370张图⽚。原因有俩,处理时间过长以及远程服务器不支持4G压缩包的zip解压,具体原因在讲到服务器再讨论。

首先将数据集中的annotation_val.odgt中的标注信息提取出来,变成和4370张图⽚对应VOC格式的XML格式。在这个数据集中,有三种标注内容,vbox、fbox、hbox,分别对应:可看到的⼈体,完整⼈体,⼈脸。在这里我们采用的是完整的人体的内容。fbox即表示提annotation_val.odgt中完整⼈体的检测框信息,person表示转换成xml后⼈体的标签名称信息。

具体代码见lesson3_codes中的data_code.py

#XML格式存放路径
roadlabels = "D:/aidlux/lesson/Lesson3/lesson3_data/Crowdhuman_data/Annotations/"
#数据集图片位置
roadimages = "D:/aidlux/lesson/Lesson3/lesson3_data/Crowdhuman_data/JPEGImages/"
#数据集annotation_val.odgt位置
fpath = "D:/aidlux/lesson/Lesson3/lesson3_data/Crowdhuman_data/annotation_val.odgt"

    # 下面是从odgt中提取三种类型的框并转为voc格式的xml的代码
    for i1, item1 in enumerate(gtboxes):
        # 提取全身框(full box)的标注;fbox即表示提annotation_val.odgt中完整⼈体的检测框信息
        boxs = [int(a) for a in item1['fbox']]
        # 左上点长宽->左上右下
        minx = str(boxs[0])
        miny = str(boxs[1])
        maxx = str(boxs[2] + boxs[0])
        maxy = str(boxs[3] + boxs[1])
        # print(box)
        object = doc.createElement('object')
        nm = doc.createElement('name')
        #person表示转换成xml后⼈体的标签
        nm.appendChild(doc.createTextNode('person'))  # 类名: fbox

2.1.2标注验证

​ 利用LabelImg软件对生成的XML格式进行标签验证,不过首先要将数据集的部分照片复制到XML格式存放路径中,验证完后进行删除。

在这里插入图片描述

2.1.3数据集整理

(1)首先对数据集进行清理,去掉那些有问题的标注、

(2)对4370张照片按8:2的比例划分成训练集和验证集

(3)将train和test的xml,转换成txt

注意的是这三个步骤要依次独立进行,不能多个同时进行。

train_data_split.py

import argparse
import xml.etree.ElementTree as ET
from utilis import *
import argparse

label_list = ['person']

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:/study/aidlux/12/Lesson3/lesson3_data/train_data', help='data dir')
    opt = parser.parse_args()
    get_image_txt(opt)

2.2训练

​ 由于电脑配置的问题,我这里选择用云服务器进行训练,采用了AutoDL AI算⼒云 (主要是免费体验10块钱的) 。注意的是选择网盘和实例的地区要选择一样的。

​ 将Yolov5_code训练代码、train_test_txt文件夹和数据集进行zip压缩后上传到网盘中(不超过4G) 。然后租一个服务器,我选择的是3080单卡,主要是便宜。根路径为/root/autodl-nas/。新建实例时要先pip install opencv-python。

​ 首先要新建一个person.yaml,因为是人体检测模型

path: /root/autodl-nas/train_data/train_test_txt  # dataset root dir
train: train.txt  # train images (relative to 'path') 118287 images
val: test.txt  # val images (relative to 'path') 5000 images
#test: test-dev2017.txt  # 20288 of 40670 images, submit to https://competitions.codalab.org/competitions/20794

# Classes
nc: 1  # number of classes
names: ['person']  # class names

​ 其次修改train.py参数,选择yolov5n的模型权重和对应的⽹络结构路径 ,数据集采用新增的person.yaml路径。采用了120的epochs和32的batch-size(为了训练快些)

def parse_opt(known=False):
    parser = argparse.ArgumentParser()
    parser.add_argument('--weights', type=str, default=ROOT / 'models/yolov5n.pt', help='initial weights path')
    parser.add_argument('--cfg', type=str, default='models/yolov5n.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=120)
    parser.add_argument('--batch-size', type=int, default=32, help='total batch size for all GPUs, -1 for autobatch')

​ 接着修改models/yolov5n.yaml的类别数为1

​ 然后安装所需的库pip install -r requirements。

​ 最后训练:python train.py,得到best.pt和last.pt。下载best.pt

在这里插入图片描述

​ 在整个服务器训练过程中,也是遇到了一些问题,折腾到了凌晨两点才完成。

​ 首先就是数据集选择问题,刚开始选择的是一个完整的数据集(15000张训练集),经过压缩后上传到服务器上后用unzip解压不了,原因是unzip不能解压4G以上的压缩包,只能用别的方式进行解压,但是搜集了网上资料后总是在服务器上安装不了(希望有人能帮帮我想想办法),因此重新压缩数据集,分成多个压缩包,将每个压缩包的大小控制在4G以下。然后再进行解压,在服务器上进行合并,合并的过程也比较忐忑,刚开始是用类似于Windows的方法进行复制粘贴,由于占用内存过大以及有点难用,导致速度有点慢,并且光卡,就放弃了这个方法。最后采用了Linux的命令进行解压,但还是不能将多个压缩包的文件里面所有文件解压到一个文件夹里(怪我是个菜鸟,不熟悉Linux命令)。最后有点崩溃,就换了那个轻量级的数据集。因为图片比较少,所以不是很卡顿,顺利完成了解压。但这整个过程也花费了我一天的时间,因为不管是压缩过程还是解压过程又或者是文件上传到服务器的过程,花费的时间都很长!!!

​ 其次就是安装的库的问题,因为在YOLOv5官方的安装requirements.txt中是要求tqdm>=4.41.0,而在这里requirements.txt的tqdm==4.8.2,不满足需要,需要卸载重装符合要求的tqdm>=4.41.0。

​ 接着就是训练过程了,整个训练过程是比较成功的,花费了五个小时,但由于在解决问题的时候,也花费了不少时间,浪费了10元代金卷的不少钱(在解压时要服务器(实例)上解决,不能关闭服务器,钱是一直花的,再加上第一次用,有点不熟练),所以为了完成训练又充了一些钱才训练完毕(学生党,没有钱啊)。这也是为什么选择120的epoch和32的batch-size以及轻量化数据集的主要原因!但这也导致一些指标不是很高,没办法,鱼和熊掌不可兼得。

最终精度如下:

在这里插入图片描述

2.3PC端Pytorch推理测试

​ 将best.pt模型下载下来后,修改成yolov5n_best.pt,放在yolov5_code中。并利用detect_image.py进行测试。仍要修改一些参数

def parse_opt():
    parser = argparse.ArgumentParser()
    parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'models/yolov5n_best.pt', help='model path(s)')
    parser.add_argument('--source', type=str, default=ROOT / 'data/images', help='file/dir/URL/glob, 0 for webcam')
    parser.add_argument('--data', type=str, default=ROOT / 'data/person.yaml', help='(optional) dataset.yaml path')

​ 但因为不知为啥,在VS上不能运行,说是torch与torchvision版本不匹配。但我在pyCharm上是可以运行的。在网上也找了些方法,都是让我重新安装的。但是好麻烦,当初在pyCharm上安装时就花了不少时间,所以直接在pyChorm上运行。不影响VS的远程使用。

​ 这里也遇到了一个问题,就是每次得按一下回车才能显示下一帧,后来发现是waitkey(0)的问题,将其设置为waitkey(10)。

在这里插入图片描述

2.4Aidlux端推理

​ Aidlux主要针对推理部分,在底层进⾏了加速优化。因此想要将pt模型移植到Aidlux上使⽤,还要进⾏转换模型。即将pt模型转换成tflite模型

​ export.py 部分代码如下,主要修改data/person.yaml、models/yolov5n_best.pt以及default=[‘tflite’],最后生成yolov5n-fp16.tflite⽂件

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/yolov5n_best.pt', help='model.pt path(s)')
   #....
    parser.add_argument('--include',
                        nargs='+',
                        default=['tflite'],
                        help='torchscript, onnx, openvino, engine, coreml, saved_model, pb, tflite, edgetpu, tfjs')

注:需要pip3 install tensorflow -i https://pypi.tuna.tsinghua.edu.cn/simple

​ 接着将yolov5_code文件传到Aidlux上去

​ in_shape,out_shape 可以使用https://netron.app/ 打开yolov5n_best-fp16.tflite⽂件,点输出单元就可以得到type

在这里插入图片描述

打开 yolov5_code\aidlux\yolov5.py文件

# aidlux相关
from cvs import *
import aidlite_gpu
from utils import detect_postprocess, preprocess_img, draw_detect_res

import time
import cv2

# AidLite初始化:调用AidLite进行AI模型的加载与推理,需导入aidlite
aidlite = aidlite_gpu.aidlite()
# Aidlite模型路径
model_path = '/home/lesson3_codes/yolov5_code/aidlux/yolov5n_best-fp16.tflite'
# 定义输入输出shape
in_shape = [1 * 640 * 640 * 3 * 4]
out_shape = [1 * 25200 * 6 * 4]
# 加载Aidlite检测模型:支持tflite, tnn, mnn, ms, nb格式的模型加载
aidlite.ANNModel(model_path, in_shape, out_shape, 4, 0)

# 读取视频进行推理
cap = cvs.VideoCapture("/home/lesson3_codes/yolov5_code/aidlux/video.mp4")
frame_id = 0
while True:
    frame = cap.read()
    if frame is None:
        continue
    frame_id += 1
    if not int(frame_id) % 5 == 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.5, iou_thres=0.45)
    # 绘制推理结果
    res_img = draw_detect_res(frame, pred)
    cvs.imshow(res_img)
cap.release()
cv2.destroyAllWindows()  

刚开始的结果是

在这里插入图片描述

后来自己独自经过改进将推理的得到的检测框分数绘制到每个⼈体上,同时检测的框变为蓝⾊

在这里插入图片描述

主要修改了untils的draw_detect_res函数,将分数从数组中提出了并利用puttext函数表示出来

def draw_detect_res(img, all_boxes):
    '''
    检测结果绘制
    '''
    img = img.astype(np.uint8)
    color_step = int(255/len(all_boxes))
    for bi in range(len(all_boxes)):
        if len(all_boxes[bi]) == 0:
            continue
        for box in all_boxes[bi]:
            x, y, w, h = [int(t) for t in box[:4]]
            score = str(box[-1])
            cv2.putText(img, str(round(float(score),2)), (x-2, y-19), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2)
            cv2.rectangle(img, (x,y), (x+w, y+h),(0, bi*color_step, 255-bi*color_step),thickness = 2)
    return img

但不知道为啥x, y, w, h,score = [int(t) for t in box[:5]]提不出来score(python菜鸟,只懂基本)

3.⽬标追踪算法

3.1算法原理

​ 在业内多⽬标跟踪算法,应⽤的⽐较⼴的发展路径是:sort->deepsort->bytetrack

​ sort算法采⽤卡尔曼预测的⽅法,判断两⼈的运动轨迹,再采⽤匈⽛利算法,从多个检测框中,匹配找到不同路人的框,并赋予各自得track_id值。但当两个⼈遮挡交错时,因为通过位置信息来构建 ,卡尔曼预测就会出问题,导致track_id错乱。

​ 因此在deepsort中额外增添了人体外观特征信息,与位置信息进行加权匹配。但在遮挡交错⽐较多的时候,⼈体的检测框的预测分数比不遮挡时低,导致track_id错乱。

​ 因此将deepsort中的外观特征舍弃掉,通过bytetrack的⽅式进⾏多⽬标追踪过这时设置⾼分和低分框,当预测运动轨迹的框,分数降低时,说明可能产⽣了遮挡的现象,这时就再多匹配⼀些。

3.2Aidlux端检测追踪代码测试

在这里插入图片描述

4.越界识别

主要步骤为越界监测区域绘制、越界识别功能实现、⼈体检测监测点调整、⼈体状态追踪判断、越界⾏为判断、系统告警。代码在yolov5_overstep.py 中

首先将所要的监测的区域坐标记录下来,传到points数组中

 # 1.绘制越界监测区域
            points = [[593,176],[904,243],[835,323],[507,259]]
            color_light_green=(144, 238, 144)  ##浅绿色
            res_img = process_points(res_img,points,color_light_green)

其次通过yolov5算法,会得到检测框的四个点信息,[左上⻆点x,左上⻆点y,宽w,⾼h]。所以我们需要通过代码,转换成⼈体下⽅的点,即[左上⻆点x+1/2*宽w,左上⻆点y+⾼h]

# 2.计算得到人体下方中心点的位置(人体检测监测点调整)
pt = [tlwh[0]+1/2*tlwh[2],tlwh[1]+tlwh[3]]

还需要根据⼈体是否在监测区域内,将⼈体在监测区域内设置为1,不在监测区域内设置为-1

# 3. 人体和违规区域的判断(人体状态追踪判断)
            track_info = is_in_poly(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)

            

is_in_poly函数

def is_in_poly(p, poly):
    """
    :param p: [x, y]
    :param poly: [[], [], [], [], ...]
    :return:
    """
    px, py = p
    is_in = False
    for i, corner in enumerate(poly):
        next_i = i + 1 if i + 1 < len(poly) else 0
        x1, y1 = corner
        x2, y2 = poly[next_i]
        if (x1 == px and y1 == py) or (x2 == px and y2 == py):  # if point is on vertex
            is_in = True
            break
        if min(y1, y2) < py <= max(y1, y2):  # find horizontal edges of polygon
            x = x1 + (py - y1) * (x2 - x1) / (y2 - y1)
            if x == px:  # if point is on edge
                is_in = True
                break
            elif x > px:  # if point is on left-side of line
                is_in = not is_in

    if is_in == True:
        person_status = 1
    else:
        person_status = -1

    return person_status

接着判断是否越界,根据person_status进行判断,⽐如某个⼈当前⼀帧的状态是-1,后⼀帧的状态变成1时,说明刚刚进⼊越界区域,并对图片进行保存

# 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)

                   

最后通过微信“喵提醒”的⽅式,来警告工作人员

这里的喵码是在“喵提醒”公众号上获得的,这段代码也是通用代码

if  track_id_status[tid][-2] == -1:
                    track_id_status[tid].append(3)
                    cv2.imwrite("overstep.jpg",res_img)
# 5.越界识别+喵提醒
                    # 填写对应的喵码
                    id = 'tP48aPC'
                    # 填写喵提醒中,发送的消息,这里放上前面提到的图片外链
                    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)

结果图,图中区域是自己设置的区域

在这里插入图片描述

5.根据越界识别进行人流统计

​ 人流统计和越界识别的步骤差不多是一样的,人流统计越界线段绘制、越界识别功能实现、⼈体检测监测点调整、⼈体和线段的位置状态判断 、越界⾏为判断、⼈流统计分析判断、视频结束后将结果通过喵提醒发送 。

这里代码是自己根据越界识别的代码进行修改的

# aidlux相关
from cvs import *
import aidlite_gpu

from aidlux.utils import detect_postprocess, preprocess_img, draw_detect_res, scale_coords,process_points,is_in_poly,is_passing_line
from utils import *
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_person = 0
while True:
    frame = cap.read()
    if frame is None:
        print("采集结束")
        #统计打印人流数量
        id = 'tPK8yD8'
        # 填写喵提醒中,发送的消息,这里放上前面提到的图片外链
        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 = [[308,220],[1209,483]]
            cv2.line(res_img,(308,220),(1209,483),(255,255,0),3)


            # 2.计算得到人体下方中心点的位置(人体检测监测点调整)⽤的yolov5算法,会得到检测框的四个点信息,[左上⻆点x,左上⻆点y,宽w,⾼h]。所以我们需要通过代码,转换成⼈体下⽅的点,即[左上⻆点x+1/2*宽w,左上⻆点y+⾼h]。
            pt = [tlwh[0]+1/2*tlwh[2],tlwh[1]+tlwh[3]]
            
            # 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)
                    count_person += 1
    cv2.putText(res_img, "-1 to 1 person count:"+str(count_person),(50,50),cv2.FONT_HERSHEY_SIMPLEX,1,(0,0,0),2)
    cvs.imshow(res_img)

is_passing_line函数:判断是否越过横线

def is_passing_line(point, polyline):
    # 在直线下方,status =-1
    # 在直线上方,status =1
    status = 1
    # 点映射在直线的高度
    poly_y = ((polyline[1][1] - polyline[0][1]) * (point[0] - polyline[0][0])) / (polyline[1][0] - polyline[0][0]) + \
              polyline[0][1]
    if point[1] > poly_y:
        status = -1
    return status

这里不知道为啥在puttext函数中用中文会显示乱码。

在这里插入图片描述

6.后续改进

​ 这篇文章写了也得有四五个小时了,给一周完成的AI实战训练营&Aidlux一个比较好的收尾总结。在这一周的学习中,可以说是收获很多,以前学习深度学习仅限于理论或者在本地PC端跑跑代码,但学习完后则可以在实战中进行应用各种项目。这里要感谢训练营的江大白老师,在整个过程中给了我们不少帮助,我也是跟着大白老师编写的使用手册才能一步步完成的。只能说,大白老师是我滴神。过几天也会根据大白的资料来发一个完整的使用文档,保证你们也能完整的做出来

​ 因为时间原因,再加上手机用的是我妈妈的手机(是部署在安卓环境下的,不支持ios系统),虽然疫情在家了,但在我手上的时间不算是很多,都是进行结果的验证,就先做到这里。因为下周我家就解封了,我妈妈也就上班了,能用到手机的时间更少了。所以后续还有时间的话就会进行优化。

​ 主要优化为:

​ (1)实现从上到下以及从下到上的人流统计(上述只统计了一侧,可以通过额外加一个判断从1 到-1的函数来实现两侧的功能)

​ (2)在越界识别时有人越界就通过服务器转接来发送图片而不仅仅发送文字

​ (3)在一个视频上同时进行越界识别和人流统计(通过修改person_status,因为越界识别和人流统计用的都是从-1到1时进行判断的,在这里我们可以将越界识别设置为-1到1时进行判断,将人流统计设置为-2到2时进行判断)

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Shall蔚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值