本项目遵循SORT算法思路,用PaddleX的PicoDet作行人检测器,设计基于卡尔曼滤波的边框估计模型,以边框交并比为度量,通过Jonker-Volgenant算法匹配,实现简单行人多目标跟踪。还分析了SORT不足,为后续按DeepSORT思路优化提供方向。

0 项目引言
当前基于深度学习的多目标跟踪思路主要有两种,分别是JDE(Jointly learns the Detector and Embedding model)和SDE(Separate Detection and Embedding model),其中代表性的有SORT1 和DeepSORT2,遵循Tracking-by-Detection思路,卡尔曼滤波算法3(Kalman Filter)是这些方法的基础,所以本项目的主要目的也是通过对卡尔曼滤波的通俗讲解,以探寻前人优秀工作轨迹和自我启发。
本项目的检测器部分使用PaddlePaddle—PaddleX4全流程开发套件接口,跟踪器部分主要描述卡尔曼滤波的算法思想和步骤,并且设计简易的卡尔曼模型,实现基于检测器预测的多目标跟踪。
与本项目类似的还有《基于PP-YOLO Tiny和DSST算法的多目标跟踪》,该方案将生成式模型修改为了相关式模型。
1 目标检测器
以行人跟踪为例,准备好的行人视频位置为 work/origin.mp4,它用来测试后面的跟踪任务。
1.1 模型导出
说明:本章的代码不一定要运行,权重已经保存在 models/。
飞桨最近发布了新模型 PP-PicoDet5 ,便采用该模型作为检测器。但为了编写方便不采用yaml形式配置项目,恰好PaddleX存在该模型的接口,所以可以直接调用该模型无需重新编写。
本节主要是将PaddleX模型装载预训练的权重,这里选择下载这个PicoDet-L预训练。
获取 COCO 数据集预训练权重。
In [ ]!mkdir work/pretrained/!wget https://paddledet.bj.bcebos.com/models/picodet_l_640_coco.pdparams -P work/pretrained/登录后复制
安装最新版 PaddleX,它支持 PicoDet 模型。
In [ ]!pip install paddlex==2.1.0!pip install scikit-image登录后复制 In [ ]
import paddleimport paddlex as pdxfrom paddlex import transforms as Timport shutilimport globimport osimport numpy as npimport pandas as pdimport cv2from PIL import Imageimport skimageimport matplotlib.pyplot as plt%matplotlib inline登录后复制
考虑到笔者不想重新训练行人跟踪模型,所以将要手动灌入权重等信息,导出为部署模型,但是 PaddleX 不提供接口支持,所以就自己实现。
首先是模型框架搭建,注意 “backbone” 要和预训练 “ESNet_l” 相对应,然后将参数灌入。
In [ ]def set_model_params(model, params_path): param_state_dict = paddle.load(params_path) model_state_dict = model.net.state_dict() for k in param_state_dict.keys(): if 'backbone.res5' in k: new_k = k.replace('backbone', 'bbox_head.head') if new_k in model_state_dict: value = param_state_dict.pop(k) param_state_dict[new_k] = value num_params_loaded = 0 for k in model_state_dict: if k not in param_state_dict: print("{} is not in pretrained model".format(k)) elif list(param_state_dict[k].shape) != list(model_state_dict[k].shape): print("[SKIP] Shape of pretrained params {} doesn't match.(Pretrained: {}, Actual: {})" .format(k, param_state_dict[k].shape, model_state_dict[k].shape)) else: model_state_dict[k] = param_state_dict[k] num_params_loaded += 1 model.net.set_state_dict(model_state_dict) print("There are {}/{} variables loaded into PicoDet.".format(num_params_loaded, len(model_state_dict))) return model登录后复制 In [ ]model = pdx.det.PicoDet(backbone='ESNet_l')model = set_model_params(model, params_path='work/pretrained/picodet_l_640_coco.pdparams')登录后复制
There are 660/660 variables loaded into PicoDet.登录后复制
因为没有训练集,所以也就没有标签和评估变换,这也是需要手动赋予的。
In [ ]model.labels = [ 'person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush']from paddlex import transforms as Tmodel.test_transforms = T.Compose([ T.Resize(target_size=640, interp='CUBIC'), T.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])])登录后复制
