1313import cv2
1414import glob
1515import numpy as np
16+ from tqdm import tqdm
1617
17- DATA_ROOT = '/data/wujiapeng/datasets/ VisDrone2019/VisDrone2019'
18-
18+ # VisDrone2019, MOT20, MOT17
19+ DATA_ROOT = "/perception/yixu.cui/datas/tracking/VisDrone2019"
1920
2021# 以下两个seqs只跟踪车的时候有用
21- certain_seqs = ['uav0000071_03240_v' , 'uav0000072_04488_v' ,'uav0000072_05448_v' , 'uav0000072_06432_v' ,'uav0000124_00944_v' ,'uav0000126_00001_v' ,'uav0000138_00000_v' ,'uav0000145_00000_v' ,'uav0000150_02310_v' ,'uav0000222_03150_v' ,'uav0000239_12336_v' ,'uav0000243_00001_v' ,
22- 'uav0000248_00001_v' ,'uav0000263_03289_v' ,'uav0000266_03598_v' ,'uav0000273_00001_v' ,'uav0000279_00001_v' ,'uav0000281_00460_v' ,'uav0000289_00001_v' ,'uav0000289_06922_v' ,'uav0000307_00000_v' ,
23- 'uav0000308_00000_v' ,'uav0000308_01380_v' ,'uav0000326_01035_v' ,'uav0000329_04715_v' ,'uav0000361_02323_v' ,'uav0000366_00001_v' ]
24-
25- ignored_seqs = ['uav0000013_00000_v' , 'uav0000013_01073_v' , 'uav0000013_01392_v' ,
26- 'uav0000020_00406_v' , 'uav0000079_00480_v' ,
27- 'uav0000084_00000_v' , 'uav0000099_02109_v' , 'uav0000086_00000_v' ,
28- 'uav0000073_00600_v' , 'uav0000073_04464_v' , 'uav0000088_00290_v' ]
22+ certain_seqs = [
23+ "uav0000071_03240_v" ,
24+ "uav0000072_04488_v" ,
25+ "uav0000072_05448_v" ,
26+ "uav0000072_06432_v" ,
27+ "uav0000124_00944_v" ,
28+ "uav0000126_00001_v" ,
29+ "uav0000138_00000_v" ,
30+ "uav0000145_00000_v" ,
31+ "uav0000150_02310_v" ,
32+ "uav0000222_03150_v" ,
33+ "uav0000239_12336_v" ,
34+ "uav0000243_00001_v" ,
35+ "uav0000248_00001_v" ,
36+ "uav0000263_03289_v" ,
37+ "uav0000266_03598_v" ,
38+ "uav0000273_00001_v" ,
39+ "uav0000279_00001_v" ,
40+ "uav0000281_00460_v" ,
41+ "uav0000289_00001_v" ,
42+ "uav0000289_06922_v" ,
43+ "uav0000307_00000_v" ,
44+ "uav0000308_00000_v" ,
45+ "uav0000308_01380_v" ,
46+ "uav0000326_01035_v" ,
47+ "uav0000329_04715_v" ,
48+ "uav0000361_02323_v" ,
49+ "uav0000366_00001_v" ,
50+ ]
51+
52+ ignored_seqs = [
53+ "uav0000013_00000_v" ,
54+ "uav0000013_01073_v" ,
55+ "uav0000013_01392_v" ,
56+ "uav0000020_00406_v" ,
57+ "uav0000079_00480_v" ,
58+ "uav0000084_00000_v" ,
59+ "uav0000099_02109_v" ,
60+ "uav0000086_00000_v" ,
61+ "uav0000073_00600_v" ,
62+ "uav0000073_04464_v" ,
63+ "uav0000088_00290_v" ,
64+ ]
2965
3066image_wh_dict = {} # seq->(w,h) 字典 用于归一化
3167
68+
3269def generate_imgs_and_labels (opts ):
3370 """
3471 产生图片路径的txt文件以及yolo格式真值文件
3572 """
3673 if not opts .certain_seqs :
37- seq_list = os .listdir (osp .join (DATA_ROOT , opts .split_name , 'sequences' )) # 所有序列名称
74+ seq_list = os .listdir (
75+ osp .join (DATA_ROOT , opts .split_name , "sequences" )
76+ ) # 所有序列名称
3877 else :
3978 seq_list = certain_seqs
40-
79+
4180 if opts .car_only : # 只跟踪车就忽略行人多的视频
4281 seq_list = [seq for seq in seq_list if seq not in ignored_seqs ]
4382 category_list = [4 , 5 , 6 , 9 ] # 感兴趣的类别编号 List[int]
4483 else :
4584 category_list = [i for i in range (1 , 11 )]
4685
47- print (f' Total { len (seq_list )} seqs!!' )
48- if not osp .exists (' ./visdrone/' ):
49- os .makedirs (' ./visdrone/' )
86+ print (f" Total { len (seq_list )} seqs!!" )
87+ if not osp .exists (" ./visdrone/" ):
88+ os .makedirs (" ./visdrone/" )
5089
5190 # 类别ID 从0开始
5291 category_dict = {category_list [idx ]: idx for idx in range (len (category_list ))}
5392
54- txt_name_dict = {'VisDrone2019-MOT-train' : 'train' ,
55- 'VisDrone2019-MOT-val' : 'val' ,
56- 'VisDrone2019-MOT-test-dev' : 'test' } # 产生txt文件名称对应关系
93+ txt_name_dict = {
94+ "VisDrone2019-MOT-train" : "train" ,
95+ "VisDrone2019-MOT-val" : "val" ,
96+ "VisDrone2019-MOT-test-dev" : "test" ,
97+ } # 产生txt文件名称对应关系
5798
5899 # 如果已经存在就不写了
59- write_txt = False if os .path .isfile (os .path .join ('./visdrone' , txt_name_dict [opts .split_name ] + '.txt' )) else True
60- print (f'write txt is { write_txt } ' )
61-
62- frame_range = {'start' : 0.0 , 'end' : 1.0 }
100+ write_txt = (
101+ False
102+ if os .path .isfile (
103+ os .path .join ("./visdrone" , txt_name_dict [opts .split_name ] + ".txt" )
104+ )
105+ else True
106+ )
107+ print (f"write txt is { write_txt } " )
108+
109+ frame_range = {"start" : 0.0 , "end" : 1.0 }
63110 if opts .half : # VisDrone-half 截取一半
64- frame_range [' end' ] = 0.5
111+ frame_range [" end" ] = 0.5
65112
66113 # 以序列为单位进行处理
67- for seq in seq_list :
68- img_dir = osp .join (DATA_ROOT , opts .split_name , 'sequences' , seq ) # 该序列下所有图片路径
114+ for seq in tqdm (sorted (seq_list )):
115+ print (f"{ '*' * 8 } { seq } { '*' * 8 } " )
116+ img_dir = osp .join (DATA_ROOT , opts .split_name , "sequences" , seq ) # 该序列下所有图片路径
69117
70118 imgs = sorted (os .listdir (img_dir )) # 所有图片
71119 seq_length = len (imgs ) # 序列长度
72120
73121 img_eg = cv2 .imread (os .path .join (img_dir , imgs [0 ])) # 序列的第一张图 用以计算高宽
74122 w0 , h0 = img_eg .shape [1 ], img_eg .shape [0 ] # 原始高宽
75123
76- ann_of_seq_path = os .path .join (DATA_ROOT , opts .split_name , 'annotations' , seq + '.txt' ) # GT文件路径
77- ann_of_seq = np .loadtxt (ann_of_seq_path , dtype = np .float32 , delimiter = ',' ) # GT内容
124+ ann_of_seq_path = os .path .join (
125+ DATA_ROOT , opts .split_name , "annotations" , seq + ".txt"
126+ ) # GT文件路径
127+ ann_of_seq = np .loadtxt (
128+ ann_of_seq_path , dtype = np .float32 , delimiter = ","
129+ ) # GT内容
78130
79- gt_to_path = osp .join (DATA_ROOT , ' labels' , opts .split_name , seq ) # 要写入的真值文件夹
131+ gt_to_path = osp .join (DATA_ROOT , " labels" , opts .split_name , seq ) # 要写入的真值文件夹
80132 # 如果不存在就创建
81133 if not osp .exists (gt_to_path ):
82134 os .makedirs (gt_to_path )
83135
84136 exist_gts = [] # 初始化该列表 每个元素对应该seq的frame中有无真值框
85137 # 如果没有 就在train.txt产生图片路径
86138
87- for idx , img in enumerate (imgs ):
139+ for idx , img in enumerate (tqdm ( imgs ) ):
88140 # img: 相对路径 即 图片名称 0000001.jpg
89- if idx < int (seq_length * frame_range ['start' ]) or idx > int (seq_length * frame_range ['end' ]):
141+ if idx < int (seq_length * frame_range ["start" ]) or idx > int (
142+ seq_length * frame_range ["end" ]
143+ ):
90144 continue
91145
92146 # 第一步 产生图片软链接
93147 # print('step1, creating imgs symlink...')
94148 if opts .generate_imgs :
95- img_to_path = osp .join (DATA_ROOT , 'images' , opts .split_name , seq ) # 该序列图片存储位置
149+ img_to_path = osp .join (
150+ DATA_ROOT , "images" , opts .split_name , seq
151+ ) # 该序列图片存储位置
96152
97153 if not osp .exists (img_to_path ):
98154 os .makedirs (img_to_path )
99155
100- os .symlink (osp .join (img_dir , img ),
101- osp .join (img_to_path , img )) # 创建软链接
156+ link_name = osp .join (img_to_path , img )
157+ if not osp .exists (link_name ):
158+ os .symlink (
159+ osp .join (img_dir , img ),
160+ link_name ,
161+ ) # 创建软链接
102162 # print('Done!\n')
103163
104164 # 第二步 产生真值文件
105165 # print('step2, generating gt files...')
106166
107167 # 根据本序列的真值文件读取
108168 # ann_idx = int(ann_of_seq[:, 0]) == idx + 1
109- ann_of_current_frame = ann_of_seq [ann_of_seq [:, 0 ] == float (idx + 1 ), :] # 筛选真值文件里本帧的目标信息
169+ ann_of_current_frame = ann_of_seq [
170+ ann_of_seq [:, 0 ] == float (idx + 1 ), :
171+ ] # 筛选真值文件里本帧的目标信息
110172 exist_gts .append (True if ann_of_current_frame .shape [0 ] != 0 else False )
111173
112- gt_to_file = osp .join (gt_to_path , img [:- 4 ] + ' .txt' )
174+ gt_to_file = osp .join (gt_to_path , img [:- 4 ] + " .txt" )
113175
114- with open (gt_to_file , 'a' ) as f_gt :
176+ with open (gt_to_file , "w" ) as f_gt :
115177 for i in range (ann_of_current_frame .shape [0 ]):
116-
117- category = int (ann_of_current_frame [i ][7 ])
118- if int (ann_of_current_frame [i ][6 ]) == 1 and category in category_list :
119178
120- # bbox xywh
121- x0 , y0 = int (ann_of_current_frame [i ][2 ]), int (ann_of_current_frame [i ][3 ])
122- w , h = int (ann_of_current_frame [i ][4 ]), int (ann_of_current_frame [i ][5 ])
179+ category = int (ann_of_current_frame [i ][7 ])
180+ if (
181+ int (ann_of_current_frame [i ][6 ]) == 1
182+ and category in category_list
183+ ):
184+
185+ # bbox xywh
186+ x0 , y0 = int (ann_of_current_frame [i ][2 ]), int (
187+ ann_of_current_frame [i ][3 ]
188+ )
189+ w , h = int (ann_of_current_frame [i ][4 ]), int (
190+ ann_of_current_frame [i ][5 ]
191+ )
123192
124193 xc , yc = x0 + w // 2 , y0 + h // 2 # 中心点 x y
125194
@@ -129,40 +198,69 @@ def generate_imgs_and_labels(opts):
129198
130199 category_id = category_dict [category ]
131200
132- write_line = '{:d} {:.6f} {:.6f} {:.6f} {:.6f}\n ' .format (
133- category_id , xc , yc , w , h )
201+ write_line = "{:d} {:.6f} {:.6f} {:.6f} {:.6f}\n " .format (
202+ category_id , xc , yc , w , h
203+ )
134204
135205 f_gt .write (write_line )
136206
137207 f_gt .close ()
138208 # print('Done!\n')
139- print (f'img symlink and gt files of seq { seq } Done!' )
209+ print (f"img symlink and gt files of seq { seq } Done!" )
210+
140211 # 第三步 产生图片索引train.txt等
141- print (f'generating img index file of { seq } ' )
142212 if write_txt :
143- to_file = os .path .join ('./visdrone' , txt_name_dict [opts .split_name ] + '.txt' )
144- with open (to_file , 'a' ) as f :
213+ print (f"generating img index file of { seq } " )
214+ to_file = os .path .join (
215+ "./visdrone" , txt_name_dict [opts .split_name ] + ".txt"
216+ )
217+ with open (to_file , "a" ) as f :
145218 for idx , img in enumerate (imgs ):
146- if idx < int (seq_length * frame_range ['start' ]) or idx > int (seq_length * frame_range ['end' ]):
219+ if idx < int (seq_length * frame_range ["start" ]) or idx > int (
220+ seq_length * frame_range ["end" ]
221+ ):
147222 continue
148-
223+
149224 if exist_gts [idx ]:
150- f .write ('VisDrone2019/' + 'VisDrone2019/' + 'images/' + opts .split_name + '/' \
151- + seq + '/' + img + '\n ' )
225+ f .write (
226+ f"VisDrone2019/VisDrone2019/images/{ opts .split_name } /{ seq } /{ img } \n "
227+ )
152228
153229 f .close ()
154230
155- print ('All done!!' )
231+ print ("All done!!" )
232+
156233
157- if __name__ == ' __main__' :
234+ if __name__ == " __main__" :
158235 parser = argparse .ArgumentParser ()
159- parser .add_argument ('--split_name' , type = str , default = 'VisDrone2019-MOT-train' , help = 'train or test' )
160- parser .add_argument ('--generate_imgs' , action = 'store_true' , help = 'whether generate soft link of imgs' )
161- parser .add_argument ('--car_only' , action = 'store_true' , help = 'only cars' )
162- parser .add_argument ('--certain_seqs' , action = 'store_true' , help = 'for debug' )
163- parser .add_argument ('--half' , action = 'store_true' , help = 'half frames' )
236+ parser .add_argument (
237+ "--split_name" ,
238+ type = str ,
239+ default = "VisDrone2019-MOT-train" ,
240+ help = "train or test" ,
241+ )
242+ parser .add_argument (
243+ "--generate_imgs" ,
244+ action = "store_true" ,
245+ help = "whether generate soft link of imgs" ,
246+ )
247+ parser .add_argument (
248+ "--car_only" ,
249+ action = "store_true" ,
250+ help = "only cars" ,
251+ )
252+ parser .add_argument (
253+ "--certain_seqs" ,
254+ action = "store_true" ,
255+ help = "for debug" ,
256+ )
257+ parser .add_argument (
258+ "--half" ,
259+ action = "store_true" ,
260+ help = "half frames" ,
261+ )
164262
165263 opts = parser .parse_args ()
166264
167265 generate_imgs_and_labels (opts )
168- # python tools/convert_VisDrone_to_yolov2.py --split_name VisDrone2019-MOT-train --generate_imgs --car_only --half
266+ # python tools/convert_VisDrone_to_yolov2.py --split_name VisDrone2019-MOT-train --generate_imgs --car_only --half
0 commit comments