code: def update(self, sample_dict, pp_out_dict):
      VOID = 0  # id==0 stands for area to be ignored
  
      pred = pp_out_dict["pan_pred"].squeeze().numpy()
      gt = sample_dict["pan_label"].squeeze().numpy()
      # Use sample['ann'], rather than parsing info from gt.
      # Note that the consistency between gt and gt_ann must be ensured.
      gt_ann = sample_dict["ann"][0]
      if self.convert_id is not None:
          for el in gt_ann:
              el["category_id"] = self.convert_id(el["category_id"])
  
      pred_ann = []
      labels, labels_cnt = np.unique(pred, return_counts=True)
      for label, label_cnt in zip(labels, labels_cnt):
          if label == VOID:
              continue
          cat_id, _ = decode_pan_id(label, self.label_divisor)
          if self.convert_id is not None:
              cat_id = self.convert_id(cat_id)
          pred_ann.append(
              {"id": label, "category_id": cat_id, "area": label_cnt}
          )
  
      gt_segms = {el["id"]: el for el in gt_ann}
      pred_segms = {el["id"]: el for el in pred_ann}
  
      # Calculate confusion matrix
      pan_gt_pred = gt.astype(np.uint64) * OFFSET + pred.astype(
          np.uint64
      )
      gt_pred_map = {}
      labels, labels_cnt = np.unique(pan_gt_pred, return_counts=True)
      for label, intersection in zip(labels, labels_cnt):
          gt_id = label // OFFSET
          pred_id = label % OFFSET
          gt_pred_map[(gt_id, pred_id)] = intersection
  
      # Count all matched pairs
      gt_matched = set()
      pred_matched = set()
      for label_tuple, intersection in gt_pred_map.items():
          gt_label, pred_label = label_tuple
          if gt_label not in gt_segms:
              continue
          if pred_label not in pred_segms:
              continue
          if gt_segms[gt_label]["iscrowd"] == 1:
              continue
          if (
              gt_segms[gt_label]["category_id"]
              != pred_segms[pred_label]["category_id"]
          ):
              continue
  
          union = (
              pred_segms[pred_label]["area"]
              + gt_segms[gt_label]["area"]
              - intersection
              - gt_pred_map.get((VOID, pred_label), 0)
          )
          iou = intersection / union
          if iou > 0.5:
              self.pq_stat[gt_segms[gt_label]["category_id"]].tp += 1
              self.pq_stat[gt_segms[gt_label]["category_id"]].iou += iou
              gt_matched.add(gt_label)
              pred_matched.add(pred_label)
  
      crowd_labels_dict = {}
      for gt_label, gt_info in gt_segms.items():
          if gt_label in gt_matched:
              continue
          # Ignore crowd seegments
          if gt_info["iscrowd"] == 1:
              crowd_labels_dict[gt_info["category_id"]] = gt_label
              continue
          self.pq_stat[gt_info["category_id"]].fn += 1
  
      for pred_label, pred_info in pred_segms.items():
          if pred_label in pred_matched:
              continue
          intersection = gt_pred_map.get((VOID, pred_label), 0)
  
          if pred_info["category_id"] in crowd_labels_dict:
              intersection += gt_pred_map.get(
                  (
                      crowd_labels_dict[pred_info["category_id"]],
                      pred_label,
                  ),
                  0,
              )
          if intersection / pred_info["area"] > 0.5:
              continue
          self.pq_stat[pred_info["category_id"]].fp += 1
  
imports: from collections import defaultdict
  import numpy
  from paddlepanseg.cvlibs import build_info_dict
  from paddlepanseg.utils import decode_pan_id
  from .evaluator import Evaluator
label_desc: Use image node_id 2 for calling the PanSegEvaluator obj's underlying member method code with example usage: obj.update(sample_dict, pp_out_dict) without return types