class_docstr: KITTI tracking statistics (CLEAR MOT, id-switches, fragments, ML/PT/MT, precision/recall)
  MOTA       - Multi-object tracking accuracy in [0,100]
  MOTP       - Multi-object tracking precision in [0,100] (3D) / [td,100] (2D)
  MOTAL      - Multi-object tracking accuracy in [0,100] with log10(id-switches)
  
  id-switches - number of id switches
  fragments   - number of fragmentations
  
  MT, PT, ML - number of mostly tracked, partially tracked and mostly lost trajectories
  
  recall             - recall = percentage of detected targets
  precision      - precision = percentage of correctly detected targets
  FAR                    - number of false alarms per frame
  falsepositives - number of false positives (FP)
  missed         - number of missed targets (FN)
class_docstr_tok: ["KITTI","tracking","statistics","(","CLEAR","MOT",",","id-switches",",","fragments",",","ML\/PT\/MT",",","precision\/recall",")","MOTA","-","Multi-object","tracking","accuracy","in","[","0,100","]","MOTP","-","Multi-object","tracking","precision","in","[","0,100","]","(","3D",")","\/","[","td,100","]","(","2D",")","MOTAL","-","Multi-object","tracking","accuracy","in","[","0,100","]","with","log10","(","id-switches",")","id-switches","-","number","of","id","switches","fragments","-","number","of","fragmentations","MT",",","PT",",","ML","-","number","of","mostly","tracked",",","partially","tracked","and","mostly","lost","trajectories","recall","-","recall","=","percentage","of","detected","targets","precision","-","precision","=","percentage","of","correctly","detected","targets","FAR","-","number","of","false","alarms","per","frame","falsepositives","-","number","of","false","positives","(","FP",")","missed","-","number","of","missed","targets","(","FN",")"]
docstr: Generic loader for ground truth and tracking data.
  Use loadGroundtruth() or loadTracker() to load this data.
  Loads detections in KITTI format from textfiles.
