Skip to content

Commit a4f9fc0

Browse files
committed
add scripts
1 parent dabffff commit a4f9fc0

15 files changed

+833
-0
lines changed

scripts/convert_to_bdd.sh

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export PYTHONPATH=$PYTHONPATH:`pwd`
2+
3+
python ./tools/to_bdd100k.py configs/segtrack-frcnn_r50_fpn_12e_bdd10k_fixed_refine_pcan.py --res eval_result_pcan_comp.pkl --task seg_track --bdd-dir converted_results/ --nproc 2
4+

scripts/convert_to_bdd_test.sh

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export PYTHONPATH=$PYTHONPATH:`pwd`
2+
3+
python ./tools/to_bdd100k.py configs/segtrack-frcnn_r50_fpn_12e_bdd10k_fixed_refine_pcan.py --res eval_result_pcan_test.pkl --task seg_track --bdd-dir converted_results_test/ --nproc 2
4+

scripts/eval_bdd_submit.sh

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export PYTHONPATH=$PYTHONPATH:`pwd`
2+
3+
python -m bdd100k.eval.run -t seg_track -g ../pcan/data/bdd/labels/seg_track_20/bitmasks/val -r ../pcan/converted_results/seg_track

scripts/test_pcan.sh

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export PYTHONPATH=$PYTHONPATH:`pwd`
2+
3+
bash ./tools/dist_test.sh configs/segtrack-frcnn_r50_fpn_12e_bdd10k_fixed_refine_pcan.py pcan_training_result_4gpu/epoch_12.pth 4 --out eval_result_pcan_test.pkl --eval 'segtrack'
4+

scripts/train_pcan.sh

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
bash ./tools/dist_train.sh configs/segtrack-frcnn_r50_fpn_12e_bdd10k_fixed_refine_pcan.py 4 --work-dir ./pcan_training_result/

scripts/vis_pcan.sh

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export PYTHONPATH=$PYTHONPATH:`pwd`
2+
3+
python3 ./tools/test.py configs/segtrack-frcnn_r50_fpn_12e_bdd10k_fixed_refine_pcan.py pcan_training_result_4gpu/epoch_12.pth --out eval_pcan_results_testv.pkl --eval 'segtrack' --show-dir ./vis_pcan_result_testv/
4+

setup.py

