YOLO format compatibility matrix

AnnotateIt reads and writes YOLO detection and instance-segmentation datasets, and does not read or write YOLO pose or OBB. Because YOLOv5, YOLOv8 and YOLOv11 share one label-row grammar, there is no per-version importer: what decides whether an archive works is the row shape and the class list, not the version number on the box. This page is the full matrix, including what is refused and why.

Everything below is read out of the importer and exporter source, and the conversion behaviour is locked down by tests that fail if an exporter changes without this page changing with it (src/offline/dataset-io/coco-yolo-round-trip.test.ts and exporters/shape-format-matrix.test.ts).

YOLOv5, YOLOv8 and YOLOv11

These three are usually presented as three formats. For annotation data they are very nearly one. A label file is still one plain-text row per object, still a class index followed by numbers normalised to the image, and a detection row written for YOLOv5 is byte-identical to one written for YOLOv11. What actually changed between them is the dataset descriptor and the set of tasks the framework offers.

GenerationWhat differs in the dataAnnotateIt
YOLOv5data.yaml with names as a list (names: [person, car]) and nc:; Darknet-style obj.names also commonRead — both forms
YOLOv8data.yaml with names as an index map (names: {0: person, 1: car}); adds segment, pose and obb tasksRead — detect and segment rows
YOLOv11Same descriptor and same row grammar as v8; the changes are in the model, not the labelsRead — detect and segment rows

So the honest statement is not “AnnotateIt supports YOLOv8”. It is that AnnotateIt reads the YOLO label grammar and both descriptor dialects, which covers v5, v8 and v11 datasets for the two tasks it supports — and does not silently accept the task-specific row shapes it does not support.

Task matrix

YOLO taskRow shapeImportExport
Detectionclass cx cy w hYes — becomes a bounding boxYes — from an object-detection project
Instance segmentationclass x1 y1 x2 y2 … (even count, ≥ 6 values)Yes — becomes a polygonYes — from an instance-segmentation project
Pose / keypointsclass cx cy w h then x y [v] per jointNo — a dataset declaring kpt_shape or flip_idx is rejected with an errorNo — YOLO is not offered for a keypoint project
Oriented boxes (OBB)class x1 y1 x2 y2 x3 y3 x4 y4Partly — read as a 4-point polygon; the angle is not reconstructedNo — a rotated box exports as its axis-aligned bounds
ClassificationFolder-per-class, no label filesNo — see belowYes — from a single-label classification project

Two of those rows deserve their reasoning rather than just a “no”:

  • Pose is refused, not guessed — and the signal it is refused on matters. A pose row is “class cx cy w h” followed by a flat coordinate list, which is the same grammar as a segmentation polygon; the two cannot be told apart from the row alone. Ultralytics declares the layout as kpt_shape: [joints, dimensions] in the dataset YAML, and AnnotateIt refuses any archive carrying it, whichever layout it names — [N, 2] without visibility just as much as [N, 3] with it. YAML can spell that value as a flow sequence, an indented block or a quoted scalar, and all three are recognised; a kpt_shape that cannot be parsed is also a refusal rather than a shrug, because “present but not understood” collapsing into “absent” is precisely how a pose dataset would slip through as polygons. flip_idx, the other key only a pose dataset carries, counts as the same declaration. Without any declaration at all, only the common COCO-17 case is caught on its own, because 4 + 17×3 happens to be an odd number of values and fails row validation; a pose archive that ships no YAML and uses an even value count is genuinely ambiguous and would be read as polygons.
  • Classification import is refused on purpose. A YOLO object row labels a box inside the image, not the image as a whole, so offering to import one as an image-level class would misrepresent the data. External YOLO classification datasets are folder-per-class with no label files at all, and that import path is not implemented. AnnotateIt can export this layout from a single-label classification project; multi-label, hierarchical, unlabeled and anomaly samples are rejected rather than flattened into incorrect classes.

The OBB row is the one place where a YOLO archive can be misread, and it is unavoidable: an oriented-box row and a four-vertex segmentation polygon are the same eight numbers. AnnotateIt reads them as a polygon, which keeps every corner in the right place — you lose the knowledge that it was meant to be a rectangle, not the geometry. Export it as Datumaro if you need an angle to survive.

Class lists the importer accepts

An archive is only recognised as YOLO if a class list is found, because the class index in every row is meaningless without one. Any of these will do:

FormExample
A file ending in obj.namesOne class name per line
YAML inline listnames: [person, forklift, helmet]
YAML block listnames: then - person, - forklift on following lines
YAML inline mapnames: {0: person, 1: forklift}
YAML block mapnames: then 0: person, 1: forklift on following lines

