class_docstr: Load dataset with MOT format, support multi-class MOT.
  
  Args:
      dataset_dir (str): root directory for dataset.
      image_lists (list(str)): mcmot data image lists, muiti-source mcmot dataset.
      data_fields (list): key name of data dictionary, at least have 'image'.
      label_list (str): if use_default_label is False, will load
          mapping between category and class index.
      sample_num (int): number of samples to load, -1 means all.
  
  Notes:
      MCMOT datasets root directory following this:
          dataset/mot
          |——————image_lists
          |        |——————visdrone_mcmot.train  
          |        |——————visdrone_mcmot.val   
          visdrone_mcmot
          |——————images
          |        └——————train
          |        └——————val
          └——————labels_with_ids
                      └——————train
class_docstr_tok: ["Load","dataset","with","MOT","format",",","support","multi-class","MOT",".","Args",":","dataset_dir","(","str",")",":","root","directory","for","dataset",".","image_lists","(","list","(","str",")",")",":","mcmot","data","image","lists",",","muiti-source","mcmot","dataset",".","data_fields","(","list",")",":","key","name","of","data","dictionary",",","at","least","have","'image","'",".","label_list","(","str",")",":","if","use_default_label","is","False",",","will","load","mapping","between","category","and","class","index",".","sample_num","(","int",")",":","number","of","samples","to","load",",","-1","means","all",".","Notes",":","MCMOT","datasets","root","directory","following","this",":","dataset\/mot","|\u2014\u2014\u2014\u2014\u2014\u2014image_lists","|","|\u2014\u2014\u2014\u2014\u2014\u2014visdrone_mcmot.train","|","|\u2014\u2014\u2014\u2014\u2014\u2014visdrone_mcmot.val","visdrone_mcmot","|\u2014\u2014\u2014\u2014\u2014\u2014images","|","\u2514\u2014\u2014\u2014\u2014\u2014\u2014train","|","\u2514\u2014\u2014\u2014\u2014\u2014\u2014val","\u2514\u2014\u2014\u2014\u2014\u2014\u2014labels_with_ids","\u2514\u2014\u2014\u2014\u2014\u2014\u2014train"]
code: def parse_dataset(self):
      self.img_files = OrderedDict()
      self.img_start_index = OrderedDict()
      self.label_files = OrderedDict()
      self.tid_num = OrderedDict()
      self.tid_start_idx_of_cls_ids = defaultdict(dict)  # for MCMOT
  
      img_index = 0
      for data_name in self.image_lists:
          # check every data image list
          image_lists_dir = os.path.join(
              self.dataset_dir, "image_lists"
          )
          assert os.path.isdir(
              image_lists_dir
          ), "The {} is not a directory.".format(image_lists_dir)
  
          list_path = os.path.join(image_lists_dir, data_name)
          assert os.path.exists(
              list_path
          ), "The list path {} does not exist.".format(list_path)
  
          # record img_files, filter out empty ones
          with open(list_path, "r") as file:
              self.img_files[data_name] = file.readlines()
              self.img_files[data_name] = [
                  os.path.join(self.dataset_dir, x.strip())
                  for x in self.img_files[data_name]
              ]
              self.img_files[data_name] = list(
                  filter(
                      lambda x: len(x) > 0, self.img_files[data_name]
                  )
              )
  
              self.img_start_index[data_name] = img_index
              img_index += len(self.img_files[data_name])
  
          # record label_files
          self.label_files[data_name] = [
              x.replace("images", "labels_with_ids")
              .replace(".png", ".txt")
              .replace(".jpg", ".txt")
              for x in self.img_files[data_name]
          ]
  
      for data_name, label_paths in self.label_files.items():
          # using max_ids_dict rather than max_index
          max_ids_dict = defaultdict(int)
          for lp in label_paths:
              lb = np.loadtxt(lp)
              if len(lb) < 1:
                  continue
              lb = lb.reshape(-1, 6)
              for item in lb:
                  if item[1] > max_ids_dict[int(item[0])]:
                      # item[0]: cls_id
                      # item[1]: track id
                      max_ids_dict[int(item[0])] = int(item[1])
          # track id number
          self.tid_num[data_name] = max_ids_dict
  
      last_idx_dict = defaultdict(int)
      for i, (k, v) in enumerate(
          self.tid_num.items()
      ):  # each sub dataset
          for cls_id, id_num in v.items():  # v is a max_ids_dict
              self.tid_start_idx_of_cls_ids[k][cls_id] = last_idx_dict[
                  cls_id
              ]
              last_idx_dict[cls_id] += id_num
  
      self.num_identities_dict = defaultdict(int)
      for k, v in last_idx_dict.items():
          self.num_identities_dict[k] = int(
              v
          )  # total ids of each category
  
      self.num_imgs_each_data = [
          len(x) for x in self.img_files.values()
      ]
      self.total_imgs = sum(self.num_imgs_each_data)
  
      # cname2cid and cid2cname
      cname2cid = {}
      if self.label_list is not None:
          # if use label_list for multi source mix dataset,
          # please make sure label_list in the first sub_dataset at least.
          sub_dataset = self.image_lists[0].split(".")[0]
          label_path = os.path.join(
              self.dataset_dir, sub_dataset, self.label_list
          )
          if not os.path.exists(label_path):
              logger.info(
                  "Note: label_list {} does not exists, use VisDrone 10 classes labels as default.".format(
                      label_path
                  )
              )
              cname2cid = visdrone_mcmot_label()
          else:
              with open(label_path, "r") as fr:
                  label_id = 0
                  for line in fr.readlines():
                      cname2cid[line.strip()] = label_id
                      label_id += 1
      else:
          cname2cid = visdrone_mcmot_label()
  
      cid2cname = dict([(v, k) for (k, v) in cname2cid.items()])
  
      logger.info("MCMOT dataset summary: ")
      logger.info(self.tid_num)
      logger.info("Total images: {}".format(self.total_imgs))
      logger.info("Image start index: {}".format(self.img_start_index))
  
      logger.info("Total identities of each category: ")
      num_identities_dict = sorted(
          self.num_identities_dict.items(), key=lambda x: x[0]
      )
      total_IDs_all_cats = 0
      for k, v in num_identities_dict:
          logger.info(
              "Category {} [{}] has {} IDs.".format(k, cid2cname[k], v)
          )
          total_IDs_all_cats += v
      logger.info(
          "Total identities of all categories: {}".format(
              total_IDs_all_cats
          )
      )
  
      logger.info("Identity start index of each category: ")
      for k, v in self.tid_start_idx_of_cls_ids.items():
          sorted_v = sorted(v.items(), key=lambda x: x[0])
          for cls_id, start_idx in sorted_v:
              logger.info(
                  "Start index of dataset {} category {:d} is {:d}".format(
                      k, cls_id, start_idx
                  )
              )
  
      records = []
      for img_index in range(self.total_imgs):
          for i, (k, v) in enumerate(self.img_start_index.items()):
              if img_index >= v:
                  data_name = list(self.label_files.keys())[i]
                  start_index = v
          img_file = self.img_files[data_name][img_index - start_index]
          lbl_file = self.label_files[data_name][
              img_index - start_index
          ]
  
          if not os.path.exists(img_file):
              logger.warning(
                  "Illegal image file: {}, and it will be ignored".format(
                      img_file
                  )
              )
              continue
          if not os.path.isfile(lbl_file):
              logger.warning(
                  "Illegal label file: {}, and it will be ignored".format(
                      lbl_file
                  )
              )
              continue
  
          labels = np.loadtxt(lbl_file, dtype=np.float32).reshape(-1, 6)
          # each row in labels (N, 6) is [gt_class, gt_identity, cx, cy, w, h]
  
          cx, cy = labels[:, 2], labels[:, 3]
          w, h = labels[:, 4], labels[:, 5]
          gt_bbox = np.stack((cx, cy, w, h)).T.astype("float32")
          gt_class = labels[:, 0:1].astype("int32")
          gt_score = np.ones((len(labels), 1)).astype("float32")
          gt_ide = labels[:, 1:2].astype("int32")
          for i, _ in enumerate(gt_ide):
              if gt_ide[i] > -1:
                  cls_id = int(gt_class[i])
                  start_idx = self.tid_start_idx_of_cls_ids[data_name][
                      cls_id
                  ]
                  gt_ide[i] += start_idx
  
          mot_rec = (
              {
                  "im_file": img_file,
                  "im_id": img_index,
              }
              if "image" in self.data_fields
              else {}
          )
  
          gt_rec = {
              "gt_class": gt_class,
              "gt_score": gt_score,
              "gt_bbox": gt_bbox,
              "gt_ide": gt_ide,
          }
  
          for k, v in gt_rec.items():
              if k in self.data_fields:
                  mot_rec[k] = v
  
          records.append(mot_rec)
          if self.sample_num > 0 and img_index >= self.sample_num:
              break
      assert len(records) > 0, "not found any mot record in %s" % (
          self.image_lists
      )
      self.roidbs, self.cname2cid = records, cname2cid
  
imports: import os
  import sys
  import cv2
  import glob
  import numpy
  from collections import OrderedDict, defaultdict
  from .dataset import DetDataset, _make_dataset, _is_valid_file
  from ppdet.core.workspace import register, serializable
  from ppdet.utils.logger import setup_logger
label_desc: Use image node_id 3 for calling the MCMOTDataSet obj's underlying member method code with example usage: obj.parse_dataset() without return types