code: def eval_map(
      det_results,
      annotations,
      scale_ranges=None,
      iou_thr=0.5,
      ioa_thr=None,
      dataset=None,
      logger=None,
      tpfp_fn=None,
      nproc=4,
      use_legacy_coordinate=False,
      use_group_of=False,
      eval_mode="area",
  ):
      """Evaluate mAP of a dataset.
  
      Args:
          det_results (list[list]): [[cls1_det, cls2_det, ...], ...].
              The outer list indicates images, and the inner list indicates
              per-class detected bboxes.
          annotations (list[dict]): Ground truth annotations where each item of
              the list indicates an image. Keys of annotations are:
  
              - `bboxes`: numpy array of shape (n, 4)
              - `labels`: numpy array of shape (n, )
              - `bboxes_ignore` (optional): numpy array of shape (k, 4)
              - `labels_ignore` (optional): numpy array of shape (k, )
          scale_ranges (list[tuple] | None): Range of scales to be evaluated,
              in the format [(min1, max1), (min2, max2), ...]. A range of
              (32, 64) means the area range between (32**2, 64**2).
              Defaults to None.
          iou_thr (float): IoU threshold to be considered as matched.
              Defaults to 0.5.
          ioa_thr (float | None): IoA threshold to be considered as matched,
              which only used in OpenImages evaluation. Defaults to None.
          dataset (list[str] | str | None): Dataset name or dataset classes,
              there are minor differences in metrics for different datasets, e.g.
              "voc", "imagenet_det", etc. Defaults to None.
          logger (logging.Logger | str | None): The way to print the mAP
              summary. See `mmengine.logging.print_log()` for details.
              Defaults to None.
          tpfp_fn (callable | None): The function used to determine true/
              false positives. If None, :func:`tpfp_default` is used as default
              unless dataset is 'det' or 'vid' (:func:`tpfp_imagenet` in this
              case). If it is given as a function, then this function is used
              to evaluate tp & fp. Default None.
          nproc (int): Processes used for computing TP and FP.
              Defaults to 4.
          use_legacy_coordinate (bool): Whether to use coordinate system in
              mmdet v1.x. which means width, height should be
              calculated as 'x2 - x1 + 1` and 'y2 - y1 + 1' respectively.
              Defaults to False.
          use_group_of (bool): Whether to use group of when calculate TP and FP,
              which only used in OpenImages evaluation. Defaults to False.
          eval_mode (str): 'area' or '11points', 'area' means calculating the
              area under precision-recall curve, '11points' means calculating
              the average precision of recalls at [0, 0.1, ..., 1],
              PASCAL VOC2007 uses `11points` as default evaluate mode, while
              others are 'area'. Defaults to 'area'.
  
      Returns:
          tuple: (mAP, [dict, dict, ...])
      """
      assert len(det_results) == len(annotations)
      assert eval_mode in ["area", "11points"], (
          f'Unrecognized {eval_mode} mode, only "area" and "11points" '
          "are supported"
      )
      if not use_legacy_coordinate:
          extra_length = 0.0
      else:
          extra_length = 1.0
  
      num_imgs = len(det_results)
      num_scales = len(scale_ranges) if scale_ranges is not None else 1
      num_classes = len(det_results[0])  # positive class num
      area_ranges = (
          [(rg[0] ** 2, rg[1] ** 2) for rg in scale_ranges]
          if scale_ranges is not None
          else None
      )
  
      # There is no need to use multi processes to process
      # when num_imgs = 1 .
      if num_imgs > 1:
          assert nproc > 0, "nproc must be at least one."
          nproc = min(nproc, num_imgs)
          pool = Pool(nproc)
  
      eval_results = []
      for i in range(num_classes):
          # get gt and det bboxes of this class
          cls_dets, cls_gts, cls_gts_ignore = get_cls_results(
              det_results, annotations, i
          )
          # choose proper function according to datasets to compute tp and fp
          if tpfp_fn is None:
              if dataset in ["det", "vid"]:
                  tpfp_fn = tpfp_imagenet
              elif (
                  dataset in ["oid_challenge", "oid_v6"]
                  or use_group_of is True
              ):
                  tpfp_fn = tpfp_openimages
              else:
                  tpfp_fn = tpfp_default
          if not callable(tpfp_fn):
              raise ValueError(
                  f"tpfp_fn has to be a function or None, but got {tpfp_fn}"
              )
  
          if num_imgs > 1:
              # compute tp and fp for each image with multiple processes
              args = []
              if use_group_of:
                  # used in Open Images Dataset evaluation
                  gt_group_ofs = get_cls_group_ofs(annotations, i)
                  args.append(gt_group_ofs)
                  args.append([use_group_of for _ in range(num_imgs)])
              if ioa_thr is not None:
                  args.append([ioa_thr for _ in range(num_imgs)])
  
              tpfp = pool.starmap(
                  tpfp_fn,
                  zip(
                      cls_dets,
                      cls_gts,
                      cls_gts_ignore,
                      [iou_thr for _ in range(num_imgs)],
                      [area_ranges for _ in range(num_imgs)],
                      [use_legacy_coordinate for _ in range(num_imgs)],
                      *args,
                  ),
              )
          else:
              tpfp = tpfp_fn(
                  cls_dets[0],
                  cls_gts[0],
                  cls_gts_ignore[0],
                  iou_thr,
                  area_ranges,
                  use_legacy_coordinate,
                  gt_bboxes_group_of=(
                      get_cls_group_ofs(annotations, i)[0]
                      if use_group_of
                      else None
                  ),
                  use_group_of=use_group_of,
                  ioa_thr=ioa_thr,
              )
              tpfp = [tpfp]
  
          if use_group_of:
              tp, fp, cls_dets = tuple(zip(*tpfp))
          else:
              tp, fp = tuple(zip(*tpfp))
          # calculate gt number of each scale
          # ignored gts or gts beyond the specific scale are not counted
          num_gts = np.zeros(num_scales, dtype=int)
          for j, bbox in enumerate(cls_gts):
              if area_ranges is None:
                  num_gts[0] += bbox.shape[0]
              else:
                  gt_areas = (
                      bbox[:, 2] - bbox[:, 0] + extra_length
                  ) * (bbox[:, 3] - bbox[:, 1] + extra_length)
                  for k, (min_area, max_area) in enumerate(area_ranges):
                      num_gts[k] += np.sum(
                          (gt_areas >= min_area) & (gt_areas < max_area)
                      )
          # sort all det bboxes by score, also sort tp and fp
          cls_dets = np.vstack(cls_dets)
          num_dets = cls_dets.shape[0]
          sort_inds = np.argsort(-cls_dets[:, -1])
          tp = np.hstack(tp)[:, sort_inds]
          fp = np.hstack(fp)[:, sort_inds]
          # calculate recall and precision with tp and fp
          tp = np.cumsum(tp, axis=1)
          fp = np.cumsum(fp, axis=1)
          eps = np.finfo(np.float32).eps
          recalls = tp / np.maximum(num_gts[:, np.newaxis], eps)
          precisions = tp / np.maximum((tp + fp), eps)
          # calculate AP
          if scale_ranges is None:
              recalls = recalls[0, :]
              precisions = precisions[0, :]
              num_gts = num_gts.item()
          ap = average_precision(recalls, precisions, eval_mode)
          eval_results.append(
              {
                  "num_gts": num_gts,
                  "num_dets": num_dets,
                  "recall": recalls,
                  "precision": precisions,
                  "ap": ap,
              }
          )
  
      if num_imgs > 1:
          pool.close()
  
      if scale_ranges is not None:
          # shape (num_classes, num_scales)
          all_ap = np.vstack(
              [cls_result["ap"] for cls_result in eval_results]
          )
          all_num_gts = np.vstack(
              [cls_result["num_gts"] for cls_result in eval_results]
          )
          mean_ap = []
          for i in range(num_scales):
              if np.any(all_num_gts[:, i] > 0):
                  mean_ap.append(
                      all_ap[all_num_gts[:, i] > 0, i].mean()
                  )
              else:
                  mean_ap.append(0.0)
      else:
          aps = []
          for cls_result in eval_results:
              if cls_result["num_gts"] > 0:
                  aps.append(cls_result["ap"])
          mean_ap = np.array(aps).mean().item() if aps else 0.0
  
      print_map_summary(
          mean_ap, eval_results, dataset, area_ranges, logger=logger
      )
  
      return mean_ap, eval_results
  
file_path: mmdetection/mmdet/evaluation/functional/mean_ap.py
imports: from multiprocessing import Pool
  import numpy
  from mmengine.logging import print_log
  from mmengine.utils import is_str
  from terminaltables import AsciiTable
  from .bbox_overlaps import bbox_overlaps
  from .class_names import get_classes
label_desc: Use image node_id 7 for calling a global function with example usage: eval_map(det_results, annotations, scale_ranges, iou_thr, ioa_thr, dataset, logger, tpfp_fn, nproc, use_legacy_coordinate, use_group_of, eval_mode) and returns: mean_ap,  eval_results