手把手教你为PP-Human添加简单的自定义功能

0. 写在前面

本项目主要记录了我在使用PP-Human时为其扩展自己所需功能的过程,希望可以给大家提供一些参考,减少大家自己看代码所花费的时间。快速上手与扩展运用PP-Human

球员队伍标注与分类为例,主要介绍如何添加不需要模型推理的简单任务,并为自己的功能添加所需的可视化效果。

1. PP-Human介绍

PP-Human是基于飞桨深度学习框架的业界首个开源产业级实时行人分析工具,具有功能丰富,应用广泛和部署高效三大优势。

在这里插入图片描述

以上是官方文档提供的介绍与功能展示。

功能非常丰富,包含行为识别、人体属性识别、流量计数、跨镜跟踪等等。官方也提供了各个功能的二次开发教程链接

教程主要集中在模型的训练与替换上,写的非常通俗易懂,建议先阅读官方文档。

添加了自定义球员队伍分类后的效果:

识别两支足球队的队员,并分别用不同的颜色框进行标注,显示所属的球队名

白色皇马RMA,红色利物浦LIV,黑色是其他

在这里插入图片描述

2. PP-Human快速开始

2.1 环境安装与配置

因为develop分支未在gitee上更新,我这里打包挂载在了数据集中

解压develop分支的PaddleDetection

!unzip data/data158776/PaddleDetection-develop.zip 

安装PaddleDetection依赖

%cd PaddleDetection-develop
!pip install -r requirements.txt

2.2 PP-Human功能初体验

首先修改 infer_cfg_pphuman 配置文件 (直接点击就能跳转)。

路径:PaddleDetection-develop/deploy/pipeline/config/infer_cfg_pphuman.yml

将其中MOTenable参数改为True以开启PP-Human的人员追踪功能。

之后运行下面的代码,体验PP-Human的基础人员追踪功能

%cd /home/aistudio/PaddleDetection-develop
!python deploy/pipeline/pipeline.py --config deploy/pipeline/config/infer_cfg_pphuman.yml \
    --video_file=/home/aistudio/work/test-video/test.mp4 \
    --device=gpu

可以在PaddleDetection-develop/output找到PP-Human输出的视频

从中截取一张图片的效果:

实现了人员的追踪与编号

在这里插入图片描述

PP-Human还提供了许多其他模型的串联推理和其他的一些可视化功能,这里摘取官方文档的一部分:

预测部署

#行人检测,指定配置文件路径和测试图片
python deploy/pipeline/pipeline.py --config deploy/pipeline/config/infer_cfg_pphuman.yml --image_file=test_image.jpg --device=gpu [--run_mode trt_fp16]

#行人跟踪,指定配置文件路径和测试视频,在配置文件deploy/pipeline/config/infer_cfg_pphuman.yml中的MOT部分enable设置为```True```
python deploy/pipeline/pipeline.py --config deploy/pipeline/config/infer_cfg_pphuman.yml --video_file=test_video.mp4 --device=gpu [--run_mode trt_fp16]

#行人跟踪,指定配置文件路径,模型路径和测试视频,在配置文件deploy/pipeline/config/infer_cfg_pphuman.yml中的MOT部分enable设置为```True```
#命令行中指定的模型路径优先级高于配置文件
python deploy/pipeline/pipeline.py --config deploy/pipeline/config/infer_cfg_pphuman.yml --video_file=test_video.mp4 --device=gpu [--run_mode trt_fp16]

#行人属性识别,指定配置文件路径和测试视频,在配置文件deploy/pipeline/config/infer_cfg_pphuman.yml中的ATTR部分enable设置为```True```
python deploy/pipeline/pipeline.py --config deploy/pipeline/config/infer_cfg_pphuman.yml --video_file=test_video.mp4 --device=gpu [--run_mode trt_fp16]

#行为识别,以摔倒识别为例,指定配置文件路径和测试视频,在配置文件deploy/pipeline/config/infer_cfg_pphuman.yml中的SKELETON_ACTION部分enable设置为```True```
python deploy/pipeline/pipeline.py --config deploy/pipeline/config/infer_cfg_pphuman.yml --video_file=test_video.mp4 --device=gpu [--run_mode trt_fp16]

