open-mmlab/mmdetection · error · KeyError

In the image with ID {} the following segment IDs {} are pre

Error message

In the image with ID {} the following segment IDs {} are presented in JSON and not presented in PNG.

What it means

Inverse consistency check of error 68: every id listed in segments_info must appear as a nonzero label in the prediction PNG. Leftover JSON ids not found in the PNG raise KeyError listing the missing ids.

Source

Thrown at mmdet/evaluation/functional/panoptic_utils.py:104

        labels, labels_cnt = np.unique(pan_pred, return_counts=True)
        for label, label_cnt in zip(labels, labels_cnt):
            if label not in pred_segms:
                if label == VOID:
                    continue
                raise KeyError(
                    'In the image with ID {} segment with ID {} is '
                    'presented in PNG and not presented in JSON.'.format(
                        gt_ann['image_id'], label))
            pred_segms[label]['area'] = label_cnt
            pred_labels_set.remove(label)
            if pred_segms[label]['category_id'] not in categories:
                raise KeyError(
                    'In the image with ID {} segment with ID {} has '
                    'unknown category_id {}.'.format(
                        gt_ann['image_id'], label,
                        pred_segms[label]['category_id']))
        if len(pred_labels_set) != 0:
            raise KeyError(
                'In the image with ID {} the following segment IDs {} '
                'are presented in JSON and not presented in PNG.'.format(
                    gt_ann['image_id'], list(pred_labels_set)))

        # confusion matrix calculation
        pan_gt_pred = pan_gt.astype(np.uint64) * OFFSET + pan_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():

View on GitHub (pinned to cfd5d3a985)

Solutions

  1. Write the PNG and segments_info from the same final segment set (single source of truth)
  2. Use int32-safe PNG encoding so large ids are not truncated
  3. Filter both JSON and PNG consistently when applying min-area/size thresholds

Example fix

# before
# JSON ids {1,2,3}; PNG contains {1,2} only
# after
result_panpng[seg_mask] = seg['id']  # write every seg in segments_info to PNG
json.dump({'segments_info': segments_info, ...}, f)
Defensive patterns

Strategy: validation

Validate before calling

png_ids = set(np.unique(pan_png)) - {0}
json_ids = {s['id'] for s in segments_info}
assert png_ids == json_ids, f'missing in PNG: {json_ids - png_ids}'

Try / catch

try:
    pq_compute_single_core(...)
except KeyError as e:
    if 'not presented in PNG' in str(e):
        raise ValueError('Regenerate PNG so all JSON segment ids are painted') from e
    raise

Prevention

When it happens

Trigger: segments_info entries kept for segments that were dropped, merged, or fully suppressed when writing the PNG; tiny segments lost to resizing; empty masks encoded as absent.

Common situations: Postprocessing that filters PNG masks (e.g. min-area threshold) without updating JSON; PNG encoding that maps some ids to 0 due to dtype overflow (ids > 65535 in uint16).

Related errors


AI-assisted analysis of open-mmlab/mmdetection@cfd5d3a985 (2026-08-27). Data as JSON: /api/errors/8df239faf4b9cbde. Report an issue: GitHub.