Quoted scalars, escaped quotes and trailing # comments are handled, and an index map is sorted by index rather than by reading order. Where a map is used, the index in the file is authoritative; where a list is used, position is the index. Either way the order is the contract — a class list in a different order to the one the labels were written with shifts every class in the dataset, and nothing in the format can detect that.

Train / validation / test structure

What AnnotateIt writes

Two layouts, depending on whether the dataset has a saved split and you export in split mode.

Split mode — the Ultralytics layout, trains as-is
export.zip
├── data.yaml           # path/train/val/test + nc + names index map
├── images/
│   ├── train/…
│   ├── val/…
│   └── test/…
└── labels/
    ├── train/…
    ├── val/…
    └── test/…
Without splits — the Darknet-style layout
export.zip
├── obj.names           # one class per line
├── obj.data            # classes / names / train
├── train.txt           # list of image paths
└── obj_train_data/
    ├── img_0001.jpg
    └── img_0001.txt

In split mode the validation subset is written to val/, following the Ultralytics convention rather than the app’s internal name for it. Every image gets a label file even when it has no objects — an empty .txt is how YOLO expresses a negative example, and dropping the file instead would quietly remove those images from training.

What AnnotateIt recognises on import

  • images/train, images/val, images/test — and the training/valid/validation spellings.
  • The transposed layout: train/images, val/images, test/images.
  • An AnnotateIt annotateit-splits.json manifest, which wins over folder guessing when present because it carries the ratios, seed and per-image assignments the standard cannot.

A split recovered from folders alone is imported as locked manual assignments with ratios derived from the observed counts — honest about the fact that the original seed and ratios are not recoverable from the layout.

Label files are matched to images by path with the extension removed, not by bare filename. That is what makes split datasets safe: labels/train/img1.txt and labels/val/img1.txt are different keys, so identically-named files in different subsets do not overwrite each other.

Import and export limitations

The format itself is the limit in most of these. A YOLO row is a class index and some coordinates; there is no field for anything else.

WhatThrough YOLOKeep it by
Pixel masksTraced to polygon rows, one per connected component — holes are filledExporting COCO (native RLE) or Datumaro
PolylinesClosed into a polygon ribbon of the stroke widthExporting Datumaro, the only format that keeps a line open
Rotated boxesFlattened to axis-aligned boundsExporting Datumaro, which stores the angle as an attribute
CirclesWritten as their bounding boxExporting Datumaro
Keypoints / posesNot offered at allExporting COCO person-keypoints or Datumaro
Attributes and iscrowdNo field exists — dropped from the standard layerExporting COCO or Datumaro, or re-importing AnnotateIt’s own archive
Text prompts, label colours, hierarchy, task schemaNo field existsThe annotateit-metadata.json sidecar, or Datumaro
VideoYOLO holds no videoExporting Datumaro, Supervisely Video, MOT or MOTS

The Export dialog lists what the chosen format will leave behind before you commit, so none of this is discovered after the fact. And every annotated export also carries an annotateit-metadata.json sidecar: the YOLO files stay a valid YOLO dataset for any trainer, while re-importing the same archive into AnnotateIt restores the attributes, prompts and hierarchy the standard had nowhere to put.

What the importer refuses

The contract is fail-closed: a well-formed archive imports completely, and anything ambiguous is rejected before a single annotation is written rather than half-imported.

  • A class index the class list does not declare — the row cannot be attributed to a class, and guessing would silently mislabel objects.
  • Coordinates outside the normalised 0–1 range, or a box with non-positive width or height. They are rejected rather than clamped: a clamped box is a wrong box that looks right.
  • A polygon with zero area.
  • A row whose value count matches neither grammar — which is how a pose file is caught.
  • A label file with no matching image.
  • Duplicate class names in the class list.

An empty label file is not an error. It is a valid negative example, and an archive whose label files are all empty is still recognised as YOLO provided it has a class list and conventional label paths — otherwise a dataset of hard negatives would import as unlabelled media.

Coordinate precision

YOLO stores fractions of the image, so a round trip through it is a division and a multiplication. Coordinates are written to six decimal places of the normalised value, so a stored vertex cannot move by more than half a step — 0.5 × 10⁻⁶ of the image, which is 6 × 10⁻⁴ pixels on a 1200-pixel axis. A box corner is worse by half again, because it is reconstructed from two separately rounded numbers as cx − w/2, putting its ceiling at 9 × 10⁻⁴ pixels. Those are arithmetic bounds, and the round-trip test asserts them across a 128-shape sweep that reaches 6 × 10⁻⁴ pixels at its worst. Geometry is not where YOLO loses data; the missing fields are.

See also

Video tutorial

AnnotateIt tutorial