+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import os
2+
import subprocess
3+
import time
4+
from setuptools import find_packages, setup
5+
6+
7+
def readme():
8+
with open('README.md', encoding='utf-8') as f:
9+
content = f.read()
10+
return content
11+
12+
13+
version_file = 'pcan/version.py'
14+
15+
16+
def get_git_hash():
17+
18+
def _minimal_ext_cmd(cmd):
19+
# construct minimal environment
20+
env = {}
21+
for k in ['SYSTEMROOT', 'PATH', 'HOME']:
22+
v = os.environ.get(k)
23+
if v is not None:
24+
env[k] = v
25+
# LANGUAGE is used on win32
26+
env['LANGUAGE'] = 'C'
27+
env['LANG'] = 'C'
28+
env['LC_ALL'] = 'C'
29+
out = subprocess.Popen(
30+
cmd, stdout=subprocess.PIPE, env=env).communicate()[0]
31+
return out
32+
33+
try:
34+
out = _minimal_ext_cmd(['git', 'rev-parse', 'HEAD'])
35+
sha = out.strip().decode('ascii')
36+
except OSError:
37+
sha = 'unknown'
38+
39+
return sha
40+
41+
42+
def get_hash():
43+
if os.path.exists('.git'):
44+
sha = get_git_hash()[:7]
45+
elif os.path.exists(version_file):
46+
try:
47+
from pcan.version import __version__
48+
sha = __version__.split('+')[-1]
49+
except ImportError:
50+
raise ImportError('Unable to get git version')
51+
else:
52+
sha = 'unknown'
53+
54+
return sha
55+
56+
57+
def write_version_py():
58+
content = """# GENERATED VERSION FILE
59+
# TIME: {}
60+
__version__ = '{}'
61+
short_version = '{}'
62+
version_info = ({})
63+
"""
64+
sha = get_hash()
65+
with open('pcan/VERSION', 'r') as f:
66+
SHORT_VERSION = f.read().strip()
67+
VERSION_INFO = ', '.join(SHORT_VERSION.split('.'))
68+
VERSION = SHORT_VERSION + '+' + sha
69+
70+
version_file_str = content.format(time.asctime(), VERSION, SHORT_VERSION,
71+
VERSION_INFO)
72+
with open(version_file, 'w') as f:
73+
f.write(version_file_str)
74+
75+
76+
def get_version():
77+
with open(version_file, 'r') as f:
78+
exec(compile(f.read(), version_file, 'exec'))
79+
return locals()['__version__']
80+
81+
82+
def get_requirements(filename='requirements.txt'):
83+
here = os.path.dirname(os.path.realpath(__file__))
84+
with open(os.path.join(here, filename), 'r') as f:
85+
requires = [line.replace('\n', '') for line in f.readlines()]
86+
for i, req in enumerate(requires):
87+
if req.startswith("git"):
88+
pkg_name = req.split("/")[-1].split(".")[0]
89+
req = pkg_name
90+
requires[i] = req
91+
return requires
92+
93+
94+
if __name__ == '__main__':
95+
write_version_py()
96+
setup(
97+
name='pcan',
98+
version=get_version(),
99+
description='A template for pytorch projects.',
100+
long_description=readme(),
101+
packages=find_packages(exclude=('configs', 'tools', 'demo')),
102+
package_data={'pcan.ops': ['*/*.so']},
103+
classifiers=[
104+
'Development Status :: 4 - Beta',
105+
'License :: OSI Approved :: Apache Software License',
106+
'Operating System :: OS Independent',
107+
'Programming Language :: Python :: 3',
108+
'Programming Language :: Python :: 3.5',
109+
'Programming Language :: Python :: 3.6',
110+
'Programming Language :: Python :: 3.7',
111+
],
112+
license='Apache License 2.0',
113+
setup_requires=['pytest-runner', 'cython', 'numpy'],
114+
tests_require=['pytest', 'xdoctest'],
115+
install_requires=get_requirements(),
116+
zip_safe=False)

tools/convert_datasets/mot2coco.py

