FAQ

Formats

The COCO JSON format, explained field by field

What every key in a COCO annotation file means, how segmentation and bbox differ, and the silent mistakes that corrupt a training run without making a loader throw.

COCO is the lingua franca of object detection. Almost every vision framework will read it, which means almost every dataset you download has been bent into it at some point — sometimes badly. Here is what each field actually means.

The five top-level keys

A COCO annotation file is a single JSON object. Only three of its keys carry data you need: images, annotations and categories. The other two, info and licenses, are metadata that most loaders ignore entirely — though you should fill them in, because they are the only place the provenance of a derived dataset survives.

The structure is relational, not nested. Images do not contain their annotations. Instead every annotation carries an image_id that points back at an entry in images, and a category_id that points at categories. That is why a COCO file stays easy to join and validate: the three lists are independent and linked only by ids, though most loaders still parse the whole document into memory.

the skeleton
{
  "info": {"description": "...", "version": "1.0", "year": 2026},
  "licenses": [{"id": 1, "name": "CC BY 4.0", "url": "..."}],
  "images": [
    {"id": 1, "file_name": "000001.jpg", "width": 640, "height": 480, "license": 1}
  ],
  "annotations": [
    {"id": 1, "image_id": 1, "category_id": 3,
     "bbox": [x, y, width, height], "area": 1234.5,
     "segmentation": [[x1,y1, x2,y2, ...]], "iscrowd": 0}
  ],
  "categories": [
    {"id": 3, "name": "car", "supercategory": "vehicle"}
  ]
}
The same object in three conventions. A corner/centre mix-up shifts a box by half its size, so a wrong conversion looks fine on small objects and is badly wrong on large ones.

bbox is not what most people assume

The single most common error in hand-written COCO files is the bounding box convention. COCO's bbox is [x_min, y_min, width, height] in absolute pixels, with the origin at the top left of the image.

It is not [x_min, y_min, x_max, y_max] — that is Pascal VOC. It is not normalised to 0–1 — that is YOLO. And it is not centre-based — that is YOLO too. Converting between them is three lines of arithmetic, but getting the direction wrong produces boxes that look plausible on small objects and wildly wrong on large ones, which is exactly the failure mode that survives a quick eyeball check and ruins a training run.

FormatBox encodingUnits
COCOx_min, y_min, w, habsolute pixels
Pascal VOCx_min, y_min, x_max, y_maxabsolute pixels
YOLOx_centre, y_centre, w, hnormalised 0–1
Albumentationsx_min, y_min, x_max, y_maxnormalised 0–1

segmentation has two different shapes

The segmentation field is polymorphic, and which shape you get depends on iscrowd. This catches people who write a loader against one half of a dataset and then hit the other half.

When iscrowd is 0, segmentation is a list of polygons, each a flat list of alternating x and y coordinates: [[x1, y1, x2, y2, ...]]. An object split by occlusion gets several polygons in that outer list.

When iscrowd is 1, the object is a crowd region — a pile of bicycles, a stadium of people — and segmentation becomes a run-length encoding object instead: {"counts": ..., "size": [h, w]}. You need pycocotools to decode it. Models are conventionally not penalised on crowd regions during evaluation, which is the entire reason the flag exists.

A street photograph with detection output drawn on it. Several parked cars and two benches are each enclosed in a coloured bounding box with a class label, and the same objects additionally carry a translucent instance mask that follows their outline rather than their box.
Instance-segmentation output for one image: each object gets an axis-aligned box and a mask that follows its outline — the same distinction as the bbox and segmentation fields of a COCO annotation. Image: open-mmlab/mmdetection · Apache-2.0 repository

area, and why it decides your metrics

area is the pixel area of the segmentation mask, not of the bounding box. For a diagonal object the two differ by a lot, and COCO evaluation buckets objects into small (area < 32²), medium and large (area > 96²) using this field.