#行人跨境跟踪,指定配置文件路径和测试视频列表文件夹,在配置文件deploy/pipeline/config/infer_cfg_pphuman.yml中的REID部分enable设置为```True```
python deploy/pipeline/pipeline.py --config deploy/pipeline/config/infer_cfg_pphuman.yml --video_dir=mtmct_dir/ --device=gpu [--run_mode trt_fp16]

#行人跨境跟踪,指定配置文件路径和测试视频列表文件夹,直接使用deploy/pipeline/config/examples/infer_cfg_reid.yml配置文件,并利用-o命令修改跟踪模型路径
python deploy/pipeline/pipeline.py --config deploy/pipeline/config/examples/infer_cfg_reid.yml --video_dir=mtmct_dir/ -o MOT.model_dir="mot_model_dir" --device=gpu [--run_mode trt_fp16]

对rtsp流的支持,video_file后面的视频地址更换为rtsp流地址,示例如下:

#行人属性识别,指定配置文件路径和测试视频,在配置文件deploy/pipeline/config/infer_cfg_pphuman.yml中的ATTR部分enable设置为True
python deploy/pipeline/pipeline.py --config deploy/pipeline/config/infer_cfg_pphuman.yml -o visual=False --video_file=rtsp://[YOUR_RTSP_SITE] --device=gpu [--run_mode trt_fp16]

参数说明

参数是否必须含义
–configYes配置文件路径
-oOption覆盖配置文件中对应的配置
–image_fileOption需要预测的图片
–image_dirOption要预测的图片文件夹路径
–video_fileOption需要预测的视频,或者rtsp流地址
–camera_idOption用来预测的摄像头ID,默认为-1(表示不使用摄像头预测,可设置为:0 - (摄像头数目-1) ),预测过程中在可视化界面按q退出输出预测结果到:output/output.mp4
–deviceOption运行时的设备,可选择CPU/GPU/XPU,默认为CPU
–output_dirOption可视化结果保存的根目录,默认为output/
–run_modeOption使用GPU时,默认为paddle, 可选(paddle/trt_fp32/trt_fp16/trt_int8)
–enable_mkldnnOptionCPU预测中是否开启MKLDNN加速,默认为False
–cpu_threadsOption设置cpu线程数,默认为1
–trt_calib_modeOptionTensorRT是否使用校准功能,默认为False。使用TensorRT的int8功能时,需设置为True,使用PaddleSlim量化后的模型时需要设置为False
–do_entrance_countingOption是否统计出入口流量,默认为False
–draw_center_trajOption是否绘制跟踪轨迹,默认为False

3. 扩展球队分类功能

以上面的一段视频为例,想要识别分别穿着白色红色皇马利物浦球员是一个很简单的任务,只需要对每个检出框中的球衣颜色进行识别即可。完全不需要采集、标注数据后再去训练图片分类模型(这是基于id属性分类的流程)

而且对于类似的球赛,两队队服颜色肯定是不同的,也一般不会和场地颜色相同。使用行人检出框中的内容用颜色去识别球队应该是快速且可行的简单方案。

以下是实现的过程:

3.1 添加命令行参数

将需要新加的功能放在命令行中提供开关的接口

修改 pipeline/pipe_utils.py

点击打开pipe_utils.py

在开头的argsparser()函数中可以看到命令行各参数的配置,我们在137行添加以下内容:

--team_clas参数,接受4个字符串分别是:color1, name1, color2, name2分别代表两个队伍的球服颜色与球队名

parser.add_argument(
        "--team_clas",
        nargs='+',
        type=str,
        default=[],
        help="Color based team classification, "
             "receive four parameters(color1, name1, color2, name2),"
             "The optional color parameters are: [black, white, blue, red, yellow, green, purple, orange]")

添加完之后可以运行下面的代码进行测试,相较于原来添加了--team_clas white RMA red LIV参数

如果没有报错,命令行参数就添加成功了。

当然因为还没有加后处理和可视化,输出的结果是没有区别的,这里只是测试一下参数能否使用。