+226
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
# This script converts MOT labels into COCO style.
2+
# Offical website of the MOT dataset: https://motchallenge.net/
3+
#
4+
# Label format of MOT dataset:
5+
# GTs:
6+
# <frame_id> # starts from 1 but COCO style starts from 0,
7+
# <instance_id>, <x1>, <y1>, <w>, <h>,
8+
# <conf> # conf is annotated as 0 if the object is ignored,
9+
# <class_id>, <visibility>
10+
#
11+
# DETs and Results:
12+
# <frame_id>, <instance_id>, <x1>, <y1>, <w>, <h>, <conf>,
13+
# <x>, <y>, <z> # for 3D objects
14+
#
15+
# Classes in MOT:
16+
# 1: 'pedestrian'
17+
# 2: 'person on vehicle'
18+
# 3: 'car'
19+
# 4: 'bicycle'
20+
# 5: 'motorbike'
21+
# 6: 'non motorized vehicle'
22+
# 7: 'static person'
23+
# 8: 'distractor'
24+
# 9: 'occluder'
25+
# 10: 'occluder on the ground',
26+
# 11: 'occluder full'
27+
# 12: 'reflection'
28+
#
29+
# USELESS classes are not included into the json file.
30+
# IGNORES classes are included with `ignore=True`.
31+
import argparse
32+
import os
33+
import os.path as osp
34+
from collections import defaultdict
35+
36+
import mmcv
37+
import numpy as np
38+
from tqdm import tqdm
39+
40+
USELESS = [3, 4, 5, 6, 9, 10, 11]
41+
IGNORES = [2, 7, 8, 12, 13]
42+
43+
44+
def parse_args():
45+
parser = argparse.ArgumentParser(
46+
description='Convert MOT label and detections to COCO-VID format.')
47+
parser.add_argument('-i', '--input', help='path of MOT data')
48+
parser.add_argument(
49+
'-o', '--output', help='path to save coco formatted label file')
50+
parser.add_argument(
51+
'--convert-det',
52+
action='store_true',
53+
help='convert offical detection results.')
54+
parser.add_argument(
55+
'--split-train',
56+
action='store_true',
57+
help='split the train set into half-train and half-validate.')
58+
return parser.parse_args()
59+
60+
61+
def parse_gts(gts, is_mot15):
62+
outputs = defaultdict(list)
63+
for gt in gts:
64+
gt = gt.strip().split(',')
65+
frame_id, ins_id = map(int, gt[:2])
66+
bbox = list(map(float, gt[2:6]))
67+
if is_mot15:
68+
conf = 1.
69+
class_id = 1
70+
visibility = 1.
71+
else:
72+
conf = float(gt[6])
73+
class_id = int(gt[7])
74+
visibility = float(gt[8])
75+
if class_id in USELESS:
76+
continue
77+
elif class_id in IGNORES:
78+
continue
79+
anns = dict(
80+
category_id=1,
81+
bbox=bbox,
82+
area=bbox[2] * bbox[3],
83+
iscrowd=False,
84+
visibility=visibility,
85+
mot_instance_id=ins_id,
86+
mot_conf=conf,
87+
mot_class_id=class_id)
88+
outputs[frame_id].append(anns)
89+
return outputs
90+
91+
92+
def parse_dets(dets):
93+
outputs = defaultdict(list)
94+
for det in dets:
95+
det = det.strip().split(',')
96+
frame_id, ins_id = map(int, det[:2])
97+
assert ins_id == -1
98+
bbox = list(map(float, det[2:7]))
99+
# [x1, y1, x2, y2] to be consistent with mmdet
100+
bbox = [
101+
bbox[0], bbox[1], bbox[0] + bbox[2], bbox[1] + bbox[3], bbox[4]
102+
]
103+
outputs[frame_id].append(bbox)
104+
105+
return outputs
106+
107+
108+
def main():
109+
args = parse_args()
110+
if not osp.exists(args.output):
111+
os.makedirs(args.output)
112+
113+
sets = ['train', 'test']
114+
if args.split_train:
115+
sets += ['half-train', 'half-val']
116+
vid_id, img_id, ann_id = 1, 1, 1
117+
118+
for subset in sets:
119+
ins_id = 0
120+
print(f'Converting {subset} set to COCO format')
121+
if 'half' in subset:
122+
in_folder = osp.join(args.input, 'train')
123+
else:
124+
in_folder = osp.join(args.input, subset)
125+
out_file = osp.join(args.output, f'{subset}_cocoformat.json')
126+
outputs = defaultdict(list)
127+
outputs['categories'] = [dict(id=1, name='pedestrian')]
128+
if args.convert_det:
129+
det_file = osp.join(args.output, f'{subset}_detections.pkl')
130+
detections = dict(bbox_results=dict())
131+
video_names = os.listdir(in_folder)
132+
for video_name in tqdm(video_names):
133+
# basic params
134+
parse_gt = 'test' not in subset
135+
ins_maps = dict()
136+
# load video infos
137+
video_folder = osp.join(in_folder, video_name)
138+
infos = mmcv.list_from_file(f'{video_folder}/seqinfo.ini')
139+
# video-level infos
140+
assert video_name == infos[1].strip().split('=')[1]
141+
img_folder = infos[2].strip().split('=')[1]
142+
img_names = os.listdir(f'{video_folder}/{img_folder}')
143+
img_names = sorted(img_names)
144+
fps = int(infos[3].strip().split('=')[1])
145+
num_imgs = int(infos[4].strip().split('=')[1])
146+
assert num_imgs == len(img_names)
147+
width = int(infos[5].strip().split('=')[1])
148+
height = int(infos[6].strip().split('=')[1])
149+
video = dict(
150+
id=vid_id,
151+
name=video_name,
152+
fps=fps,
153+
width=width,
154+
height=height)
155+
# parse annotations
156+
if parse_gt:
157+
gts = mmcv.list_from_file(f'{video_folder}/gt/gt.txt')
158+
if 'MOT15' in video_folder:
159+
img2gts = parse_gts(gts, True)
160+
else:
161+
img2gts = parse_gts(gts, False)
162+
if args.convert_det:
163+
dets = mmcv.list_from_file(f'{video_folder}/det/det.txt')
164+
img2dets = parse_dets(dets)
165+
# make half sets
166+
if 'half' in subset:
167+
split_frame = num_imgs // 2 + 1
168+
if 'train' in subset:
169+
img_names = img_names[:split_frame]
170+
elif 'val' in subset:
171+
img_names = img_names[split_frame:]
172+
else:
173+
raise ValueError(
174+
'subset must be named with `train` or `val`')
175+
mot_frame_ids = [str(int(_.split('.')[0])) for _ in img_names]
176+
with open(f'{video_folder}/gt/gt_{subset}.txt', 'wt') as f:
177+
for gt in gts:
178+
if gt.split(',')[0] in mot_frame_ids:
179+
f.writelines(f'{gt}\n')
180+
# image and box level infos
181+
for frame_id, name in enumerate(img_names):
182+
img_name = osp.join(video_name, img_folder, name)
183+
mot_frame_id = int(name.split('.')[0])
184+
image = dict(
185+
id=img_id,
186+
video_id=vid_id,
187+
file_name=img_name,
188+
height=height,
189+
width=width,
190+
frame_id=frame_id,
191+
mot_frame_id=mot_frame_id)
192+
if parse_gt:
193+
gts = img2gts[mot_frame_id]
194+
for gt in gts:
195+
gt.update(id=ann_id, image_id=img_id)
196+
mot_ins_id = gt['mot_instance_id']
197+
if mot_ins_id in ins_maps:
198+
gt['instance_id'] = ins_maps[mot_ins_id]
199+
else:
200+
gt['instance_id'] = ins_id
201+
ins_maps[mot_ins_id] = ins_id
202+
ins_id += 1
203+
outputs['annotations'].append(gt)
204+
ann_id += 1
205+
if args.convert_det:
206+
dets = np.array(img2dets[mot_frame_id])
207+
if dets.ndim == 1:
208+
assert len(dets) == 0
209+
dets = np.zeros((0, 5))
210+
detections['bbox_results'][img_name] = [dets]
211+
outputs['images'].append(image)
212+
img_id += 1
213+
outputs['videos'].append(video)
214+
vid_id += 1
215+
outputs['num_instances'] = ins_id
216+
print(f'{subset} has {ins_id} instances.')
217+
mmcv.dump(outputs, out_file)
218+
if args.convert_det:
219+
mmcv.dump(detections, det_file)
220+
print(f'Done! Saved as {out_file} and {det_file}')
221+
else:
222+
print(f'Done! Saved as {out_file}')
223+
224+
225+
if __name__ == '__main__':
226+
main()

tools/dist_test.sh

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/usr/bin/env bash
2+
3+
CONFIG=$1
4+
CHECKPOINT=$2
5+
GPUS=$3
6+
PORT=${PORT:-29500}
7+
8+
PYTHONPATH="$(dirname $0)/..":$PYTHONPATH \
9+
python -m torch.distributed.launch --nproc_per_node=$GPUS --master_port=$PORT \
10+
$(dirname "$0")/test.py $CONFIG $CHECKPOINT --launcher pytorch ${@:4}

tools/dist_train.sh

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#!/usr/bin/env bash
2+
3+
CONFIG=$1
4+
GPUS=$2
5+
PORT=${PORT:-29500}
6+
7+
PYTHONPATH="$(dirname $0)/..":$PYTHONPATH \
8+
python -m torch.distributed.launch --nproc_per_node=$GPUS --master_port=$PORT \
9+
$(dirname "$0")/train.py $CONFIG --launcher pytorch ${@:3}

0 commit comments

Comments
 (0)