A histogram of number of images against bounding-box ship area (0 to 5.5 × 10^4 pixels): a tall first bar near 1,700 labelled small, a few bars between about 30 and 360 labelled medium, and a long flat tail labelled large.
Ship areas in the SAR Ship Detection Dataset, measured from axis-aligned boxes, with the dataset's own small, medium and large ranges marked. Almost all ships fall in the first few bins. The authors set these ranges for their data rather than reuse COCO's 32² and 96² pixel cut-offs, and the thresholds you apply decide which bucket, and which metric, an object counts towards. Image (panel a, cropped): Figure 15a of the article · CC BY 4.0 · from Zhang et al. 2021, Remote Sensing, “SAR Ship Detection Dataset (SSDD): Official Release and Comprehensive Data Analysis”, doi:10.3390/rs13183690

If you populate area from the bbox because you have no masks, your per-size breakdown shifts and your numbers stop being comparable to published results on the same dataset. That is acceptable as long as you say so; it is a silent problem if you do not.

Stacked precision-recall curves titled 'overall-all-all', precision on the y-axis and recall on the x-axis. The legend gives the area under each curve: C75 .399, C50 .589, Loc .682, Sim .695, Oth .713, BG .870 and FN 1.00; the blue Loc band and the purple BG band are the widest.
COCO's own error analysis of the 2015 winning detector, averaged over all categories: AP is .399 at IoU 0.75 and .589 at 0.5, rising to .682 once localisation errors are forgiven. The official tool repeats this breakdown for small, medium and large objects, and each annotation's area field decides which of those it counts in. Image: cocodataset/cocodataset.github.io · CC BY 4.0 (COCO website and annotations)

Category ids are not zero-indexed, and that is contagious

In the original MS COCO release the 80 categories carry ids running up to 90, with gaps — the ids are historical and not contiguous. Several frameworks silently remap them to a dense 0–79 range internally, and several do not.

The practical consequence: a class index printed by your training loop may not be the category_id in your file. Before you debug a model that seems to confuse two classes, check whether you are looking at a remapping artefact. Keep an explicit id-to-name mapping next to your checkpoint and you never have to ask the question twice.

validating a file before you train on it
import json, collections

d = json.load(open("annotations.json"))
imgs = {i["id"]: i for i in d["images"]}
cats = {c["id"] for c in d["categories"]}

bad = collections.Counter()
for a in d["annotations"]:
    im = imgs.get(a["image_id"])
    if im is None:                      bad["orphan annotation"] += 1; continue
    if a["category_id"] not in cats:    bad["unknown category"]  += 1
    x, y, w, h = a["bbox"]
    if w <= 0 or h <= 0:                bad["degenerate box"]    += 1
    if x < 0 or y < 0:                  bad["negative origin"]   += 1
    if x + w > im["width"] + 1 or y + h > im["height"] + 1:
                                        bad["box outside image"] += 1

print(f"{len(d['annotations'])} annotations, {len(d['images'])} images")
print(dict(bad) or "clean")

Questions people ask

Does COCO support keypoints and captions too?

Yes — they are separate annotation files over the same images. Keypoint annotations add keypoints (a flat list of x, y, visibility triplets) and num_keypoints, and the category carries a keypoints name list plus a skeleton of index pairs. Captions drop the geometry fields entirely and carry a caption string.

Can one image have zero annotations?

Yes, and it should if the image genuinely contains nothing. Negative examples are useful training signal. The image entry exists in images and simply has no annotation pointing at it. Some loaders drop such images by default, which quietly removes your negatives — check the flag before you assume they are being used.

What is the difference between COCO the format and COCO the dataset?

MS COCO is a specific dataset of around 330,000 images with 80 object categories. The format is the JSON layout it shipped with, which the ecosystem then adopted for everything else. A file being 'in COCO format' tells you nothing about which images or classes are inside it.

How large can a COCO file get before it becomes a problem?

The format keeps everything in one JSON document, so a large instance-segmentation set can reach hundreds of megabytes and will be parsed into memory in full by most loaders. Past that point people usually shard by split, or convert to a columnar or record format for training while keeping COCO as the interchange copy.

Stop hunting. Start searching.

Tens of thousands of curated datasets, searchable in plain language — with the licence and size checked before you download anything.

Search Dataset Finder →