基于AidLux平台和七牛云、喵提醒工具实现的人员跟踪计数系统

本文正在参加『In AidLux,To AIoT』AI应用案例征集活动

0.项目简介

第一次接触AidLux平台,整个软件的功能深深的惊艳了我,自带hello.py代码3行代码竟然能完成手机的语音自定义播报,第一感觉就是这个系统大有可为。

本项目主要实用yolov5 和deepsort算法对区域人员进行越线检测和人员计数功能,可以用于限制进出场景或者客流量统计。整套代码可以部署在手机上,通过七牛云、喵提醒工具可以实现远程查看告警功能。

完整的产品效果视频如下,当出现越线时,手机会自动收到一条提醒,并能查看监控区域的状态。

1.AidLux平台理解

AidLux是一个伟大的工具,有很广阔的应用前景,在ARM架构智能终端(Android系统手机、平板等)上能够同时运行Linux,提供了一系列AidLite API,动态调度CPU、GPU、NPU计算单元,充分释放AI算力,降低AI开发部署门槛,加速行业应用落地。Aidlux支持Android和鸿蒙系统,硬件上对高通的硬件支持更完善一些。AidLux上对Python代码可以无缝衔接,能够安装Python各种包,PC上的豆瓣源,清华源也可以直接用;它支持常用的深度学习原生框架如图1所示,基于pytorch的官方yolov5代码可以直接在AidLux上运行。但是由于平台封装的原因,封装了cvs图像包和opencv用法相近,主要展示图片或者视频的位置不同。对QT支持非常友好,代码小改后就可以直接运行,由于分辨率设置问题,展示的效果有点变形如图2所示。

图1 主流深度学习AI 框架

图2 QT演示效果

2.项目方案介绍

2.1系统功能介绍

本项目主要用到目标检测算法采用yolov5,跟踪算法采用deepsort框架下的ReID算法,对区域人员进行越线检测和人员计数功能,可以用于限制进出场景或者客流量统计。整套代码可以部署在手机上,通过七牛云、喵提醒工具可以展示远程告警功能,软件的流程如3下所示。

图3 软件流程图

2.2 关键技术介绍

本项目应用DeepSORT多目标跟踪技术,基于Tracking-by-Detection(检测加跟踪,使效果更稳定)策略,即基于yolov5的结果来进行目标跟踪。上面的视频是DeepSORT对人群进行跟踪的结果,每个bbox左上角的数字是用来标识某个人的唯一ID号。当人员自上向下和自下向上穿越模板区域都会触发计数和告警。

手机上运行FP32模型比较吃力,这个时候可以对yolov和deepsort算法进行int8量化,会发现识别的速度贼快!

图4 效果演示图

3.具体实现

3.1下载安装Aidlux软件

首先在安卓手机上下载一个Aidlux软件,Android的APP可以直接运行在鸿蒙系统中,在华为手机的应用商城中搜索“aidlux”,即可安装下载,如果有其他品牌的手机,在相关的应用商城中,都可以下载到相应的aidlux软件。将手机连入到WiFi后,点击aidlux APP就会进入到AidLux系统,里面会有各种软件提供下载。

3.2 ssh远程工具介绍

AidLux提供浏览终端和手机终端,总觉得不是很方便,通过ssh工具可以直接远程到手机做开发。注意 修改端口号为9022,不是ssh默认的22端口,内部做了地址映射。登陆用户名root,密码aidlux。

3.3Vscode远程调试

AidLux目前布支持pycharm远程调试,但是用vscode调试也不错。注意要按照一些插件,正常运行如下图所示。

3.4 安装Python包介绍

使用pip安裝軟需要的Python包,方法和PC端一样,具体命令如下:

pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple

3.5模型转换介绍

AidLux使用tflite格式进行加速推理,常用的Pytorch训练的模型,使用tflite进行部署,需要完成pytorch转为tflite。目前已知两种方法:一是pytorch --> onnx --> tensorflow --> tflite,此种方法为了通道变换,会增加transpose,transpose为访存密集型算子,会导致推理效率下降;二是使用tensorflow重新定义网络结构,将权重从pytorch copy过来,此方法操作效率低,且容易出错。推理示意图如下:

3.6远程提醒工具介绍

远程提醒主要‘喵提醒’发送文本信息进行提醒,通常识别后的是图片,要想看到图片就需要采用中间文件存储七彩牛工具,将图片的告警图片先推送到七彩牛服务器上,在将图片的外网地址通过‘喵提醒’发送到手机上。具体的详细过程见大白公众号推文。之前拼接图片的代码有问题已经修改,更新了测试图片。

4 代码分析

4.1代码结构

4.2预设置区域模板

 # 根据视频尺寸,填充一个polygon,供撞线计算使用
    mask_image_temp = np.zeros((1080, 1920), dtype=np.uint8)
# 初始化2个撞线polygon
list_pts_blue = [[204, 305], [227, 431], [605, 522], [1101, 464], [1900, 601], [1902, 495], [1125, 379], [604, 437],
                 [299, 375], [267, 289]]
ndarray_pts_blue = np.array(list_pts_blue, np.int32)
polygon_blue_value_1 = cv2.fillPoly(mask_image_temp, [ndarray_pts_blue], color=1)
polygon_blue_value_1 = polygon_blue_value_1[:, :, np.newaxis]

# 填充第二个polygon
mask_image_temp = np.zeros((1080, 1920), dtype=np.uint8)
list_pts_yellow = [[181, 305], [207, 442], [603, 544], [1107, 485], [1898, 625], [1893, 701], [1101, 568],
                   [594, 637], [118, 483], [109, 303]]
ndarray_pts_yellow = np.array(list_pts_yellow, np.int32)
polygon_yellow_value_2 = cv2.fillPoly(mask_image_temp, [ndarray_pts_yellow], color=2)
polygon_yellow_value_2 = polygon_yellow_value_2[:, :, np.newaxis]

