未验证 提交 13c1fef1 编写于 作者: F Feng Ni 提交者: GitHub

[MOT] add MOT feature models (#4105)

* add pedestrian vehicle cfgs

* fix metric category

* fix mot metric

* fix mot metric

* update pedestrian and vehicle modelzoo

* update headtracking modelzoo

* add tools for data processing

* add data pre-process code

* fix tools code format
上级 afa7c14d
......@@ -136,7 +136,7 @@ If you use a stronger detection model, you can get better results. Each txt is t
FairMOT DLA-34 used 2 GPUs for training and mini-batch size as 6 on each GPU, and trained for 30 epoches.
### FairMOT light model
### FairMOT light model
### Results on MOT-16 Test Set
| backbone | input shape | MOTA | IDF1 | IDS | FP | FN | FPS | download | config |
| :--------------| :------- | :----: | :----: | :----: | :----: | :----: | :------: | :----: |:-----: |
......@@ -158,20 +158,27 @@ If you use a stronger detection model, you can get better results. Each txt is t
### FairMOT Results on HT-21 Training Set
| backbone | input shape | MOTA | IDF1 | IDS | FP | FN | FPS | download | config |
| :--------------| :------- | :----: | :----: | :---: | :----: | :---: | :------: | :----: |:----: |
| DLA-34 | 1088x608 | 67.2 | 70.4 | 9403 | 124840 | 255007 | - | [model](https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_headtracking21.pdparams) | [config](https://github.com/PaddlePaddle/PaddleDetection/tree/develop/configs/mot/headtracking21/fairmot_dla34_30e_1088x608_headtracking21.yml) |
| DLA-34 | 1088x608 | 64.7 | 69.0 | 8533 | 148817 | 234970 | - | [model](https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_headtracking21.pdparams) | [config](https://github.com/PaddlePaddle/PaddleDetection/tree/develop/configs/mot/headtracking21/fairmot_dla34_30e_1088x608_headtracking21.yml) |
### FairMOT Results on HT-21 Test Set
| backbone | input shape | MOTA | IDF1 | IDS | FP | FN | FPS | download | config |
| :--------------| :------- | :----: | :----: | :----: | :----: | :----: |:-------: | :----: | :----: |
| DLA-34 | 1088x608 | 58.2 | 61.3 | 13166 | 141872 | 197074 | - | [model](https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_headtracking21.pdparams) | [config](https://github.com/PaddlePaddle/PaddleDetection/tree/develop/configs/mot/headtracking21/fairmot_dla34_30e_1088x608_headtracking21.yml) |
### [Vehicle Tracking](./kitticars/README.md)
### FairMOT Results on KITTI tracking (2D bounding-boxes) Training Set (Car)
| backbone | input shape | MOTA | FPS | download | config |
| :--------------| :------- | :-----: | :-----: | :------: | :----: |
| DLA-34 | 1088x608 | 53.9 | - |[model](https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_kitticars.pdparams) | [config](https://github.com/PaddlePaddle/PaddleDetection/tree/develop/configs/mot/kitticars/fairmot_dla34_30e_1088x608_kitticars.yml) |
| DLA-34 | 1088x608 | 60.8 | 62.8 | 12781 | 118109 | 198896 | - | [model](https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_headtracking21.pdparams) | [config](https://github.com/PaddlePaddle/PaddleDetection/tree/develop/configs/mot/headtracking21/fairmot_dla34_30e_1088x608_headtracking21.yml) |
### [Pedestrian Tracking](./pedestrian/README.md)
### FairMOT Results on each val-set of Pedestrian category
| Dataset | input shape | MOTA | IDF1 | FPS | download | config |
| :-------------| :------- | :----: | :----: | :----: | :-----: |:------: |
| PathTrack | 1088x608 | 44.9 | 59.3 | - |[model](https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_pathtrack.pdparams) | [config](https://github.com/PaddlePaddle/PaddleDetection/tree/develop/configs/mot/pedestrian/fairmot_dla34_30e_1088x608_pathtrack.yml) |
| VisDrone | 1088x608 | 49.2 | 63.1 | - | [model](https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_visdrone_pedestrian.pdparams) | [config](https://github.com/PaddlePaddle/PaddleDetection/tree/develop/configs/mot/pedestrian/fairmot_dla34_30e_1088x608_visdrone_pedestrian.yml) |
### [Vehicle Tracking](./vehicle/README.md)
### FairMOT Results on each val-set of Vehicle category
| Dataset | input shape | MOTA | IDF1 | FPS | download | config |
| :-------------| :------- | :----: | :----: | :----: | :-----: |:------: |
| BDD100K | 1088x608 | 34.9 | 39.9 | - | [model](https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_bdd100k_vehicle.pdparams) | [config](https://github.com/PaddlePaddle/PaddleDetection/tree/develop/configs/mot/vehicle/fairmot_dla34_30e_1088x608_bdd100k_vehicle.yml) |
| KITTI | 1088x608 | 53.9 | - | - |[model](https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_kitti_vehicle.pdparams) | [config](https://github.com/PaddlePaddle/PaddleDetection/tree/develop/configs/mot/vehicle/fairmot_dla34_30e_1088x608_kitti_vehicle.yml) |
| VisDrone | 1088x608 | 29.8 | 51.3 | - | [model](https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_visdrone_vehicle.pdparams) | [config](https://github.com/PaddlePaddle/PaddleDetection/tree/develop/configs/mot/vehicle/fairmot_dla34_30e_1088x608_visdrone_vehicle.yml) |
## Dataset Preparation
......
......@@ -154,23 +154,31 @@ wget https://dataset.bj.bcebos.com/mot/det_results_dir.zip
## 特色垂类跟踪模型
### [人头跟踪(Head Tracking)](./headtracking21/README.md)
### FairMOT在HT-21 Training Set上结果
| 骨干网络 | 输入尺寸 | MOTA | IDF1 | IDS | FP | FN | FPS | 下载链接 | 配置文件 |
| :--------------| :------- | :----: | :----: | :---: | :----: | :---: | :------: | :----: |:----: |
| DLA-34 | 1088x608 | 67.2 | 70.4 | 9403 | 124840 | 255007 | - | [下载链接](https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_headtracking21.pdparams) | [配置文件](https://github.com/PaddlePaddle/PaddleDetection/tree/develop/configs/mot/headtracking21/fairmot_dla34_30e_1088x608_headtracking21.yml) |
| DLA-34 | 1088x608 | 64.7 | 69.0 | 8533 | 148817 | 234970 | - | [下载链接](https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_headtracking21.pdparams) | [配置文件](https://github.com/PaddlePaddle/PaddleDetection/tree/develop/configs/mot/headtracking21/fairmot_dla34_30e_1088x608_headtracking21.yml) |
### FairMOT在HT-21 Test Set上结果
| 骨干网络 | 输入尺寸 | MOTA | IDF1 | IDS | FP | FN | FPS | 下载链接 | 配置文件 |
| :--------------| :------- | :----: | :----: | :----: | :----: | :----: |:-------: | :----: | :----: |
| DLA-34 | 1088x608 | 58.2 | 61.3 | 13166 | 141872 | 197074 | - | [下载链接](https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_headtracking21.pdparams) | [配置文件](https://github.com/PaddlePaddle/PaddleDetection/tree/develop/configs/mot/headtracking21/fairmot_dla34_30e_1088x608_headtracking21.yml) |
### [车辆跟踪 (Vehicle Tracking)](./kitticars/README.md)
### FairMOT在KITTI tracking (2D bounding-boxes) Training Set上Car类别的结果
| 骨干网络 | 输入尺寸 | MOTA | FPS | 下载链接 | 配置文件 |
| :--------------| :------- | :-----: | :-----: | :------: | :----: |
| DLA-34 | 1088x608 | 53.9 | - |[下载链接](https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_kitticars.pdparams) | [配置文件](https://github.com/PaddlePaddle/PaddleDetection/tree/develop/configs/mot/kitticars/fairmot_dla34_30e_1088x608_kitticars.yml) |
| DLA-34 | 1088x608 | 60.8 | 62.8 | 12781 | 118109 | 198896 | - | [下载链接](https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_headtracking21.pdparams) | [配置文件](https://github.com/PaddlePaddle/PaddleDetection/tree/develop/configs/mot/headtracking21/fairmot_dla34_30e_1088x608_headtracking21.yml) |
### [行人跟踪 (Pedestrian Tracking)](./pedestrian/README.md)
### FairMOT在各个数据集val-set上Pedestrian类别的结果
| 数据集 | 输入尺寸 | MOTA | IDF1 | FPS | 下载链接 | 配置文件 |
| :-------------| :------- | :----: | :----: | :----: | :-----: |:------: |
| PathTrack | 1088x608 | 44.9 | 59.3 | - |[下载链接](https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_pathtrack.pdparams) | [配置文件](https://github.com/PaddlePaddle/PaddleDetection/tree/develop/configs/mot/pedestrian/fairmot_dla34_30e_1088x608_pathtrack.yml) |
| VisDrone | 1088x608 | 49.2 | 63.1 | - | [下载链接](https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_visdrone_pedestrian.pdparams) | [配置文件](https://github.com/PaddlePaddle/PaddleDetection/tree/develop/configs/mot/pedestrian/fairmot_dla34_30e_1088x608_visdrone_pedestrian.yml) |
### [车辆跟踪 (Vehicle Tracking)](./vehicle/README.md)
### FairMOT在各个数据集val-set上Vehicle类别的结果
| 数据集 | 输入尺寸 | MOTA | IDF1 | FPS | 下载链接 | 配置文件 |
| :-------------| :------- | :----: | :----: | :----: | :-----: |:------: |
| BDD100K | 1088x608 | 34.9 | 39.9 | - | [下载链接](https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_bdd100k_vehicle.pdparams) | [配置文件](https://github.com/PaddlePaddle/PaddleDetection/tree/develop/configs/mot/vehicle/fairmot_dla34_30e_1088x608_bdd100k_vehicle.yml) |
| KITTI | 1088x608 | 53.9 | - | - |[下载链接](https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_kitti_vehicle.pdparams) | [配置文件](https://github.com/PaddlePaddle/PaddleDetection/tree/develop/configs/mot/vehicle/fairmot_dla34_30e_1088x608_kitti_vehicle.yml) |
| VisDrone | 1088x608 | 29.8 | 51.3 | - | [下载链接](https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_visdrone_vehicle.pdparams) | [配置文件](https://github.com/PaddlePaddle/PaddleDetection/tree/develop/configs/mot/vehicle/fairmot_dla34_30e_1088x608_visdrone_vehicle.yml) |
## 数据集准备
......
......@@ -36,7 +36,7 @@ English | [简体中文](README_cn.md)
**Notes:**
FairMOT DLA-34 used 2 GPUs for training and mini-batch size as 6 on each GPU, and trained for 30 epoches.
### FairMOT light model
### FairMOT light model
### Results on MOT-16 Test Set
| backbone | input shape | MOTA | IDF1 | IDS | FP | FN | FPS | download | config |
| :--------------| :------- | :----: | :----: | :----: | :----: | :----: | :------: | :----: |:-----: |
......
......@@ -13,15 +13,15 @@
### FairMOT在HT-21 Training Set上结果
| 骨干网络 | 输入尺寸 | MOTA | IDF1 | IDS | FP | FN | FPS | 下载链接 | 配置文件 |
| :--------------| :------- | :----: | :----: | :---: | :----: | :---: | :------: | :----: |:----: |
| DLA-34 | 1088x608 | 67.2 | 70.4 | 9403 | 124840 | 255007 | - | [下载链接](https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_headtracking21.pdparams) | [配置文件](https://github.com/PaddlePaddle/PaddleDetection/tree/develop/configs/mot/headtracking21/fairmot_dla34_30e_1088x608_headtracking21.yml) |
| DLA-34 | 1088x608 | 64.7 | 69.0 | 8533 | 148817 | 234970 | - | [下载链接](https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_headtracking21.pdparams) | [配置文件](./fairmot_dla34_30e_1088x608_headtracking21.yml) |
### FairMOT在HT-21 Test Set上结果
| 骨干网络 | 输入尺寸 | MOTA | IDF1 | IDS | FP | FN | FPS | 下载链接 | 配置文件 |
| :--------------| :------- | :----: | :----: | :----: | :----: | :----: |:-------: | :----: | :----: |
| DLA-34 | 1088x608 | 58.2 | 61.3 | 13166 | 141872 | 197074 | - | [下载链接](https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_headtracking21.pdparams) | [配置文件](https://github.com/PaddlePaddle/PaddleDetection/tree/develop/configs/mot/headtracking21/fairmot_dla34_30e_1088x608_headtracking21.yml) |
| DLA-34 | 1088x608 | 60.8 | 62.8 | 12781 | 118109 | 198896 | - | [下载链接](https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_headtracking21.pdparams) | [配置文件](./fairmot_dla34_30e_1088x608_headtracking21.yml) |
**注意:**
FairMOT使用2个GPU进行训练,每个GPU上batch size为6,训练30个epoch
FairMOT DLA-34使用2个GPU进行训练,每个GPU上batch size为6,训练30个epoch。目前MOTA精度位于MOT官网[Head Tracking 21](https://motchallenge.net/results/Head_Tracking_21)榜单榜首
## 快速开始
......
[English](README.md) | 简体中文
# 特色垂类跟踪模型
## 车辆跟踪 (Vehicle Tracking)
车辆跟踪的主要应用之一是交通监控。
[KITTI-Tracking](http://www.cvlibs.net/datasets/kitti/eval_tracking.php)是一个包含市区、乡村和高速公路等场景采集的数据集,每张图像中最多达15辆车和30个行人,还有各种程度的遮挡与截断。其中用于目标跟踪的数据集一共有50个视频序列,21个为训练集,29个为测试集,目标是估计类别“Car”和”Pedestrian“的目标轨迹,此处只使用类别“Car”。
<div align="center">
<img src="../../../docs/images/kitticars_fairmot.gif" width='800'/>
</div>
## 模型库
### FairMOT在KITTI tracking (2D bounding-boxes) Training Set上Car类别的结果
| 骨干网络 | 输入尺寸 | MOTA | FPS | 下载链接 | 配置文件 |
| :--------------| :------- | :-----: | :-----: | :------: | :----: |
| DLA-34 | 1088x608 | 53.9 | - |[下载链接](https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_kitticars.pdparams) | [配置文件](https://github.com/PaddlePaddle/PaddleDetection/tree/develop/configs/mot/kitticars/fairmot_dla34_30e_1088x608_kitticars.yml) |
**注意:**
FairMOT使用2个GPU进行训练,每个GPU上batch size为6,训练30个epoch。
## 快速开始
### 1. 训练
使用2个GPU通过如下命令一键式启动训练
```bash
python -m paddle.distributed.launch --log_dir=./fairmot_dla34_30e_1088x608_kitticars/ --gpus 0,1 tools/train.py -c configs/mot/kitticars/fairmot_dla34_30e_1088x608_kitticars.yml
```
### 2. 评估
使用单张GPU通过如下命令一键式启动评估
```bash
# 使用PaddleDetection发布的权重
CUDA_VISIBLE_DEVICES=0 python tools/eval_mot.py -c configs/mot/kitticars/fairmot_dla34_30e_1088x608_kitticars.yml -o weights=https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_kitticars.pdparams
# 使用训练保存的checkpoint
CUDA_VISIBLE_DEVICES=0 python tools/eval_mot.py -c configs/mot/kitticars/fairmot_dla34_30e_1088x608_kitticars.yml -o weights=output/fairmot_dla34_30e_1088x608_kitticars/model_final.pdparams
```
### 3. 预测
使用单个GPU通过如下命令预测一个视频,并保存为视频
```bash
# 预测一个视频
CUDA_VISIBLE_DEVICES=0 python tools/infer_mot.py -c configs/mot/kitticars/fairmot_dla34_30e_1088x608_kitticars.yml -o weights=https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_kitticars.pdparams --video_file={your video name}.mp4 --save_videos
```
**注意:**
请先确保已经安装了[ffmpeg](https://ffmpeg.org/ffmpeg.html), Linux(Ubuntu)平台可以直接用以下命令安装:`apt-get update && apt-get install -y ffmpeg`
### 4. 导出预测模型
```bash
CUDA_VISIBLE_DEVICES=0 python tools/export_model.py -c configs/mot/kitticars/fairmot_dla34_30e_1088x608_kitticars.yml -o weights=https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_kitticars.pdparams
```
### 5. 用导出的模型基于Python去预测
```bash
python deploy/python/mot_jde_infer.py --model_dir=output_inference/fairmot_dla34_30e_1088x608_kitticars --video_file={your video name}.mp4 --device=GPU --save_mot_txts
```
**注意:**
跟踪模型是对视频进行预测,不支持单张图的预测,默认保存跟踪结果可视化后的视频,可添加`--save_mot_txts`表示保存跟踪结果的txt文件,或`--save_images`表示保存跟踪结果可视化图片。
## 引用
```
@article{zhang2020fair,
title={FairMOT: On the Fairness of Detection and Re-Identification in Multiple Object Tracking},
author={Zhang, Yifu and Wang, Chunyu and Wang, Xinggang and Zeng, Wenjun and Liu, Wenyu},
journal={arXiv preprint arXiv:2004.01888},
year={2020}
}
@INPROCEEDINGS{Geiger2012CVPR,
author = {Andreas Geiger and Philip Lenz and Raquel Urtasun},
title = {Are we ready for Autonomous Driving? The KITTI Vision Benchmark Suite},
booktitle = {Conference on Computer Vision and Pattern Recognition (CVPR)},
year = {2012}
}
```
[English](README.md) | 简体中文
# 特色垂类跟踪模型
## 大规模行人跟踪 (Pedestrian Tracking)
行人跟踪的主要应用之一是交通监控。
[PathTrack](https://www.trace.ethz.ch/publications/2017/pathtrack/index.html)包含720个视频序列,有着超过15000个行人的轨迹。包含了街景、舞蹈、体育运动、采访等各种场景的,大部分是移动摄像头拍摄场景。该数据集只有Pedestrian一类标注作为跟踪任务。
[VisDrone](http://aiskyeye.com)是无人机视角拍摄的数据集,是以俯视视角为主。该数据集涵盖不同位置(取自中国数千个相距数千公里的14个不同城市)、不同环境(城市和乡村)、不同物体(行人、车辆、自行车等)和不同密度(稀疏和拥挤的场景)。[VisDrone2019-MOT](https://github.com/VisDrone/VisDrone-Dataset)包含56个视频序列用于训练,7个视频序列用于验证。此处针对VisDrone2019-MOT多目标跟踪数据集进行提取,抽取出类别为pedestrian和people的数据组合成一个大的Pedestrian类别。
## 模型库
### FairMOT在各个数据集val-set上Pedestrian类别的结果
| 数据集 | 输入尺寸 | MOTA | IDF1 | FPS | 下载链接 | 配置文件 |
| :-------------| :------- | :----: | :----: | :----: | :-----: |:------: |
| PathTrack | 1088x608 | 44.9 | 59.3 | - |[下载链接](https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_pathtrack.pdparams) | [配置文件](./fairmot_dla34_30e_1088x608_pathtrack.yml) |
| VisDrone | 1088x608 | 49.2 | 63.1 | - | [下载链接](https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_visdrone_pedestrian.pdparams) | [配置文件](./fairmot_dla34_30e_1088x608_visdrone_pedestrian.yml) |
**注意:**
FairMOT均使用DLA-34为骨干网络,2个GPU进行训练,每个GPU上batch size为6,训练30个epoch。
## 数据集准备和处理
### 1、数据集处理代码说明
代码统一都在tools目录下
```
# visdrone
tools/visdrone/visdrone2mot.py: 生成visdrone_pedestrian据集
```
### 2、visdrone_pedestrian数据集处理
```
# 复制tool/visdrone/visdrone2mot.py到数据集目录下
# 生成visdrone_pedestrian MOT格式的数据,抽取类别classes=1,2 (pedestrian, people)
<<--生成前目录-->>
├── VisDrone2019-MOT-val
│ ├── annotations
│ ├── sequences
│ ├── visdrone2mot.py
<<--生成后目录-->>
├── VisDrone2019-MOT-val
│ ├── annotations
│ ├── sequences
│ ├── visdrone2mot.py
│ ├── visdrone_pedestrian
│ │ ├── images
│ │ │ ├── val
│ │ ├── labels_with_ids
│ │ │ ├── val
# 执行
python visdrone2mot.py --transMot=True --data_name=visdrone_pedestrian --phase=val
python visdrone2mot.py --transMot=True --data_name=visdrone_pedestrian --phase=train
```
## 快速开始
### 1. 训练
使用2个GPU通过如下命令一键式启动训练
```bash
python -m paddle.distributed.launch --log_dir=./fairmot_dla34_30e_1088x608_pathtrack/ --gpus 0,1 tools/train.py -c configs/mot/pedestrian/fairmot_dla34_30e_1088x608_pathtrack.yml
```
### 2. 评估
使用单张GPU通过如下命令一键式启动评估
```bash
# 使用PaddleDetection发布的权重
CUDA_VISIBLE_DEVICES=0 python tools/eval_mot.py -c configs/mot/pedestrian/fairmot_dla34_30e_1088x608_pathtrack.yml -o weights=https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_pathtrack.pdparams
# 使用训练保存的checkpoint
CUDA_VISIBLE_DEVICES=0 python tools/eval_mot.py -c configs/mot/pedestrian/fairmot_dla34_30e_1088x608_pathtrack.yml -o weights=output/fairmot_dla34_30e_1088x608_pathtrack/model_final.pdparams
```
### 3. 预测
使用单个GPU通过如下命令预测一个视频,并保存为视频
```bash
# 预测一个视频
CUDA_VISIBLE_DEVICES=0 python tools/infer_mot.py -c configs/mot/pedestrian/fairmot_dla34_30e_1088x608_pathtrack.yml -o weights=https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_pathtrack.pdparams --video_file={your video name}.mp4 --save_videos
```
**注意:**
请先确保已经安装了[ffmpeg](https://ffmpeg.org/ffmpeg.html), Linux(Ubuntu)平台可以直接用以下命令安装:`apt-get update && apt-get install -y ffmpeg`
### 4. 导出预测模型
```bash
CUDA_VISIBLE_DEVICES=0 python tools/export_model.py -c configs/mot/pedestrian/fairmot_dla34_30e_1088x608_pathtrack.yml -o weights=https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_pathtrack.pdparams
```
### 5. 用导出的模型基于Python去预测
```bash
python deploy/python/mot_jde_infer.py --model_dir=output_inference/fairmot_dla34_30e_1088x608_pathtrack --video_file={your video name}.mp4 --device=GPU --save_mot_txts
```
**注意:**
跟踪模型是对视频进行预测,不支持单张图的预测,默认保存跟踪结果可视化后的视频,可添加`--save_mot_txts`表示保存跟踪结果的txt文件,或`--save_images`表示保存跟踪结果可视化图片。
## 引用
```
@article{zhang2020fair,
title={FairMOT: On the Fairness of Detection and Re-Identification in Multiple Object Tracking},
author={Zhang, Yifu and Wang, Chunyu and Wang, Xinggang and Zeng, Wenjun and Liu, Wenyu},
journal={arXiv preprint arXiv:2004.01888},
year={2020}
}
@INPROCEEDINGS{8237302,
author={S. {Manen} and M. {Gygli} and D. {Dai} and L. V. {Gool}},
booktitle={2017 IEEE International Conference on Computer Vision (ICCV)},
title={PathTrack: Fast Trajectory Annotation with Path Supervision},
year={2017},
volume={},
number={},
pages={290-299},
doi={10.1109/ICCV.2017.40},
ISSN={2380-7504},
month={Oct},}
@article{zhu2018vision,
title={Vision meets drones: A challenge},
author={Zhu, Pengfei and Wen, Longyin and Bian, Xiao and Ling, Haibin and Hu, Qinghua},
journal={arXiv preprint arXiv:1804.07437},
year={2018}
}
@article{zhu2020vision,
title={Vision Meets Drones: Past, Present and Future},
author={Zhu, Pengfei and Wen, Longyin and Du, Dawei and Bian, Xiao and Hu, Qinghua and Ling, Haibin},
journal={arXiv preprint arXiv:2001.06303},
year={2020}
}
```
_BASE_: [
'../fairmot/fairmot_dla34_30e_1088x608.yml'
]
weights: output/fairmot_dla34_30e_1088x608_pathtrack/model_final
# for MOT training
TrainDataset:
!MOTDataSet
dataset_dir: dataset/mot
image_lists: ['pathtrack.train']
data_fields: ['image', 'gt_bbox', 'gt_class', 'gt_ide']
# for MOT evaluation
# If you want to change the MOT evaluation dataset, please modify 'data_root'
EvalMOTDataset:
!MOTImageFolder
dataset_dir: dataset/mot
data_root: pathtrack/images/test
keep_ori_im: False # set True if save visualization images or video, or used in DeepSORT
# for MOT video inference
TestMOTDataset:
!MOTImageFolder
dataset_dir: dataset/mot
keep_ori_im: True # set True if save visualization images or video
_BASE_: [
'../fairmot/fairmot_dla34_30e_1088x608.yml'
]
weights: output/fairmot_dla34_30e_1088x608_visdrone_pedestrian/model_final
# for MOT training
TrainDataset:
!MOTDataSet
dataset_dir: dataset/mot
image_lists: ['visdrone_pedestrian.train']
data_fields: ['image', 'gt_bbox', 'gt_class', 'gt_ide']
# for MOT evaluation
# If you want to change the MOT evaluation dataset, please modify 'data_root'
EvalMOTDataset:
!MOTImageFolder
dataset_dir: dataset/mot
data_root: visdrone_pedestrian/images/val
keep_ori_im: False # set True if save visualization images or video, or used in DeepSORT
# for MOT video inference
TestMOTDataset:
!MOTImageFolder
dataset_dir: dataset/mot
keep_ori_im: True # set True if save visualization images or video
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import glob
import os
import os.path as osp
import cv2
import argparse
import numpy as np
import random
# The object category indicates the type of annotated object,
# (i.e., ignored regions(0), pedestrian(1), people(2), bicycle(3), car(4), van(5), truck(6), tricycle(7), awning-tricycle(8), bus(9), motor(10),others(11))
def mkdir_if_missing(d):
if not osp.exists(d):
os.makedirs(d)
def genGtFile(seqPath, outPath, classes=[]):
id_idx = 0
old_idx = -1
with open(seqPath, 'r') as singleSeqFile:
motLine = []
allLines = singleSeqFile.readlines()
for line in allLines:
line = line.replace('\n', '')
line = line.split(',')
# exclude occlusion!='2'
if line[-1] != '2' and line[7] in classes:
if old_idx != int(line[1]):
id_idx += 1
old_idx = int(line[1])
newLine = line[0:6]
newLine[1] = str(id_idx)
newLine.append('1')
if (len(classes) > 1):
class_index = str(classes.index(line[7]) + 1)
newLine.append(class_index)
else:
newLine.append('1') # use permenant class '1'
newLine.append('1')
motLine.append(newLine)
mkdir_if_missing(outPath)
gtFilePath = osp.join(outPath, 'gt.txt')
with open(gtFilePath, 'w') as gtFile:
motLine = list(map(lambda x: str.join(',', x), motLine))
motLineStr = str.join('\n', motLine)
gtFile.write(motLineStr)
def genSeqInfo(img1Path, seqName):
imgPaths = glob.glob(img1Path + '/*.jpg')
seqLength = len(imgPaths)
if seqLength > 0:
image1 = cv2.imread(imgPaths[0])
imgHeight = image1.shape[0]
imgWidth = image1.shape[1]
else:
imgHeight = 0
imgWidth = 0
seqInfoStr = f'''[Sequence]\nname={seqName}\nimDir=img1\nframeRate=30\nseqLength={seqLength}\nimWidth={imgWidth}\nimHeight={imgHeight}\nimExt=.jpg'''
seqInfoPath = img1Path.replace('/img1', '')
with open(seqInfoPath + '/seqinfo.ini', 'w') as seqFile:
seqFile.write(seqInfoStr)
def copyImg(img1Path, gtTxtPath, outputFileName):
with open(gtTxtPath, 'r') as gtFile:
allLines = gtFile.readlines()
imgList = []
for line in allLines:
imgIdx = int(line.split(',')[0])
if imgIdx not in imgList:
imgList.append(imgIdx)
seqName = gtTxtPath.replace('./{}/'.format(outputFileName),
'').replace('/gt/gt.txt', '')
sourceImgPath = osp.join('./sequences', seqName,
'{:07d}.jpg'.format(imgIdx))
os.system(f'cp {sourceImgPath} {img1Path}')
def genMotLabels(datasetPath, outputFileName, classes=['2']):
mkdir_if_missing(osp.join(datasetPath, outputFileName))
annotationsPath = osp.join(datasetPath, 'annotations')
annotationsList = glob.glob(osp.join(annotationsPath, '*.txt'))
for annotationPath in annotationsList:
seqName = annotationPath.split('/')[-1].replace('.txt', '')
mkdir_if_missing(osp.join(datasetPath, outputFileName, seqName, 'gt'))
mkdir_if_missing(osp.join(datasetPath, outputFileName, seqName, 'img1'))
genGtFile(annotationPath,
osp.join(datasetPath, outputFileName, seqName, 'gt'), classes)
img1Path = osp.join(datasetPath, outputFileName, seqName, 'img1')
gtTxtPath = osp.join(datasetPath, outputFileName, seqName, 'gt/gt.txt')
copyImg(img1Path, gtTxtPath, outputFileName)
genSeqInfo(img1Path, seqName)
def deleteFileWhichImg1IsEmpty(mot16Path, dataType='train'):
path = mot16Path
data_images_train = osp.join(path, 'images', f'{dataType}')
data_images_train_seqs = glob.glob(data_images_train + '/*')
if (len(data_images_train_seqs) == 0):
print('dataset is empty!')
for data_images_train_seq in data_images_train_seqs:
data_images_train_seq_img1 = osp.join(data_images_train_seq, 'img1')
if len(glob.glob(data_images_train_seq_img1 + '/*.jpg')) == 0:
print(f"os.system(rm -rf {data_images_train_seq})")
os.system(f'rm -rf {data_images_train_seq}')
def formatMot16Path(dataPath, pathType='train'):
train_path = osp.join(dataPath, 'images', pathType)
mkdir_if_missing(train_path)
os.system(f'mv {dataPath}/* {train_path}')
def VisualGt(dataPath, phase='train'):
seqList = sorted(glob.glob(osp.join(dataPath, 'images', phase) + '/*'))
seqIndex = random.randint(0, len(seqList) - 1)
seqPath = seqList[seqIndex]
gt_path = osp.join(seqPath, 'gt', 'gt.txt')
img_list_path = sorted(glob.glob(osp.join(seqPath, 'img1', '*.jpg')))
imgIndex = random.randint(0, len(img_list_path))
img_Path = img_list_path[imgIndex]
frame_value = int(img_Path.split('/')[-1].replace('.jpg', ''))
gt_value = np.loadtxt(gt_path, dtype=int, delimiter=',')
gt_value = gt_value[gt_value[:, 0] == frame_value]
get_list = gt_value.tolist()
img = cv2.imread(img_Path)
colors = [[255, 0, 0], [255, 255, 0], [255, 0, 255], [0, 255, 0],
[0, 255, 255], [0, 0, 255]]
for seq, _id, pl, pt, w, h, _, bbox_class, _ in get_list:
cv2.putText(img,
str(bbox_class), (pl, pt), cv2.FONT_HERSHEY_PLAIN, 2,
colors[bbox_class - 1])
cv2.rectangle(
img, (pl, pt), (pl + w, pt + h),
colors[bbox_class - 1],
thickness=2)
cv2.imwrite('testGt.jpg', img)
def VisualDataset(datasetPath, phase='train', seqName='', frameId=1):
trainPath = osp.join(datasetPath, 'labels_with_ids', phase)
seq1Paths = osp.join(trainPath, seqName)
seq_img1_path = osp.join(seq1Paths, 'img1')
label_with_idPath = osp.join(seq_img1_path, '%07d' % frameId) + '.txt'
image_path = label_with_idPath.replace('labels_with_ids', 'images').replace(
'.txt', '.jpg')
seqInfoPath = str.join('/', image_path.split('/')[:-2])
seqInfoPath = seqInfoPath + '/seqinfo.ini'
seq_info = open(seqInfoPath).read()
width = int(seq_info[seq_info.find('imWidth=') + 8:seq_info.find(
'\nimHeight')])
height = int(seq_info[seq_info.find('imHeight=') + 9:seq_info.find(
'\nimExt')])
with open(label_with_idPath, 'r') as label:
allLines = label.readlines()
images = cv2.imread(image_path)
for line in allLines:
line = line.split(' ')
line = list(map(lambda x: float(x), line))
c1, c2, w, h = line[2:6]
x1 = c1 - w / 2
x2 = c2 - h / 2
x3 = c1 + w / 2
x4 = c2 + h / 2
cv2.rectangle(
images, (int(x1 * width), int(x2 * height)),
(int(x3 * width), int(x4 * height)), (255, 0, 0),
thickness=2)
cv2.imwrite('test.jpg', images)
def gen_image_list(dataPath, datType):
inputPath = f'{dataPath}/images/{datType}'
pathList = glob.glob(inputPath + '/*')
pathList = sorted(pathList)
allImageList = []
for pathSingle in pathList:
imgList = sorted(glob.glob(osp.join(pathSingle, 'img1', '*.jpg')))
for imgPath in imgList:
allImageList.append(imgPath)
with open(f'{dataPath}.{datType}', 'w') as image_list_file:
allImageListStr = str.join('\n', allImageList)
image_list_file.write(allImageListStr)
def gen_labels_mot(MOT_data, phase='train'):
seq_root = './{}/images/{}'.format(MOT_data, phase)
label_root = './{}/labels_with_ids/{}'.format(MOT_data, phase)
mkdir_if_missing(label_root)
seqs = [s for s in os.listdir(seq_root)]
print('seqs => ', seqs)
tid_curr = 0
tid_last = -1
for seq in seqs:
seq_info = open(osp.join(seq_root, seq, 'seqinfo.ini')).read()
seq_width = int(seq_info[seq_info.find('imWidth=') + 8:seq_info.find(
'\nimHeight')])
seq_height = int(seq_info[seq_info.find('imHeight=') + 9:seq_info.find(
'\nimExt')])
gt_txt = osp.join(seq_root, seq, 'gt', 'gt.txt')
gt = np.loadtxt(gt_txt, dtype=np.float64, delimiter=',')
seq_label_root = osp.join(label_root, seq, 'img1')
mkdir_if_missing(seq_label_root)
for fid, tid, x, y, w, h, mark, label, _ in gt:
# if mark == 0 or not label == 1:
# continue
fid = int(fid)
tid = int(tid)
if not tid == tid_last:
tid_curr += 1
tid_last = tid
x += w / 2
y += h / 2
label_fpath = osp.join(seq_label_root, '{:07d}.txt'.format(fid))
label_str = '0 {:d} {:.6f} {:.6f} {:.6f} {:.6f}\n'.format(
tid_curr, x / seq_width, y / seq_height, w / seq_width,
h / seq_height)
with open(label_fpath, 'a') as f:
f.write(label_str)
def parse_arguments():
parser = argparse.ArgumentParser(description='input method')
parser.add_argument("--transMot", type=bool, default=False)
parser.add_argument("--genMot", type=bool, default=False)
parser.add_argument("--formatMotPath", type=bool, default=False)
parser.add_argument("--deleteEmpty", type=bool, default=False)
parser.add_argument("--genLabelsMot", type=bool, default=False)
parser.add_argument("--genImageList", type=bool, default=False)
parser.add_argument("--visualImg", type=bool, default=False)
parser.add_argument("--visualGt", type=bool, default=False)
parser.add_argument("--data_name", type=str, default='visdrone_pedestrain')
parser.add_argument("--phase", type=str, default='train')
parser.add_argument(
"--classes", type=str, default='1, 2') # pedestrian and people
return parser.parse_args()
if __name__ == "__main__":
args = parse_arguments()
classes = args.classes.split(',')
datasetPath = './'
dataName = args.data_name
phase = args.phase
if args.transMot:
genMotLabels(datasetPath, dataName, classes)
formatMot16Path(dataName, pathType=phase)
mot16Path = f'./{dataName}'
deleteFileWhichImg1IsEmpty(mot16Path, dataType=phase)
gen_labels_mot(dataName, phase=phase)
gen_image_list(dataName, phase)
if args.genMot:
genMotLabels(datasetPath, dataName, classes)
if args.formatMotPath:
formatMot16Path(dataName, pathType=phase)
if args.deleteEmpty:
mot16Path = f'./{dataName}'
deleteFileWhichImg1IsEmpty(mot16Path, dataType=phase)
if args.genLabelsMot:
gen_labels_mot(dataName, phase=phase)
if args.genImageList:
gen_image_list(dataName, phase)
if args.visualGt:
VisualGt(f'./{dataName}', phase)
if args.visualImg:
seqName = 'uav0000137_00458_v'
frameId = 43
VisualDataset(
f'./{dataName}', phase=phase, seqName=seqName, frameId=frameId)
README_cn.md
\ No newline at end of file
[English](README.md) | 简体中文
# 特色垂类跟踪模型
## 车辆跟踪 (Vehicle Tracking)
车辆跟踪的主要应用之一是交通监控。在监控场景中,大多是从公共区域的监控摄像头视角拍摄车辆,获取图像后再进行车辆检测和跟踪。
[BDD100K](https://www.bdd100k.com)是伯克利大学AI实验室(BAIR)提出的一个驾驶视频数据集,是以驾驶员视角为主。该数据集不仅分多类别标注,还分晴天、多云等六种天气,住宅区、公路等六种场景,白天、夜晚等三个时间段,以及是否遮挡、是否截断。BDD100K MOT数据集包含1400个视频序列用于训练,200个视频序列用于验证。每个视频序列大约40秒长,每秒5帧,因此每个视频大约有200帧。此处针对BDD100K MOT数据集进行提取,抽取出类别为car, truck, bus, trailer, other vehicle的数据组合成一个Vehicle类别。
[KITTI](http://www.cvlibs.net/datasets/kitti)是一个包含市区、乡村和高速公路等场景采集的数据集,每张图像中最多达15辆车和30个行人,还有各种程度的遮挡与截断。[KITTI-Tracking](http://www.cvlibs.net/datasets/kitti/eval_tracking.php)(2D bounding-boxes)数据集一共有50个视频序列,21个为训练集,29个为测试集,目标是估计类别Car和Pedestrian的目标轨迹,此处抽取出类别为Car的数据作为一个Vehicle类别。
[VisDrone](http://aiskyeye.com)是无人机视角拍摄的数据集,是以俯视视角为主。该数据集涵盖不同位置(取自中国数千个相距数千公里的14个不同城市)、不同环境(城市和乡村)、不同物体(行人、车辆、自行车等)和不同密度(稀疏和拥挤的场景)。[VisDrone2019-MOT](https://github.com/VisDrone/VisDrone-Dataset)包含56个视频序列用于训练,7个视频序列用于验证。此处针对VisDrone2019-MOT多目标跟踪数据集进行提取,抽取出类别为car、van、truck、bus的数据组合成一个Vehicle类别。
## 模型库
### FairMOT在各个数据集val-set上Vehicle类别的结果
| 数据集 | 输入尺寸 | MOTA | IDF1 | FPS | 下载链接 | 配置文件 |
| :-------------| :------- | :----: | :----: | :----: | :-----: |:------: |
| BDD100K | 1088x608 | 34.9 | 39.9 | - | [下载链接](https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_bdd100kmot_vehicle.pdparams) | [配置文件](./fairmot_dla34_30e_1088x608_bdd100kmot_vehicle.yml) |
| KITTI | 1088x608 | 53.9 | - | - |[下载链接](https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_kitti_vehicle.pdparams) | [配置文件](./fairmot_dla34_30e_1088x608_kitti_vehicle.yml) |
| VisDrone | 1088x608 | 29.8 | 51.3 | - | [下载链接](https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_visdrone_vehicle.pdparams) | [配置文件](./fairmot_dla34_30e_1088x608_visdrone_vehicle.yml) |
**注意:**
FairMOT均使用DLA-34为骨干网络,2个GPU进行训练,每个GPU上batch size为6,训练30个epoch。
## 数据集准备和处理
### 1、数据集处理代码说明
代码统一都在tools目录下
```
# bdd100kmot
tools/bdd100kmot/gen_bdd100kmot_vehicle.sh:通过执行bdd100k2mot.py和gen_labels_MOT.py生成bdd100kmot_vehicle 数据集
tools/bdd100kmot/bdd100k2mot.py:将bdd100k全集转换成mot格式
tools/bdd100kmot/gen_labels_MOT.py:生成单类别的labels_with_ids文件
# visdrone
tools/visdrone/visdrone2mot.py:生成visdrone_vehicle
```
### 2、bdd100k_vehicle数据集处理
```
# 复制tools/bdd100kmot里的代码到数据集目录下
# 生成bdd100kmot_vehicle MOT格式的数据,抽取类别classes=2,3,4,9,10 (car, truck, bus, trailer, other vehicle)
<<--生成前目录-->>
├── bdd100k_path
│ ├── images
│ ├── labels
<<--生成后目录-->>
├── bdd100k_path
│ ├── images
│ ├── labels
│ ├── bdd100kmot_vehicle
│ │ ├── images
│ │ │ ├── train
│ │ │ ├── val
│ │ ├── labels_with_ids
│ │ │ ├── train
│ │ │ ├── val
# 执行
sh gen_bdd100kmot_vehicle.sh
```
### 3、visdrone_vehicle数据集处理
```
# 复制tools/visdrone/visdrone2mot.py到数据集目录下
# 生成visdrone_vehicle MOT格式的数据,抽取类别classes=4,5,6,9 (car, van, truck, bus)
<<--生成前目录-->>
├── VisDrone2019-MOT-val
│ ├── annotations
│ ├── sequences
│ ├── visdrone2mot.py
<<--生成后目录-->>
├── VisDrone2019-MOT-val
│ ├── annotations
│ ├── sequences
│ ├── visdrone2mot.py
│ ├── visdrone-vehicle
│ │ ├── images
│ │ │ ├── val
│ │ ├── labels_with_ids
│ │ │ ├── val
# 执行
python visdrone2mot.py --transMot=True --data_name=visdrone_vehicle --phase=val
python visdrone2mot.py --transMot=True --data_name=visdrone_vehicle --phase=train
```
## 快速开始
### 1. 训练
使用2个GPU通过如下命令一键式启动训练
```bash
python -m paddle.distributed.launch --log_dir=./fairmot_dla34_30e_1088x608_bdd100k_vehicle/ --gpus 0,1 tools/train.py -c configs/mot/vehicle/fairmot_dla34_30e_1088x608_bdd100k_vehicle.yml
```
### 2. 评估
使用单张GPU通过如下命令一键式启动评估
```bash
# 使用PaddleDetection发布的权重
CUDA_VISIBLE_DEVICES=0 python tools/eval_mot.py -c configs/mot/vehicle/fairmot_dla34_30e_1088x608_bdd100k_vehicle.yml -o weights=https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_bdd100k_vehicle.pdparams
# 使用训练保存的checkpoint
CUDA_VISIBLE_DEVICES=0 python tools/eval_mot.py -c configs/mot/vehicle/fairmot_dla34_30e_1088x608_bdd100k_vehicle.yml -o weights=output/fairmot_dla34_30e_1088x608_bdd100k_vehicle/model_final.pdparams
```
### 3. 预测
使用单个GPU通过如下命令预测一个视频,并保存为视频
```bash
# 预测一个视频
CUDA_VISIBLE_DEVICES=0 python tools/infer_mot.py -c configs/mot/vehicle/fairmot_dla34_30e_1088x608_bdd100k_vehicle.yml -o weights=https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_bdd100k_vehicle.pdparams --video_file={your video name}.mp4 --save_videos
```
**注意:**
请先确保已经安装了[ffmpeg](https://ffmpeg.org/ffmpeg.html), Linux(Ubuntu)平台可以直接用以下命令安装:`apt-get update && apt-get install -y ffmpeg`
### 4. 导出预测模型
```bash
CUDA_VISIBLE_DEVICES=0 python tools/export_model.py -c configs/mot/vehicle/fairmot_dla34_30e_1088x608_bdd100k_vehicle.yml -o weights=https://paddledet.bj.bcebos.com/models/mot/fairmot_dla34_30e_1088x608_bdd100k_vehicle.pdparams
```
### 5. 用导出的模型基于Python去预测
```bash
python deploy/python/mot_jde_infer.py --model_dir=output_inference/fairmot_dla34_30e_1088x608_bdd100k_vehicle --video_file={your video name}.mp4 --device=GPU --save_mot_txts
```
**注意:**
跟踪模型是对视频进行预测,不支持单张图的预测,默认保存跟踪结果可视化后的视频,可添加`--save_mot_txts`表示保存跟踪结果的txt文件,或`--save_images`表示保存跟踪结果可视化图片。
## 引用
```
@article{zhang2020fair,
title={FairMOT: On the Fairness of Detection and Re-Identification in Multiple Object Tracking},
author={Zhang, Yifu and Wang, Chunyu and Wang, Xinggang and Zeng, Wenjun and Liu, Wenyu},
journal={arXiv preprint arXiv:2004.01888},
year={2020}
}
@InProceedings{bdd100k,
author = {Yu, Fisher and Chen, Haofeng and Wang, Xin and Xian, Wenqi and Chen,
Yingying and Liu, Fangchen and Madhavan, Vashisht and Darrell, Trevor},
title = {BDD100K: A Diverse Driving Dataset for Heterogeneous Multitask Learning},
booktitle = {IEEE/CVF Conference on Computer Vision and Pattern Recognition (CVPR)},
month = {June},
year = {2020}
}
@INPROCEEDINGS{Geiger2012CVPR,
author = {Andreas Geiger and Philip Lenz and Raquel Urtasun},
title = {Are we ready for Autonomous Driving? The KITTI Vision Benchmark Suite},
booktitle = {Conference on Computer Vision and Pattern Recognition (CVPR)},
year = {2012}
}
@article{zhu2018vision,
title={Vision meets drones: A challenge},
author={Zhu, Pengfei and Wen, Longyin and Bian, Xiao and Ling, Haibin and Hu, Qinghua},
journal={arXiv preprint arXiv:1804.07437},
year={2018}
}
@article{zhu2020vision,
title={Vision Meets Drones: Past, Present and Future},
author={Zhu, Pengfei and Wen, Longyin and Du, Dawei and Bian, Xiao and Hu, Qinghua and Ling, Haibin},
journal={arXiv preprint arXiv:2001.06303},
year={2020}
}
```
_BASE_: [
'../fairmot/fairmot_dla34_30e_1088x608.yml'
]
weights: output/fairmot_dla34_30e_1088x608_bdd100kmot_vehicle/model_final
# for MOT training
TrainDataset:
!MOTDataSet
dataset_dir: dataset/mot
image_lists: ['bdd100kmot_vehicle.train']
data_fields: ['image', 'gt_bbox', 'gt_class', 'gt_ide']
# for MOT evaluation
# If you want to change the MOT evaluation dataset, please modify 'data_root'
EvalMOTDataset:
!MOTImageFolder
dataset_dir: dataset/mot
data_root: bdd100kmot_vehicle/images/val
keep_ori_im: False # set True if save visualization images or video, or used in DeepSORT
# for MOT video inference
TestMOTDataset:
!MOTImageFolder
dataset_dir: dataset/mot
keep_ori_im: True # set True if save visualization images or video
......@@ -3,13 +3,13 @@ _BASE_: [
]
metric: KITTI
weights: output/fairmot_dla34_30e_1088x608_kitticars/model_final
weights: output/fairmot_dla34_30e_1088x608_kitti_vehicle/model_final
# for MOT training
TrainDataset:
!MOTDataSet
dataset_dir: dataset/mot
image_lists: ['kitticars.train']
image_lists: ['kitti_vehicle.train']
data_fields: ['image', 'gt_bbox', 'gt_class', 'gt_ide']
# for MOT evaluation
......@@ -17,7 +17,7 @@ TrainDataset:
EvalMOTDataset:
!MOTImageFolder
dataset_dir: dataset/mot
data_root: kitticars/images/test
data_root: kitti_vehicle/images/train
keep_ori_im: False # set True if save visualization images or video, or used in DeepSORT
# for MOT video inference
......
_BASE_: [
'../fairmot/fairmot_dla34_30e_1088x608.yml'
]
weights: output/fairmot_dla34_30e_1088x608_visdrone_vehicle/model_final
# for MOT training
TrainDataset:
!MOTDataSet
dataset_dir: dataset/mot
image_lists: ['visdrone_vehicle.train']
data_fields: ['image', 'gt_bbox', 'gt_class', 'gt_ide']
# for MOT evaluation
# If you want to change the MOT evaluation dataset, please modify 'data_root'
EvalMOTDataset:
!MOTImageFolder
dataset_dir: dataset/mot
data_root: visdrone_vehicle/images/val
keep_ori_im: False # set True if save visualization images or video, or used in DeepSORT
# for MOT video inference
TestMOTDataset:
!MOTImageFolder
dataset_dir: dataset/mot
keep_ori_im: True # set True if save visualization images or video
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import glob
import os
import os.path as osp
import cv2
import random
import numpy as np
import argparse
def mkdir_if_missing(d):
if not osp.exists(d):
os.makedirs(d)
def bdd2mot_tracking(img_dir, label_dir, save_img_dir, save_label_dir):
label_jsons = os.listdir(label_dir)
for label_json in tqdm(label_jsons):
with open(os.path.join(label_dir, label_json)) as f:
labels_json = json.load(f)
for label_json in labels_json:
img_name = label_json['name']
video_name = label_json['videoName']
labels = label_json['labels']
txt_string = ""
for label in labels:
category = label['category']
x1 = label['box2d']['x1']
x2 = label['box2d']['x2']
y1 = label['box2d']['y1']
y2 = label['box2d']['y2']
width = x2 - x1
height = y2 - y1
x_center = (x1 + x2) / 2. / args.width
y_center = (y1 + y2) / 2. / args.height
width /= args.width
height /= args.height
identity = int(label['id'])
# [class] [identity] [x_center] [y_center] [width] [height]
txt_string += "{} {} {} {} {} {}\n".format(
attr_id_dict[category], identity, x_center, y_center,
width, height)
fn_label = os.path.join(save_label_dir, img_name[:-4] + '.txt')
source_img = os.path.join(img_dir, video_name, img_name)
target_img = os.path.join(save_img_dir, img_name)
with open(fn_label, 'w') as f:
f.write(txt_string)
os.system('cp {} {}'.format(source_img, target_img))
def transBBOx(bbox):
# bbox --> cx cy w h
bbox = list(map(lambda x: float(x), bbox))
bbox[0] = (bbox[0] - bbox[2] / 2) * 1280
bbox[1] = (bbox[1] - bbox[3] / 2) * 720
bbox[2] = bbox[2] * 1280
bbox[3] = bbox[3] * 720
bbox = list(map(lambda x: str(x), bbox))
return bbox
def genSingleImageMot(inputPath, classes=[]):
labelPaths = glob.glob(inputPath + '/*.txt')
labelPaths = sorted(labelPaths)
allLines = []
result = {}
for labelPath in labelPaths:
frame = str(int(labelPath.split('-')[-1].replace('.txt', '')))
with open(labelPath, 'r') as labelPathFile:
lines = labelPathFile.readlines()
for line in lines:
line = line.replace('\n', '')
lineArray = line.split(' ')
if len(classes) > 0:
if lineArray[0] in classes:
lineArray.append(frame)
allLines.append(lineArray)
else:
lineArray.append(frame)
allLines.append(lineArray)
resultMap = {}
for line in allLines:
if line[1] not in resultMap.keys():
resultMap[line[1]] = []
resultMap[line[1]].append(line)
mot_gt = []
id_idx = 0
for rid in resultMap.keys():
id_idx += 1
for id_line in resultMap[rid]:
mot_line = []
mot_line.append(id_line[-1])
mot_line.append(str(id_idx))
id_line_temp = transBBOx(id_line[2:6])
mot_line.extend(id_line_temp)
mot_line.append('1')
# mot_line.append(id_line[0]) # origin class
mot_line.append('1') # permanent class => 1
mot_line.append('1')
mot_gt.append(mot_line)
result = list(map(lambda line: str.join(',', line), mot_gt))
resultStr = str.join('\n', result)
return resultStr
def writeGt(inputPath, outPath, classes=[]):
singleImageResult = genSingleImageMot(inputPath, classes=classes)
outPathFile = outPath + '/gt.txt'
mkdir_if_missing(outPath)
with open(outPathFile, 'w') as gtFile:
gtFile.write(singleImageResult)
def genSeqInfo(seqInfoPath):
name = seqInfoPath.split('/')[-2]
img1Path = osp.join(str.join('/', seqInfoPath.split('/')[0:-1]), 'img1')
seqLength = len(glob.glob(img1Path + '/*.jpg'))
seqInfoStr = f'''[Sequence]\nname={name}\nimDir=img1\nframeRate=30\nseqLength={seqLength}\nimWidth=1280\nimHeight=720\nimExt=.jpg'''
with open(seqInfoPath, 'w') as seqFile:
seqFile.write(seqInfoStr)
def genMotGt(dataDir, classes=[]):
seqLists = sorted(glob.glob(dataDir))
for seqList in seqLists:
inputPath = osp.join(seqList, 'img1')
outputPath = seqList.replace('labels_with_ids', 'images')
outputPath = osp.join(outputPath, 'gt')
mkdir_if_missing(outputPath)
print('processing...', outputPath)
writeGt(inputPath, outputPath, classes=classes)
seqList = seqList.replace('labels_with_ids', 'images')
seqInfoPath = osp.join(seqList, 'seqinfo.ini')
genSeqInfo(seqInfoPath)
def updateSeqInfo(dataDir, phase):
seqPath = osp.join(dataDir, 'labels_with_ids', phase)
seqList = glob.glob(seqPath + '/*')
for seqName in seqList:
print('seqName=>', seqName)
seqName_img1_dir = osp.join(seqName, 'img1')
txtLength = glob.glob(seqName_img1_dir + '/*.txt')
name = seqName.split('/')[-1].replace('.jpg', '').replace('.txt', '')
seqLength = len(txtLength)
seqInfoStr = f'''[Sequence]\nname={name}\nimDir=img1\nframeRate=30\nseqLength={seqLength}\nimWidth=1280\nimHeight=720\nimExt=.jpg'''
seqInfoPath = seqName_img1_dir.replace('labels_with_ids', 'images')
seqInfoPath = seqInfoPath.replace('/img1', '')
seqInfoPath = seqInfoPath + '/seqinfo.ini'
with open(seqInfoPath, 'w') as seqFile:
seqFile.write(seqInfoStr)
def VisualDataset(datasetPath, phase='train', seqName='', frameId=1):
trainPath = osp.join(datasetPath, 'labels_with_ids', phase)
seq1Paths = osp.join(trainPath, seqName)
seq_img1_path = osp.join(seq1Paths, 'img1')
label_with_idPath = osp.join(seq_img1_path, seqName + '-' + '%07d' %
frameId) + '.txt'
image_path = label_with_idPath.replace('labels_with_ids', 'images').replace(
'.txt', '.jpg')
seqInfoPath = str.join('/', image_path.split('/')[:-2])
seqInfoPath = seqInfoPath + '/seqinfo.ini'
seq_info = open(seqInfoPath).read()
width = int(seq_info[seq_info.find('imWidth=') + 8:seq_info.find(
'\nimHeight')])
height = int(seq_info[seq_info.find('imHeight=') + 9:seq_info.find(
'\nimExt')])
with open(label_with_idPath, 'r') as label:
allLines = label.readlines()
images = cv2.imread(image_path)
print('image_path => ', image_path)
for line in allLines:
line = line.split(' ')
line = list(map(lambda x: float(x), line))
c1, c2, w, h = line[2:6]
x1 = c1 - w / 2
x2 = c2 - h / 2
x3 = c1 + w / 2
x4 = c2 + h / 2
cv2.rectangle(
images, (int(x1 * width), int(x2 * height)),
(int(x3 * width), int(x4 * height)), (255, 0, 0),
thickness=2)
cv2.imwrite('test.jpg', images)
def VisualGt(dataPath, phase='train'):
seqList = sorted(glob.glob(osp.join(dataPath, 'images', phase) + '/*'))
seqIndex = random.randint(0, len(seqList) - 1)
seqPath = seqList[seqIndex]
gt_path = osp.join(seqPath, 'gt', 'gt.txt')
img_list_path = sorted(glob.glob(osp.join(seqPath, 'img1', '*.jpg')))
imgIndex = random.randint(0, len(img_list_path))
img_Path = img_list_path[imgIndex]
#
frame_value = img_Path.split('/')[-1].replace('.jpg', '')
frame_value = frame_value.split('-')[-1]
frame_value = int(frame_value)
seqNameStr = img_Path.split('/')[-1].replace('.jpg', '').replace('img', '')
frame_value = int(seqNameStr.split('-')[-1])
print('frame_value => ', frame_value)
gt_value = np.loadtxt(gt_path, dtype=float, delimiter=',')
gt_value = gt_value[gt_value[:, 0] == frame_value]
get_list = gt_value.tolist()
img = cv2.imread(img_Path)
colors = [[255, 0, 0], [255, 255, 0], [255, 0, 255], [0, 255, 0],
[0, 255, 255], [0, 0, 255]]
for seq, _id, pl, pt, w, h, _, bbox_class, _ in get_list:
pl, pt, w, h = int(pl), int(pt), int(w), int(h)
print('pl,pt,w,h => ', pl, pt, w, h)
cv2.putText(img,
str(bbox_class), (pl, pt), cv2.FONT_HERSHEY_PLAIN, 2,
colors[int(bbox_class - 1)])
cv2.rectangle(
img, (pl, pt), (pl + w, pt + h),
colors[int(bbox_class - 1)],
thickness=2)
cv2.imwrite('testGt.jpg', img)
print(seqPath, frame_value)
return seqPath.split('/')[-1], frame_value
def gen_image_list(dataPath, datType):
inputPath = f'{dataPath}/labels_with_ids/{datType}'
pathList = sorted(glob.glob(inputPath + '/*'))
print(pathList)
allImageList = []
for pathSingle in pathList:
imgList = sorted(glob.glob(osp.join(pathSingle, 'img1', '*.txt')))
for imgPath in imgList:
imgPath = imgPath.replace('labels_with_ids', 'images').replace(
'.txt', '.jpg')
allImageList.append(imgPath)
with open(f'{dataPath}.{datType}', 'w') as image_list_file:
allImageListStr = str.join('\n', allImageList)
image_list_file.write(allImageListStr)
def formatOrigin(datapath, phase):
label_with_idPath = osp.join(datapath, 'labels_with_ids', phase)
print(label_with_idPath)
for txtList in sorted(glob.glob(label_with_idPath + '/*.txt')):
print(txtList)
seqName = txtList.split('/')[-1]
seqName = str.join('-', seqName.split('-')[0:-1]).replace('.txt', '')
seqPath = osp.join(label_with_idPath, seqName, 'img1')
mkdir_if_missing(seqPath)
os.system(f'mv {txtList} {seqPath}')
def copyImg(fromRootPath, toRootPath, phase):
fromPath = osp.join(fromRootPath, 'images', phase)
toPathSeqPath = osp.join(toRootPath, 'labels_with_ids', phase)
seqList = sorted(glob.glob(toPathSeqPath + '/*'))
for seqPath in seqList:
seqName = seqPath.split('/')[-1]
imgTxtList = sorted(glob.glob(osp.join(seqPath, 'img1') + '/*.txt'))
img_toPathSeqPath = osp.join(seqPath, 'img1')
img_toPathSeqPath = img_toPathSeqPath.replace('labels_with_ids',
'images')
mkdir_if_missing(img_toPathSeqPath)
for imgTxt in imgTxtList:
imgName = imgTxt.split('/')[-1].replace('.txt', '.jpg')
imgfromPath = osp.join(fromPath, seqName, imgName)
print(f'cp {imgfromPath} {img_toPathSeqPath}')
os.system(f'cp {imgfromPath} {img_toPathSeqPath}')
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='BDD100K to MOT format')
parser.add_argument("--data_path", default='/path/to/bdd100k')
parser.add_argument("--phase", default='train')
parser.add_argument("--classes", default='2,3,4,9,10')
parser.add_argument("--img_dir", default="/path/to/bdd/image/")
parser.add_argument("--label_dir", default="/path/to/bdd/label/")
parser.add_argument("--save_path", default="/save/path")
parser.add_argument("--height", default=720)
parser.add_argument("--width", default=1280)
args = parser.parse_args()
### for bdd tracking dataset
attr_dict = dict()
attr_dict["categories"] = [{
"supercategory": "none",
"id": 0,
"name": "pedestrian"
}, {
"supercategory": "none",
"id": 1,
"name": "rider"
}, {
"supercategory": "none",
"id": 2,
"name": "car"
}, {
"supercategory": "none",
"id": 3,
"name": "truck"
}, {
"supercategory": "none",
"id": 4,
"name": "bus"
}, {
"supercategory": "none",
"id": 5,
"name": "train"
}, {
"supercategory": "none",
"id": 6,
"name": "motorcycle"
}, {
"supercategory": "none",
"id": 7,
"name": "bicycle"
}, {
"supercategory": "none",
"id": 8,
"name": "other person"
}, {
"supercategory": "none",
"id": 9,
"name": "trailer"
}, {
"supercategory": "none",
"id": 10,
"name": "other vehicle"
}]
attr_id_dict = {i['name']: i['id'] for i in attr_dict['categories']}
# create BDD training set tracking in MOT format
print('Loading and converting training set...')
train_img_dir = os.path.join(args.img_dir, 'train')
train_label_dir = os.path.join(args.label_dir, 'train')
save_img_dir = os.path.join(args.save_path, 'images', 'train')
save_label_dir = os.path.join(args.save_path, 'labels_with_ids', 'train')
if not os.path.exists(save_img_dir): os.makedirs(save_img_dir)
if not os.path.exists(save_label_dir): os.makedirs(save_label_dir)
bdd2mot_tracking(train_img_dir, train_label_dir, save_img_dir,
save_label_dir)
# create BDD validation set tracking in MOT format
print('Loading and converting validation set...')
val_img_dir = os.path.join(args.img_dir, 'val')
val_label_dir = os.path.join(args.label_dir, 'val')
save_img_dir = os.path.join(args.save_path, 'images', 'val')
save_label_dir = os.path.join(args.save_path, 'labels_with_ids', 'val')
if not os.path.exists(save_img_dir): os.makedirs(save_img_dir)
if not os.path.exists(save_label_dir): os.makedirs(save_label_dir)
bdd2mot_tracking(val_img_dir, val_label_dir, save_img_dir, save_label_dir)
# gen gt file
dataPath = args.data_path
phase = args.phase
classes = args.classes.split(',')
formatOrigin(osp.join(dataPath, 'bdd100kmot_vehicle'), phase)
dataDir = osp.join(
osp.join(dataPath, 'bdd100kmot_vehicle'), 'labels_with_ids',
phase) + '/*'
genMotGt(dataDir, classes=classes)
copyImg(dataPath, osp.join(dataPath, 'bdd100kmot_vehicle'), phase)
updateSeqInfo(osp.join(dataPath, 'bdd100kmot_vehicle'), phase)
gen_image_list(osp.join(dataPath, 'bdd100kmot_vehicle'), phase)
os.system(f'rm -r {dataPath}/bdd100kmot_vehicle/images/' + phase + '/*.jpg')
data_path=bdd100k_path
img_dir=${data_path}/images
label_dir=${data_path}/labels
save_path=${data_path}/bdd100kmot_vehicle
phasetrain=train
phaseval=val
classes=2,3,4,9,10
# gen mot dataste
python bdd100k2mot.py --data_path=${data_path} --phase=${phasetrain} --classes=${classes} --img_dir=${img_dir} --label_dir=${label_dir} --save_path=${save_path}
python bdd100k2mot.py --data_path=${data_path} --phase=${phaseval} --classes=${classes} --img_dir=${img_dir} --label_dir=${label_dir} --save_path=${save_path}
# gen new labels_with_ids
python gen_labels_MOT.py --mot_data=${data_path} --phase=${phasetrain}
python gen_labels_MOT.py --mot_data=${data_path} --phase=${phaseval}
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import os.path as osp
import numpy as np
import argparse
def mkdirs(d):
if not osp.exists(d):
os.makedirs(d)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='BDD100K to MOT format')
parser.add_argument(
"--mot_data", default='/paddle/dataset/bdd100kmot/bdd100k_small')
parser.add_argument("--phase", default='train')
args = parser.parse_args()
MOT_data = args.mot_data
phase = args.phase
seq_root = osp.join(MOT_data, 'bdd100kmot_vehicle', 'images', phase)
label_root = osp.join(MOT_data, 'bdd100kmot_vehicle', 'labels_with_ids',
phase)
mkdirs(label_root)
seqs = [s for s in os.listdir(seq_root)]
tid_curr = 0
tid_last = -1
os.system(f'rm -r {MOT_data}/bdd100kmot_vehicle/labels_with_ids')
for seq in seqs:
print('seq => ', seq)
seq_info = open(osp.join(seq_root, seq, 'seqinfo.ini')).read()
seq_width = int(seq_info[seq_info.find('imWidth=') + 8:seq_info.find(
'\nimHeight')])
seq_height = int(seq_info[seq_info.find('imHeight=') + 9:seq_info.find(
'\nimExt')])
gt_txt = osp.join(seq_root, seq, 'gt', 'gt.txt')
gt = np.loadtxt(gt_txt, dtype=np.float64, delimiter=',')
seq_label_root = osp.join(label_root, seq, 'img1')
mkdirs(seq_label_root)
for fid, tid, x, y, w, h, mark, label, _ in gt:
fid = int(fid)
tid = int(tid)
if not tid == tid_last:
tid_curr += 1
tid_last = tid
x += w / 2
y += h / 2
label_fpath = osp.join(seq_label_root,
seq + '-' + '{:07d}.txt'.format(fid))
label_str = '0 {:d} {:.6f} {:.6f} {:.6f} {:.6f}\n'.format(
tid_curr, x / seq_width, y / seq_height, w / seq_width,
h / seq_height)
with open(label_fpath, 'a') as f:
f.write(label_str)
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import glob
import os
import os.path as osp
import cv2
import argparse
import numpy as np
import random
# The object category indicates the type of annotated object,
# (i.e., ignored regions(0), pedestrian(1), people(2), bicycle(3), car(4), van(5), truck(6), tricycle(7), awning-tricycle(8), bus(9), motor(10),others(11))
def mkdir_if_missing(d):
if not osp.exists(d):
os.makedirs(d)
def genGtFile(seqPath, outPath, classes=[]):
id_idx = 0
old_idx = -1
with open(seqPath, 'r') as singleSeqFile:
motLine = []
allLines = singleSeqFile.readlines()
for line in allLines:
line = line.replace('\n', '')
line = line.split(',')
# exclude occlusion!='2'
if line[-1] != '2' and line[7] in classes:
if old_idx != int(line[1]):
id_idx += 1
old_idx = int(line[1])
newLine = line[0:6]
newLine[1] = str(id_idx)
newLine.append('1')
if (len(classes) > 1):
class_index = str(classes.index(line[7]) + 1)
newLine.append(class_index)
else:
newLine.append('1') # use permenant class '1'
newLine.append('1')
motLine.append(newLine)
mkdir_if_missing(outPath)
gtFilePath = osp.join(outPath, 'gt.txt')
with open(gtFilePath, 'w') as gtFile:
motLine = list(map(lambda x: str.join(',', x), motLine))
motLineStr = str.join('\n', motLine)
gtFile.write(motLineStr)
def genSeqInfo(img1Path, seqName):
imgPaths = glob.glob(img1Path + '/*.jpg')
seqLength = len(imgPaths)
if seqLength > 0:
image1 = cv2.imread(imgPaths[0])
imgHeight = image1.shape[0]
imgWidth = image1.shape[1]
else:
imgHeight = 0
imgWidth = 0
seqInfoStr = f'''[Sequence]\nname={seqName}\nimDir=img1\nframeRate=30\nseqLength={seqLength}\nimWidth={imgWidth}\nimHeight={imgHeight}\nimExt=.jpg'''
seqInfoPath = img1Path.replace('/img1', '')
with open(seqInfoPath + '/seqinfo.ini', 'w') as seqFile:
seqFile.write(seqInfoStr)
def copyImg(img1Path, gtTxtPath, outputFileName):
with open(gtTxtPath, 'r') as gtFile:
allLines = gtFile.readlines()
imgList = []
for line in allLines:
imgIdx = int(line.split(',')[0])
if imgIdx not in imgList:
imgList.append(imgIdx)
seqName = gtTxtPath.replace('./{}/'.format(outputFileName),
'').replace('/gt/gt.txt', '')
sourceImgPath = osp.join('./sequences', seqName,
'{:07d}.jpg'.format(imgIdx))
os.system(f'cp {sourceImgPath} {img1Path}')
def genMotLabels(datasetPath, outputFileName, classes=['2']):
mkdir_if_missing(osp.join(datasetPath, outputFileName))
annotationsPath = osp.join(datasetPath, 'annotations')
annotationsList = glob.glob(osp.join(annotationsPath, '*.txt'))
for annotationPath in annotationsList:
seqName = annotationPath.split('/')[-1].replace('.txt', '')
mkdir_if_missing(osp.join(datasetPath, outputFileName, seqName, 'gt'))
mkdir_if_missing(osp.join(datasetPath, outputFileName, seqName, 'img1'))
genGtFile(annotationPath,
osp.join(datasetPath, outputFileName, seqName, 'gt'), classes)
img1Path = osp.join(datasetPath, outputFileName, seqName, 'img1')
gtTxtPath = osp.join(datasetPath, outputFileName, seqName, 'gt/gt.txt')
copyImg(img1Path, gtTxtPath, outputFileName)
genSeqInfo(img1Path, seqName)
def deleteFileWhichImg1IsEmpty(mot16Path, dataType='train'):
path = mot16Path
data_images_train = osp.join(path, 'images', f'{dataType}')
data_images_train_seqs = glob.glob(data_images_train + '/*')
if (len(data_images_train_seqs) == 0):
print('dataset is empty!')
for data_images_train_seq in data_images_train_seqs:
data_images_train_seq_img1 = osp.join(data_images_train_seq, 'img1')
if len(glob.glob(data_images_train_seq_img1 + '/*.jpg')) == 0:
print(f"os.system(rm -rf {data_images_train_seq})")
os.system(f'rm -rf {data_images_train_seq}')
def formatMot16Path(dataPath, pathType='train'):
train_path = osp.join(dataPath, 'images', pathType)
mkdir_if_missing(train_path)
os.system(f'mv {dataPath}/* {train_path}')
def VisualGt(dataPath, phase='train'):
seqList = sorted(glob.glob(osp.join(dataPath, 'images', phase) + '/*'))
seqIndex = random.randint(0, len(seqList) - 1)
seqPath = seqList[seqIndex]
gt_path = osp.join(seqPath, 'gt', 'gt.txt')
img_list_path = sorted(glob.glob(osp.join(seqPath, 'img1', '*.jpg')))
imgIndex = random.randint(0, len(img_list_path))
img_Path = img_list_path[imgIndex]
frame_value = int(img_Path.split('/')[-1].replace('.jpg', ''))
gt_value = np.loadtxt(gt_path, dtype=int, delimiter=',')
gt_value = gt_value[gt_value[:, 0] == frame_value]
get_list = gt_value.tolist()
img = cv2.imread(img_Path)
colors = [[255, 0, 0], [255, 255, 0], [255, 0, 255], [0, 255, 0],
[0, 255, 255], [0, 0, 255]]
for seq, _id, pl, pt, w, h, _, bbox_class, _ in get_list:
cv2.putText(img,
str(bbox_class), (pl, pt), cv2.FONT_HERSHEY_PLAIN, 2,
colors[bbox_class - 1])
cv2.rectangle(
img, (pl, pt), (pl + w, pt + h),
colors[bbox_class - 1],
thickness=2)
cv2.imwrite('testGt.jpg', img)
def VisualDataset(datasetPath, phase='train', seqName='', frameId=1):
trainPath = osp.join(datasetPath, 'labels_with_ids', phase)
seq1Paths = osp.join(trainPath, seqName)
seq_img1_path = osp.join(seq1Paths, 'img1')
label_with_idPath = osp.join(seq_img1_path, '%07d' % frameId) + '.txt'
image_path = label_with_idPath.replace('labels_with_ids', 'images').replace(
'.txt', '.jpg')
seqInfoPath = str.join('/', image_path.split('/')[:-2])
seqInfoPath = seqInfoPath + '/seqinfo.ini'
seq_info = open(seqInfoPath).read()
width = int(seq_info[seq_info.find('imWidth=') + 8:seq_info.find(
'\nimHeight')])
height = int(seq_info[seq_info.find('imHeight=') + 9:seq_info.find(
'\nimExt')])
with open(label_with_idPath, 'r') as label:
allLines = label.readlines()
images = cv2.imread(image_path)
for line in allLines:
line = line.split(' ')
line = list(map(lambda x: float(x), line))
c1, c2, w, h = line[2:6]
x1 = c1 - w / 2
x2 = c2 - h / 2
x3 = c1 + w / 2
x4 = c2 + h / 2
cv2.rectangle(
images, (int(x1 * width), int(x2 * height)),
(int(x3 * width), int(x4 * height)), (255, 0, 0),
thickness=2)
cv2.imwrite('test.jpg', images)
def gen_image_list(dataPath, datType):
inputPath = f'{dataPath}/images/{datType}'
pathList = glob.glob(inputPath + '/*')
pathList = sorted(pathList)
allImageList = []
for pathSingle in pathList:
imgList = sorted(glob.glob(osp.join(pathSingle, 'img1', '*.jpg')))
for imgPath in imgList:
allImageList.append(imgPath)
with open(f'{dataPath}.{datType}', 'w') as image_list_file:
allImageListStr = str.join('\n', allImageList)
image_list_file.write(allImageListStr)
def gen_labels_mot(MOT_data, phase='train'):
seq_root = './{}/images/{}'.format(MOT_data, phase)
label_root = './{}/labels_with_ids/{}'.format(MOT_data, phase)
mkdir_if_missing(label_root)
seqs = [s for s in os.listdir(seq_root)]
print('seqs => ', seqs)
tid_curr = 0
tid_last = -1
for seq in seqs:
seq_info = open(osp.join(seq_root, seq, 'seqinfo.ini')).read()
seq_width = int(seq_info[seq_info.find('imWidth=') + 8:seq_info.find(
'\nimHeight')])
seq_height = int(seq_info[seq_info.find('imHeight=') + 9:seq_info.find(
'\nimExt')])
gt_txt = osp.join(seq_root, seq, 'gt', 'gt.txt')
gt = np.loadtxt(gt_txt, dtype=np.float64, delimiter=',')
seq_label_root = osp.join(label_root, seq, 'img1')
mkdir_if_missing(seq_label_root)
for fid, tid, x, y, w, h, mark, label, _ in gt:
# if mark == 0 or not label == 1:
# continue
fid = int(fid)
tid = int(tid)
if not tid == tid_last:
tid_curr += 1
tid_last = tid
x += w / 2
y += h / 2
label_fpath = osp.join(seq_label_root, '{:07d}.txt'.format(fid))
label_str = '0 {:d} {:.6f} {:.6f} {:.6f} {:.6f}\n'.format(
tid_curr, x / seq_width, y / seq_height, w / seq_width,
h / seq_height)
with open(label_fpath, 'a') as f:
f.write(label_str)
def parse_arguments():
parser = argparse.ArgumentParser(description='input method')
parser.add_argument("--transMot", type=bool, default=False)
parser.add_argument("--genMot", type=bool, default=False)
parser.add_argument("--formatMotPath", type=bool, default=False)
parser.add_argument("--deleteEmpty", type=bool, default=False)
parser.add_argument("--genLabelsMot", type=bool, default=False)
parser.add_argument("--genImageList", type=bool, default=False)
parser.add_argument("--visualImg", type=bool, default=False)
parser.add_argument("--visualGt", type=bool, default=False)
parser.add_argument("--data_name", type=str, default='visdrone_vehicle')
parser.add_argument("--phase", type=str, default='train')
parser.add_argument("--classes", type=str, default='4,5,6,9')
return parser.parse_args()
if __name__ == "__main__":
args = parse_arguments()
classes = args.classes.split(',')
datasetPath = './'
dataName = args.data_name
phase = args.phase
if args.transMot:
genMotLabels(datasetPath, dataName, classes)
formatMot16Path(dataName, pathType=phase)
mot16Path = f'./{dataName}'
deleteFileWhichImg1IsEmpty(mot16Path, dataType=phase)
gen_labels_mot(dataName, phase=phase)
gen_image_list(dataName, phase)
if args.genMot:
genMotLabels(datasetPath, dataName, classes)
if args.formatMotPath:
formatMot16Path(dataName, pathType=phase)
if args.deleteEmpty:
mot16Path = f'./{dataName}'
deleteFileWhichImg1IsEmpty(mot16Path, dataType=phase)
if args.genLabelsMot:
gen_labels_mot(dataName, phase=phase)
if args.genImageList:
gen_image_list(dataName, phase)
if args.visualGt:
VisualGt(f'./{dataName}', phase)
if args.visualImg:
seqName = 'uav0000137_00458_v'
frameId = 43
VisualDataset(
f'./{dataName}', phase=phase, seqName=seqName, frameId=frameId)
......@@ -37,7 +37,7 @@ __all__ = ['MOTEvaluator', 'MOTMetric', 'JDEDetMetric', 'KITTIMOTMetric']
def read_mot_results(filename, is_gt=False, is_ignore=False):
valid_labels = {1}
ignore_labels = {2, 7, 8, 12}
ignore_labels = {2, 7, 8, 12} # only in motchallenge datasets like 'MOT16'
results_dict = dict()
if os.path.isfile(filename):
with open(filename, 'r') as f:
......@@ -53,11 +53,10 @@ def read_mot_results(filename, is_gt=False, is_ignore=False):
box_size = float(linelist[4]) * float(linelist[5])
if is_gt:
if 'MOT16-' in filename or 'MOT17-' in filename or 'MOT15-' in filename or 'MOT20-' in filename:
label = int(float(linelist[7]))
mark = int(float(linelist[6]))
if mark == 0 or label not in valid_labels:
continue
label = int(float(linelist[7]))
mark = int(float(linelist[6]))
if mark == 0 or label not in valid_labels:
continue
score = 1
elif is_ignore:
if 'MOT16-' in filename or 'MOT17-' in filename or 'MOT15-' in filename or 'MOT20-' in filename:
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册