code: def _loadData(
      self, root_dir, cls, min_score=-1000, loading_groundtruth=False
  ):
      """
      Generic loader for ground truth and tracking data.
      Use loadGroundtruth() or loadTracker() to load this data.
      Loads detections in KITTI format from textfiles.
      """
      # construct objectDetections object to hold detection data
      t_data = tData()
      data = []
      eval_2d = True
      eval_3d = True
  
      seq_data = []
      n_trajectories = 0
      n_trajectories_seq = []
      for seq, s_name in enumerate(self.sequence_name):
          i = 0
          filename = os.path.join(root_dir, "%s.txt" % s_name)
          f = open(filename, "r")
  
          f_data = [
              [] for x in range(self.n_frames[seq])
          ]  # current set has only 1059 entries, sufficient length is checked anyway
          ids = []
          n_in_seq = 0
          id_frame_cache = []
          for line in f:
              # KITTI tracking benchmark data format:
              # (frame,tracklet_id,objectType,truncation,occlusion,alpha,x1,y1,x2,y2,h,w,l,X,Y,Z,ry)
              line = line.strip()
              fields = line.split(" ")
              # classes that should be loaded (ignored neighboring classes)
              if "car" in cls.lower():
                  classes = ["car", "van"]
              elif "pedestrian" in cls.lower():
                  classes = ["pedestrian", "person_sitting"]
              else:
                  classes = [cls.lower()]
              classes += ["dontcare"]
              if not any(
                  [s for s in classes if s in fields[2].lower()]
              ):
                  continue
              # get fields from table
              t_data.frame = int(float(fields[0]))  # frame
              t_data.track_id = int(float(fields[1]))  # id
              t_data.obj_type = fields[
                  2
              ].lower()  # object type [car, pedestrian, cyclist, ...]
              t_data.truncation = int(
                  float(fields[3])
              )  # truncation [-1,0,1,2]
              t_data.occlusion = int(
                  float(fields[4])
              )  # occlusion  [-1,0,1,2]
              t_data.obs_angle = float(
                  fields[5]
              )  # observation angle [rad]
              t_data.x1 = float(fields[6])  # left   [px]
              t_data.y1 = float(fields[7])  # top    [px]
              t_data.x2 = float(fields[8])  # right  [px]
              t_data.y2 = float(fields[9])  # bottom [px]
              t_data.h = float(fields[10])  # height [m]
              t_data.w = float(fields[11])  # width  [m]
              t_data.l = float(fields[12])  # length [m]
              t_data.X = float(fields[13])  # X [m]
              t_data.Y = float(fields[14])  # Y [m]
              t_data.Z = float(fields[15])  # Z [m]
              t_data.yaw = float(fields[16])  # yaw angle [rad]
              if not loading_groundtruth:
                  if len(fields) == 17:
                      t_data.score = -1
                  elif len(fields) == 18:
                      t_data.score = float(
                          fields[17]
                      )  # detection score
                  else:
                      logger.info("file is not in KITTI format")
                      return
  
              # do not consider objects marked as invalid
              if (
                  t_data.track_id is -1
                  and t_data.obj_type != "dontcare"
              ):
                  continue
  
              idx = t_data.frame
              # check if length for frame data is sufficient
              if idx >= len(f_data):
                  print("extend f_data", idx, len(f_data))
                  f_data += [
                      [] for x in range(max(500, idx - len(f_data)))
                  ]
              try:
                  id_frame = (t_data.frame, t_data.track_id)
                  if (
                      id_frame in id_frame_cache
                      and not loading_groundtruth
                  ):
                      logger.info(
                          "track ids are not unique for sequence %d: frame %d"
                          % (seq, t_data.frame)
                      )
                      logger.info(
                          "track id %d occurred at least twice for this frame"
                          % t_data.track_id
                      )
                      logger.info("Exiting...")
                      # continue # this allows to evaluate non-unique result files
                      return False
                  id_frame_cache.append(id_frame)
                  f_data[t_data.frame].append(copy.copy(t_data))
              except:
                  print(len(f_data), idx)
                  raise
  
              if (
                  t_data.track_id not in ids
                  and t_data.obj_type != "dontcare"
              ):
                  ids.append(t_data.track_id)
                  n_trajectories += 1
                  n_in_seq += 1
  
              # check if uploaded data provides information for 2D and 3D evaluation
              if (
                  not loading_groundtruth
                  and eval_2d is True
                  and (
                      t_data.x1 == -1
                      or t_data.x2 == -1
                      or t_data.y1 == -1
                      or t_data.y2 == -1
                  )
              ):
                  eval_2d = False
              if (
                  not loading_groundtruth
                  and eval_3d is True
                  and (
                      t_data.X == -1000
                      or t_data.Y == -1000
                      or t_data.Z == -1000
                  )
              ):
                  eval_3d = False
  
          # only add existing frames
          n_trajectories_seq.append(n_in_seq)
          seq_data.append(f_data)
          f.close()
  
      if not loading_groundtruth:
          self.tracker = seq_data
          self.n_tr_trajectories = n_trajectories
          self.eval_2d = eval_2d
          self.eval_3d = eval_3d
          self.n_tr_seq = n_trajectories_seq
          if self.n_tr_trajectories == 0:
              return False
      else:
          # split ground truth and DontCare areas
          self.dcareas = []
          self.groundtruth = []
          for seq_idx in range(len(seq_data)):
              seq_gt = seq_data[seq_idx]
              s_g, s_dc = [], []
              for f in range(len(seq_gt)):
                  all_gt = seq_gt[f]
                  g, dc = [], []
                  for gg in all_gt:
                      if gg.obj_type == "dontcare":
                          dc.append(gg)
                      else:
                          g.append(gg)
                  s_g.append(g)
                  s_dc.append(dc)
              self.dcareas.append(s_dc)
              self.groundtruth.append(s_g)
          self.n_gt_seq = n_trajectories_seq
          self.n_gt_trajectories = n_trajectories
      return True
  
imports: from __future__ import absolute_import
  from __future__ import division
  from __future__ import print_function
  import os
  import copy
  import sys
  import math
  from collections import defaultdict
  import numpy
  from ppdet.modeling.bbox_utils import bbox_iou_np_expand
  from .map_utils import ap_per_class
  from .metrics import Metric
  from .munkres import Munkres
  from ppdet.utils.logger import setup_logger
label_desc: Use image node_id 4 for calling the KITTIEvaluation obj's underlying member method code with example usage: obj._loadData(root_dir, cls, min_score, loading_groundtruth) and returns: True, False, False