!python deploy/pipeline/pipeline.py --config deploy/pipeline/config/infer_cfg_pphuman.yml \
    --video_file=/home/aistudio/work/test-video/test.mp4 \
    --device=gpu --team_clas white RMA red LIV

3.2 添加后处理

根据之前所说的,我们用简单的颜色分类来实现球队的分类。这可以简单的用cv2.inrange()实现,PP-Human的pipeline中也有切割好的各个行人crop,我们只需要找到这部分数据并对他进行处理就可以。

修改pipeline.py

点击打开pipeline.py

路径:PaddleDetection-develop/deploy/pipeline/pipeline.py

在217行找到PipePredictor(object)类,我们的后处理都写在这个类中

  • 首先在类构造方法__init__中,添加以下一行代码,读取命令行输入的参数
self.team_clas = args.team_clas
  • 之后在def predict_video(self, video_file):函数中添加我们的后处理:

注意要添加在767行以后,与其他参数功能的代码在一起。可以直接ctrl+f搜索if self.with_human_attr:

if self.team_clas:
    color = {   # HSV颜色对照表
        "black": {"color_lower": np.array([0, 0, 0]), "color_upper": np.array([180, 255, 46])},
        "white": {"color_lower": np.array([0, 0, 221]), "color_upper": np.array([180, 30, 255])},
        "blue": {"color_lower": np.array([100, 43, 46]), "color_upper": np.array([124, 255, 255])},
        "red": {"color_lower": np.array([156, 43, 46]), "color_upper": np.array([180, 255, 255])},
        "yellow": {"color_lower": np.array([26, 43, 46]), "color_upper": np.array([34, 255, 255])},
        "green": {"color_lower": np.array([35, 43, 46]), "color_upper": np.array([77, 255, 255])},
        "purple": {"color_lower": np.array([125, 43, 46]), "color_upper": np.array([155, 255, 255])},
        "orange": {"color_lower": np.array([11, 43, 46]), "color_upper": np.array([25, 255, 255])}
    }
    if len(self.team_clas)!=4:  # 参数检查
        raise "team_clas input error"
    team_list = [[self.team_clas[0], self.team_clas[1]], [self.team_clas[2], self.team_clas[3]]]
    team_result = []
    crop_input_team, temp0, temp1 = crop_image_with_mot(frame_rgb, mot_res, expand=False)   # 获取行人检出框的crop结果

    for i in crop_input_team:   # 对每一张切割出的人像进行分类
        ori_img = i
        img = cv2.cvtColor(ori_img, cv2.COLOR_RGB2HSV)  # 转成HSV
        color_img_0 = cv2.inRange(img, color[team_list[0][0]]["color_lower"],
                                  color[team_list[0][0]]["color_upper"])  # 筛选出符合的颜色
        color_img_1 = cv2.inRange(img, color[team_list[1][0]]["color_lower"],
                                  color[team_list[1][0]]["color_upper"])  # 筛选出符合的颜色
        img_class_0 = color_img_0.flatten().tolist()
        img_class_1 = color_img_1.flatten().tolist()
        ratio_0 = img_class_0.count(255) / len(img_class_0)
        ratio_1 = img_class_1.count(255) / len(img_class_1)
        if ratio_0 > ratio_1 and ratio_0 > 0:
            team_result.append([team_list[0][1]])
        elif ratio_1 > 0:
            team_result.append([team_list[1][1]])
        else:
            team_result.append(['unknown'])
    attr_res = {'output': team_result}
    self.pipeline_res.update(attr_res, 'team_clas') # 回传分类结果

3.3 添加可视化

这一块需要修改三个文件:

修改pipeline.py

点击打开pipeline.py

路径:PaddleDetection-develop/deploy/pipeline/pipeline.py

ctrl+f找到human_attr_res = result.get('attr'),这里是各个参数附加功能调用visualize模块的visualize_video函数
在于其他参数可视化代码相同位置添加:(大体上就是复制了其他功能的代码)

from python.visualize import visualize_team
team_clas_res = result.get('team_clas')
if team_clas_res is not None:
    boxes = mot_res['boxes'][:, 1:]
    image = visualize_team(image, team_clas_res, boxes)
    image = np.array(image)
修改datacollector.py

点击打开datacollector.py

