visdrone2mot.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. # Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. import glob
  15. import os
  16. import os.path as osp
  17. import cv2
  18. import argparse
  19. import numpy as np
  20. import random
  21. # The object category indicates the type of annotated object,
  22. # (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))
  23. # Extract single class or multi class
  24. isExtractMultiClass = False
  25. # These sequences are excluded because there are too few pedestrians
  26. exclude_seq = [
  27. "uav0000117_02622_v", "uav0000182_00000_v", "uav0000268_05773_v",
  28. "uav0000305_00000_v"
  29. ]
  30. def mkdir_if_missing(d):
  31. if not osp.exists(d):
  32. os.makedirs(d)
  33. def genGtFile(seqPath, outPath, classes=[]):
  34. id_idx = 0
  35. old_idx = -1
  36. with open(seqPath, 'r') as singleSeqFile:
  37. motLine = []
  38. allLines = singleSeqFile.readlines()
  39. for line in allLines:
  40. line = line.replace('\n', '')
  41. line = line.split(',')
  42. # exclude occlusion!='2'
  43. if line[-1] != '2' and line[7] in classes:
  44. if old_idx != int(line[1]):
  45. id_idx += 1
  46. old_idx = int(line[1])
  47. newLine = line[0:6]
  48. newLine[1] = str(id_idx)
  49. newLine.append('1')
  50. if (len(classes) > 1 and isExtractMultiClass):
  51. class_index = str(classes.index(line[7]) + 1)
  52. newLine.append(class_index)
  53. else:
  54. newLine.append('1') # use permenant class '1'
  55. newLine.append('1')
  56. motLine.append(newLine)
  57. mkdir_if_missing(outPath)
  58. gtFilePath = osp.join(outPath, 'gt.txt')
  59. with open(gtFilePath, 'w') as gtFile:
  60. motLine = list(map(lambda x: str.join(',', x), motLine))
  61. motLineStr = str.join('\n', motLine)
  62. gtFile.write(motLineStr)
  63. def genSeqInfo(img1Path, seqName):
  64. imgPaths = glob.glob(img1Path + '/*.jpg')
  65. seqLength = len(imgPaths)
  66. if seqLength > 0:
  67. image1 = cv2.imread(imgPaths[0])
  68. imgHeight = image1.shape[0]
  69. imgWidth = image1.shape[1]
  70. else:
  71. imgHeight = 0
  72. imgWidth = 0
  73. seqInfoStr = f'''[Sequence]\nname={seqName}\nimDir=img1\nframeRate=30\nseqLength={seqLength}\nimWidth={imgWidth}\nimHeight={imgHeight}\nimExt=.jpg'''
  74. seqInfoPath = img1Path.replace('/img1', '')
  75. with open(seqInfoPath + '/seqinfo.ini', 'w') as seqFile:
  76. seqFile.write(seqInfoStr)
  77. def copyImg(img1Path, gtTxtPath, outputFileName):
  78. with open(gtTxtPath, 'r') as gtFile:
  79. allLines = gtFile.readlines()
  80. imgList = []
  81. for line in allLines:
  82. imgIdx = int(line.split(',')[0])
  83. if imgIdx not in imgList:
  84. imgList.append(imgIdx)
  85. seqName = gtTxtPath.replace('./{}/'.format(outputFileName),
  86. '').replace('/gt/gt.txt', '')
  87. sourceImgPath = osp.join('./sequences', seqName,
  88. '{:07d}.jpg'.format(imgIdx))
  89. os.system(f'cp {sourceImgPath} {img1Path}')
  90. def genMotLabels(datasetPath, outputFileName, classes=['2']):
  91. mkdir_if_missing(osp.join(datasetPath, outputFileName))
  92. annotationsPath = osp.join(datasetPath, 'annotations')
  93. annotationsList = glob.glob(osp.join(annotationsPath, '*.txt'))
  94. for annotationPath in annotationsList:
  95. seqName = annotationPath.split('/')[-1].replace('.txt', '')
  96. if seqName in exclude_seq:
  97. continue
  98. mkdir_if_missing(osp.join(datasetPath, outputFileName, seqName, 'gt'))
  99. mkdir_if_missing(osp.join(datasetPath, outputFileName, seqName, 'img1'))
  100. genGtFile(annotationPath,
  101. osp.join(datasetPath, outputFileName, seqName, 'gt'), classes)
  102. img1Path = osp.join(datasetPath, outputFileName, seqName, 'img1')
  103. gtTxtPath = osp.join(datasetPath, outputFileName, seqName, 'gt/gt.txt')
  104. copyImg(img1Path, gtTxtPath, outputFileName)
  105. genSeqInfo(img1Path, seqName)
  106. def deleteFileWhichImg1IsEmpty(mot16Path, dataType='train'):
  107. path = mot16Path
  108. data_images_train = osp.join(path, 'images', f'{dataType}')
  109. data_images_train_seqs = glob.glob(data_images_train + '/*')
  110. if (len(data_images_train_seqs) == 0):
  111. print('dataset is empty!')
  112. for data_images_train_seq in data_images_train_seqs:
  113. data_images_train_seq_img1 = osp.join(data_images_train_seq, 'img1')
  114. if len(glob.glob(data_images_train_seq_img1 + '/*.jpg')) == 0:
  115. print(f"os.system(rm -rf {data_images_train_seq})")
  116. os.system(f'rm -rf {data_images_train_seq}')
  117. def formatMot16Path(dataPath, pathType='train'):
  118. train_path = osp.join(dataPath, 'images', pathType)
  119. mkdir_if_missing(train_path)
  120. os.system(f'mv {dataPath}/* {train_path}')
  121. def VisualGt(dataPath, phase='train'):
  122. seqList = sorted(glob.glob(osp.join(dataPath, 'images', phase) + '/*'))
  123. seqIndex = random.randint(0, len(seqList) - 1)
  124. seqPath = seqList[seqIndex]
  125. gt_path = osp.join(seqPath, 'gt', 'gt.txt')
  126. img_list_path = sorted(glob.glob(osp.join(seqPath, 'img1', '*.jpg')))
  127. imgIndex = random.randint(0, len(img_list_path))
  128. img_Path = img_list_path[imgIndex]
  129. frame_value = int(img_Path.split('/')[-1].replace('.jpg', ''))
  130. gt_value = np.loadtxt(gt_path, dtype=int, delimiter=',')
  131. gt_value = gt_value[gt_value[:, 0] == frame_value]
  132. get_list = gt_value.tolist()
  133. img = cv2.imread(img_Path)
  134. colors = [[255, 0, 0], [255, 255, 0], [255, 0, 255], [0, 255, 0],
  135. [0, 255, 255], [0, 0, 255]]
  136. for seq, _id, pl, pt, w, h, _, bbox_class, _ in get_list:
  137. cv2.putText(img,
  138. str(bbox_class), (pl, pt), cv2.FONT_HERSHEY_PLAIN, 2,
  139. colors[bbox_class - 1])
  140. cv2.rectangle(
  141. img, (pl, pt), (pl + w, pt + h),
  142. colors[bbox_class - 1],
  143. thickness=2)
  144. cv2.imwrite('testGt.jpg', img)
  145. def VisualDataset(datasetPath, phase='train', seqName='', frameId=1):
  146. trainPath = osp.join(datasetPath, 'labels_with_ids', phase)
  147. seq1Paths = osp.join(trainPath, seqName)
  148. seq_img1_path = osp.join(seq1Paths, 'img1')
  149. label_with_idPath = osp.join(seq_img1_path, '%07d' % frameId) + '.txt'
  150. image_path = label_with_idPath.replace('labels_with_ids', 'images').replace(
  151. '.txt', '.jpg')
  152. seqInfoPath = str.join('/', image_path.split('/')[:-2])
  153. seqInfoPath = seqInfoPath + '/seqinfo.ini'
  154. seq_info = open(seqInfoPath).read()
  155. width = int(seq_info[seq_info.find('imWidth=') + 8:seq_info.find(
  156. '\nimHeight')])
  157. height = int(seq_info[seq_info.find('imHeight=') + 9:seq_info.find(
  158. '\nimExt')])
  159. with open(label_with_idPath, 'r') as label:
  160. allLines = label.readlines()
  161. images = cv2.imread(image_path)
  162. for line in allLines:
  163. line = line.split(' ')
  164. line = list(map(lambda x: float(x), line))
  165. c1, c2, w, h = line[2:6]
  166. x1 = c1 - w / 2
  167. x2 = c2 - h / 2
  168. x3 = c1 + w / 2
  169. x4 = c2 + h / 2
  170. cv2.rectangle(
  171. images, (int(x1 * width), int(x2 * height)),
  172. (int(x3 * width), int(x4 * height)), (255, 0, 0),
  173. thickness=2)
  174. cv2.imwrite('test.jpg', images)
  175. def gen_image_list(dataPath, datType):
  176. inputPath = f'{dataPath}/images/{datType}'
  177. pathList = glob.glob(inputPath + '/*')
  178. pathList = sorted(pathList)
  179. allImageList = []
  180. for pathSingle in pathList:
  181. imgList = sorted(glob.glob(osp.join(pathSingle, 'img1', '*.jpg')))
  182. for imgPath in imgList:
  183. allImageList.append(imgPath)
  184. with open(f'{dataPath}.{datType}', 'w') as image_list_file:
  185. allImageListStr = str.join('\n', allImageList)
  186. image_list_file.write(allImageListStr)
  187. def gen_labels_mot(MOT_data, phase='train'):
  188. seq_root = './{}/images/{}'.format(MOT_data, phase)
  189. label_root = './{}/labels_with_ids/{}'.format(MOT_data, phase)
  190. mkdir_if_missing(label_root)
  191. seqs = [s for s in os.listdir(seq_root)]
  192. print('seqs => ', seqs)
  193. tid_curr = 0
  194. tid_last = -1
  195. for seq in seqs:
  196. seq_info = open(osp.join(seq_root, seq, 'seqinfo.ini')).read()
  197. seq_width = int(seq_info[seq_info.find('imWidth=') + 8:seq_info.find(
  198. '\nimHeight')])
  199. seq_height = int(seq_info[seq_info.find('imHeight=') + 9:seq_info.find(
  200. '\nimExt')])
  201. gt_txt = osp.join(seq_root, seq, 'gt', 'gt.txt')
  202. gt = np.loadtxt(gt_txt, dtype=np.float64, delimiter=',')
  203. seq_label_root = osp.join(label_root, seq, 'img1')
  204. mkdir_if_missing(seq_label_root)
  205. for fid, tid, x, y, w, h, mark, label, _ in gt:
  206. # if mark == 0 or not label == 1:
  207. # continue
  208. fid = int(fid)
  209. tid = int(tid)
  210. if not tid == tid_last:
  211. tid_curr += 1
  212. tid_last = tid
  213. x += w / 2
  214. y += h / 2
  215. label_fpath = osp.join(seq_label_root, '{:07d}.txt'.format(fid))
  216. label_str = '0 {:d} {:.6f} {:.6f} {:.6f} {:.6f}\n'.format(
  217. tid_curr, x / seq_width, y / seq_height, w / seq_width,
  218. h / seq_height)
  219. with open(label_fpath, 'a') as f:
  220. f.write(label_str)
  221. def parse_arguments():
  222. parser = argparse.ArgumentParser(description='input method')
  223. parser.add_argument("--transMot", type=bool, default=False)
  224. parser.add_argument("--genMot", type=bool, default=False)
  225. parser.add_argument("--formatMotPath", type=bool, default=False)
  226. parser.add_argument("--deleteEmpty", type=bool, default=False)
  227. parser.add_argument("--genLabelsMot", type=bool, default=False)
  228. parser.add_argument("--genImageList", type=bool, default=False)
  229. parser.add_argument("--visualImg", type=bool, default=False)
  230. parser.add_argument("--visualGt", type=bool, default=False)
  231. parser.add_argument("--data_name", type=str, default='visdrone_pedestrian')
  232. parser.add_argument("--phase", type=str, default='train')
  233. parser.add_argument(
  234. "--classes", type=str, default='1,2') # pedestrian and people
  235. return parser.parse_args()
  236. if __name__ == "__main__":
  237. args = parse_arguments()
  238. classes = args.classes.split(',')
  239. datasetPath = './'
  240. dataName = args.data_name
  241. phase = args.phase
  242. if args.transMot:
  243. genMotLabels(datasetPath, dataName, classes)
  244. formatMot16Path(dataName, pathType=phase)
  245. mot16Path = f'./{dataName}'
  246. deleteFileWhichImg1IsEmpty(mot16Path, dataType=phase)
  247. gen_labels_mot(dataName, phase=phase)
  248. gen_image_list(dataName, phase)
  249. if args.genMot:
  250. genMotLabels(datasetPath, dataName, classes)
  251. if args.formatMotPath:
  252. formatMot16Path(dataName, pathType=phase)
  253. if args.deleteEmpty:
  254. mot16Path = f'./{dataName}'
  255. deleteFileWhichImg1IsEmpty(mot16Path, dataType=phase)
  256. if args.genLabelsMot:
  257. gen_labels_mot(dataName, phase=phase)
  258. if args.genImageList:
  259. gen_image_list(dataName, phase)
  260. if args.visualGt:
  261. VisualGt(f'./{dataName}', phase)
  262. if args.visualImg:
  263. seqName = 'uav0000137_00458_v'
  264. frameId = 43
  265. VisualDataset(
  266. f'./{dataName}', phase=phase, seqName=seqName, frameId=frameId)