4.3上行和下行判断逻辑

 if len(outputs) > 0:
            # ----------------------判断撞线----------------------
            for item_bbox in outputs:
                x1, y1, x2, y2, track_id, label,score = item_bbox
            # 撞线检测点,(x1,y1),y方向偏移比例 0.0~1.0
            y1_offset = int(y1 + ((y2 - y1) * 0.6))

            # 撞线的点
            y = int(y1_offset)
            x = int(x1)

            if polygon_mask_blue_and_yellow[y, x] == 1:
                # 如果撞 蓝polygon
                if track_id not in list_overlapping_blue_polygon:
                    list_overlapping_blue_polygon.append(track_id)
                pass

                # 判断 黄polygon list 里是否有此 track_id
                # 有此 track_id,则 认为是 外出方向
                if track_id in list_overlapping_yellow_polygon:
                    # 外出+1
                    up_count += 1

                    print(f'类别: {label} | id: {track_id} | 上行撞线 | 上行撞线总数: {up_count} | 上行id列表: {list_overlapping_yellow_polygon}')

                    if save_abnormal_image:
                        # save_abnormal_image = False
                        # abnormal_count += 1
                        img_save_path = 'up_count_abnormal_{}.jpg'.format(up_count)  
                        cv2.imwrite(img_save_path, frame)
                        img_name = img_save_path.split('\\')[-1]
                        url_receive = upload_qiniuyun(img_name, img_save_path)
                        from miaotixing_test import miaotixing_post
                        miaotixing_result = miaotixing_post(url_receive)

                    # 删除 黄polygon list 中的此id
                    list_overlapping_yellow_polygon.remove(track_id)

                    pass
                else:
                    # 无此 track_id,不做其他操作
                    pass

            elif polygon_mask_blue_and_yellow[y, x] == 2:
                # 如果撞 黄polygon
                if track_id not in list_overlapping_yellow_polygon:
                    list_overlapping_yellow_polygon.append(track_id)
                pass

                # 判断 蓝polygon list 里是否有此 track_id
                # 有此 track_id,则 认为是 进入方向
                if track_id in list_overlapping_blue_polygon:
                    # 进入+1
                    down_count += 1

                    if save_abnormal_image:
                        # save_abnormal_image = False
                        # abnormal_count += 1
                        img_save_path = 'down_count_abnormal_{}.jpg'.format(down_count)  
                        cv2.imwrite(img_save_path, frame)
                        img_name = img_save_path.split('\\')[-1]
                        url_receive = upload_qiniuyun(img_name, img_save_path)
                        from miaotixing_test import miaotixing_post
                        miaotixing_result = miaotixing_post(url_receive)

                    print(f'类别: {label} | id: {track_id} | 下行撞线 | 下行撞线总数: {down_count} | 下行id列表: {list_overlapping_blue_polygon}')

                    # 删除 蓝polygon list 中的此id
                    list_overlapping_blue_polygon.remove(track_id)

                    pass
                else:
                    # 无此 track_id,不做其他操作
                    pass
                pass
            else:
                pass
            pass

        pass

        # ----------------------清除无用id----------------------
        list_overlapping_all = list_overlapping_yellow_polygon + list_overlapping_blue_polygon
        for id1 in list_overlapping_all:
            is_found = False
            for _, _, _, _, bbox_id, _,_ in outputs:
                if bbox_id == id1:
                    is_found = True
                    break
                pass
            pass

            if not is_found:
                # 如果没找到,删除id
                if id1 in list_overlapping_yellow_polygon:
                    list_overlapping_yellow_polygon.remove(id1)
                pass
                if id1 in list_overlapping_blue_polygon:
                    list_overlapping_blue_polygon.remove(id1)
                pass
            pass
        list_overlapping_all.clear()
        pass

        # 清空list
        # outputs.clear()

        pass
    else:
        # 如果图像中没有任何的bbox,则清空list
        list_overlapping_blue_polygon.clear()
        list_overlapping_yellow_polygon.clear()
        pass
    pass

    text_draw = 'DOWN: ' + str(down_count) + \
                ' , UP: ' + str(up_count)
    output_image_frame = cv2.putText(img=output_image_frame, text=text_draw,
                                     org=draw_text_postion,
                                     fontFace=font_draw_number,
                                     fontScale=1, color=(255, 255, 255), thickness=2

4.4 手机运行实时视频效果

5. 总结和改进

本项目重点在于如何使用AidLux系统,将多目标跟踪的全套流程在AidLux系统中跑通。目标跟踪应用的场景比较广泛,像我现在工作中做的人员徘徊行为识别,重点区域的人员进出监控,感兴趣目标行为识别,都可以用AidLux做开发。后期根据实际的需求和应用场景,只用开发具体的应用逻辑,满足实际项目的需求,目前量化部分的代码支持用小米高通的芯片就可以支持int8量化,华为平台不支持int8量化加速。

AidLux优势在于基于手机终端操作系统,可以增加AI算法,非常便于原有终端系统的功能扩张。Aidlux平台兼容性和扩展性非常,对于pytorch训练的模型,很容易就能迁移到运行。文档也比较全:ttps://aidlux.com/docs。

感谢Aidlux提供算法平台,方便继续开发出更多更好更实用的AI小应用和大家一起分享交流。

全部代码gitee链接:git@gitee.com:AI-CNN/aidlux_deepsort_simpletracker.git

厉害?

实用性可以说是非常高了!

aidlux系统这么强大,学习了

充分利用身边的闲置手机,博主牛

这都可以,厉害了

虽然没太看懂原理,感觉很厉害

赞!大家都能用闲置手机做家庭安防设备了 :-D

不知道po主这个运行的帧率大概有多少,基于哪一个SoC型号呢?

我目前使用的华为的手机,是通过抽间隔帧的方法(1秒30帧的视频,只取5帧进行识别,另外的25帧就丢弃了)达到可实用的效果。

后期有问题可以在论坛交流

嗯嗯,这也是个思路。

AidLux系统非常适合给手机赋能,还能针对手机的GPU充分进行算力加速。

niubility啊,玩转aidlux啊