在开头的Result类的构造函数中添加:

'team_clas': dict(),

别忘了在上一个参数后面加,

修改visualize.py

点击打开visualize.py

路径:PaddleDetection-develop/deploy/python/visualize.py

在这里添加我们球队可视化的代码:

def visualize_team(im, results, boxes=None):
    results = results["output"]
    if isinstance(im, str):
        im = Image.open(im)
        im = np.ascontiguousarray(np.copy(im))
        im = cv2.cvtColor(im, cv2.COLOR_RGB2BGR)
    else:
        im = np.ascontiguousarray(np.copy(im))

    im_h, im_w = im.shape[:2]
    text_scale = max(0.5, im.shape[0] / 3000.)
    text_thickness = 1
    line_inter = im.shape[0] / 40.
    for i, res in enumerate(results):
        if boxes is None:
            text_w = 3
            text_h = 1
        else:
            box = boxes[i]
            text_w = int(box[2]) + 3
            text_h = int(box[3])
        for text in res:
            text_h += int(line_inter)
            text_loc = (text_w, text_h)
            cv2.putText(
                im,
                text,
                text_loc,
                cv2.FONT_ITALIC,
                text_scale, (0, 255, 255),
                thickness=text_thickness)
    return im

3.4 功能体验

自此球队分类的功能代码已经全部添加完成了,可以运行下面的代码试一下效果

输出文件路径:PaddleDetection-develop/output

!python deploy/pipeline/pipeline.py --config deploy/pipeline/config/infer_cfg_pphuman.yml \
    --video_file=/home/aistudio/work/test-video/test.mp4 \
    --device=gpu --team_clas white RMA red LIV

截一张图:
可以看见在检出框中的LIV与RMA标识
在这里插入图片描述

但是这样的可视化看起来还是有些费劲,让他的框能直接显示球队颜色那就最好了

3.5 优化可视化

修改visualize.py

点击打开visualize.py

路径:PaddleDetection-develop/deploy/python/visualize.py

在这里我们修改原来球队可视化的代码:


def visualize_team(im, results, boxes=None):
    results = results["output"]
    if isinstance(im, str):
        im = Image.open(im)
        im = np.ascontiguousarray(np.copy(im))
        im = cv2.cvtColor(im, cv2.COLOR_RGB2BGR)
    else:
        im = np.ascontiguousarray(np.copy(im))

    im_h, im_w = im.shape[:2]
    text_scale = max(0.5, im.shape[0] / 3000.)
    text_thickness = 1
    line_inter = im.shape[0] / 40.
    for i, res in enumerate(results):
        if boxes is None:
            text_w = 3
            text_h = 1
        else:
            box = boxes[i]
            text_w = int(box[2]) + 3
            text_h = int(box[3])
        for text in res:
            text_h += int(line_inter)
            text_loc = (text_w, text_h)
            cv2.putText(
                im,
                text,
                text_loc,
                cv2.FONT_ITALIC,
                text_scale, (0, 255, 255),
                thickness=text_thickness)
            if text == 'RMA':
                team_color = [255, 255, 255]
            elif text == 'LIV':
                team_color = [0, 0, 255]
            else:
                team_color = [0, 0, 0]
            cv2.rectangle(
                im,
                (int(box[2]), int(box[3])),
                (int(box[2]+box[4]), int(box[3]+box[5])),
                team_color,
                thickness=text_thickness*2
            )
    return im

之后再运行下面的代码

!python deploy/pipeline/pipeline.py --config deploy/pipeline/config/infer_cfg_pphuman.yml \
    --video_file=/home/aistudio/work/test-video/test.mp4 \
    --device=gpu --team_clas white RMA red LIV

最终效果:
白色皇马,红色利物浦,黑色是其他
在这里插入图片描述

4. 一些问题

  • 因为没有考虑前后帧与id对应,结果可能偶尔会有一些闪烁
  • 多人重叠的时候使用颜色识别来判断队伍会出现错误
  • 使用id与前后帧数据的简单可视化功能会在后面介绍(可能)
Logo

学大模型,用大模型上飞桨星河社区!每天8点V100G算力免费领!免费领取ERNIE 4.0 100w Token >>>

更多推荐