Lesson 07: Export Formats & Pipelines
You have annotated your images. Now you need to get those labels into a format your training framework understands. AnyLabeling exports to four formats natively, and each one maps to a different set of training tools.
The Four Export Formats
YOLO Format
Output: One .txt file per image + a classes.txt file.
Structure:
dataset/
├── images/
│ ├── img_001.jpg
│ └── img_002.jpg
├── labels/
│ ├── img_001.txt
│ └── img_002.txt
└── classes.txt
Label file format (per line):
<class_id> <center_x> <center_y> <width> <height>
All coordinates are normalized to [0, 1] relative to image dimensions.
Best for: Ultralytics YOLOv5, YOLOv8, YOLO11, and any YOLO-family trainer.
How to export:
- Go to
Tools > Export Annotations > Export YOLO Annotations. - Select the task type (detection, segmentation, OBB, or keypoints).
- Provide a
classes.txtor let AnyLabeling generate one from your labels. - Click OK. Labels are saved to a
labels/subfolder by default.
Segmentation variant: For instance segmentation, each line contains the class ID followed by polygon coordinates:
<class_id> <x1> <y1> <x2> <y2> ... <xn> <yn>. All coordinates normalized.
COCO Format
Output: A single annotations.json file containing all images and annotations.
Structure:
{
"images": [{ "id": 1, "file_name": "img_001.jpg", "width": 1280, "height": 720 }],
"annotations": [
{
"id": 1,
"image_id": 1,
"category_id": 1,
"bbox": [100, 150, 300, 200],
"area": 60000,
"segmentation": [[100, 150, 400, 150, 400, 350, 100, 350]],
"iscrowd": 0
}
],
"categories": [{ "id": 1, "name": "car" }]
}
Best for: Detectron2, MMDetection, TensorFlow Object Detection API, DETR, and most research frameworks.
How to export:
- Go to
Tools > Export Annotations > Export COCO Annotations. - Select the task (detection, segmentation, or keypoints).
- Configure options and click OK.
- The export runs in a background thread (can take time for large datasets) and produces a single JSON file.
COCO bbox format:
[x_min, y_min, width, height]in absolute pixels. This is different from YOLO's normalized center format. Do not confuse them.
Pascal VOC Format
Output: One .xml file per image.
Structure:
<annotation>
<folder>images</folder>
<filename>img_001.jpg</filename>
<size>
<width>1280</width>
<height>720</height>
<depth>3</depth>
</size>
<object>
<name>car</name>
<bndbox>
<xmin>100</xmin>
<ymin>150</ymin>
<xmax>400</xmax>
<ymax>350</ymax>
</bndbox>
</object>
</annotation>
Best for: Legacy systems, TensorFlow 1.x object detection, any pipeline expecting VOC-style XML.
How to export:
- Go to
Tools > Export Annotations > Export VOC Annotations. - Configure and click OK.
- XML files are saved to an
Annotations/subfolder.
VOC bbox format:
[xmin, ymin, xmax, ymax]in absolute pixels. A third coordinate convention to keep straight.
CreateML Format
Output: A annotations.json file in Apple's CreateML format.
Best for: Training models with Apple's CreateML for iOS/macOS deployment.
Choosing the Right Format
| Training Framework | Format | Notes |
|---|---|---|
| Ultralytics (YOLOv5/v8/11) | YOLO | Native format, no conversion needed |
| Detectron2 | COCO | Register with register_coco_instances() |
| MMDetection | COCO | Supported natively |
| TensorFlow Object Detection | VOC or COCO | TFRecord conversion still needed |
| PaddleDetection | COCO | Supported natively |
| Apple CreateML | CreateML | Native format |
| Custom PyTorch training | COCO | Most flexible; easy to parse with pycocotools |
If you are unsure, export to COCO. It is the most widely supported format and preserves the most information (bounding boxes, segmentation polygons, keypoints, and area).
Coordinate System Summary
This trips people up constantly:
| Format | Bbox Convention | Coordinates |
|---|---|---|
| YOLO | center_x, center_y, width, height | Normalized [0,1] |
| COCO | x_min, y_min, width, height | Absolute pixels |
| VOC | x_min, y_min, x_max, y_max | Absolute pixels |
A box at pixel position (100, 150) with size (300, 200) in a 1280x720 image:
YOLO: 0 0.1953 0.3472 0.2344 0.2778
COCO: {"bbox": [100, 150, 300, 200]}
VOC: <xmin>100</xmin> <ymin>150</ymin> <xmax>400</xmax> <ymax>350</ymax>
Format Conversion with Python
Sometimes you need a format AnyLabeling does not export directly, or you need to transform the export. Here are the conversions you will use most:
COCO to YOLO
import json
from pathlib import Path
def coco_to_yolo(coco_json_path, output_dir):
with open(coco_json_path) as f:
coco = json.load(f)
# Build lookups
images = {img["id"]: img for img in coco["images"]}
categories = {cat["id"]: idx for idx, cat in enumerate(coco["categories"])}
output_dir = Path(output_dir)
output_dir.mkdir(parents=True, exist_ok=True)
# Group annotations by image
from collections import defaultdict
anns_by_image = defaultdict(list)
for ann in coco["annotations"]:
anns_by_image[ann["image_id"]].append(ann)
for image_id, anns in anns_by_image.items():
img = images[image_id]
w, h = img["width"], img["height"]
stem = Path(img["file_name"]).stem
lines = []
for ann in anns:
cls_id = categories[ann["category_id"]]
bx, by, bw, bh = ann["bbox"]
# Convert COCO (xmin, ymin, w, h) to YOLO (cx, cy, w, h) normalized
cx = (bx + bw / 2) / w
cy = (by + bh / 2) / h
nw = bw / w
nh = bh / h
lines.append(f"{cls_id} {cx:.6f} {cy:.6f} {nw:.6f} {nh:.6f}")
(output_dir / f"{stem}.txt").write_text("\n".join(lines))
# Write classes.txt
class_names = [cat["name"] for cat in sorted(coco["categories"], key=lambda c: categories[c["id"]])]
(output_dir / "classes.txt").write_text("\n".join(class_names))
# Usage
coco_to_yolo("annotations.json", "labels/")
YOLO to COCO
import json
from pathlib import Path
from PIL import Image
def yolo_to_coco(images_dir, labels_dir, classes_file, output_path):
classes = Path(classes_file).read_text().strip().split("\n")
categories = [{"id": i, "name": name} for i, name in enumerate(classes)]
images_dir = Path(images_dir)
labels_dir = Path(labels_dir)
coco = {"images": [], "annotations": [], "categories": categories}
ann_id = 0
for img_id, img_path in enumerate(sorted(images_dir.glob("*"))):
if img_path.suffix.lower() not in (".jpg", ".jpeg", ".png", ".bmp"):
continue
img = Image.open(img_path)
w, h = img.size
coco["images"].append({
"id": img_id, "file_name": img_path.name, "width": w, "height": h
})
label_path = labels_dir / f"{img_path.stem}.txt"
if not label_path.exists():
continue
for line in label_path.read_text().strip().split("\n"):
if not line.strip():
continue
parts = line.split()
cls_id = int(parts[0])
cx, cy, nw, nh = map(float, parts[1:5])
bx = (cx - nw / 2) * w
by = (cy - nh / 2) * h
bw = nw * w
bh = nh * h
coco["annotations"].append({
"id": ann_id, "image_id": img_id, "category_id": cls_id,
"bbox": [round(bx, 2), round(by, 2), round(bw, 2), round(bh, 2)],
"area": round(bw * bh, 2), "iscrowd": 0
})
ann_id += 1
Path(output_path).write_text(json.dumps(coco, indent=2))
# Usage
yolo_to_coco("images/", "labels/", "classes.txt", "coco_annotations.json")
Dataset Split Script
Most training frameworks expect train/val/test splits. Here is a quick split script:
import random
import shutil
from pathlib import Path
def split_dataset(images_dir, labels_dir, output_dir, ratios=(0.8, 0.1, 0.1)):
images = sorted(Path(images_dir).glob("*"))
images = [p for p in images if p.suffix.lower() in (".jpg", ".jpeg", ".png", ".bmp")]
random.shuffle(images)
n = len(images)
train_end = int(n * ratios[0])
val_end = train_end + int(n * ratios[1])
splits = {
"train": images[:train_end],
"val": images[train_end:val_end],
"test": images[val_end:],
}
for split_name, split_images in splits.items():
img_out = Path(output_dir) / split_name / "images"
lbl_out = Path(output_dir) / split_name / "labels"
img_out.mkdir(parents=True, exist_ok=True)
lbl_out.mkdir(parents=True, exist_ok=True)
for img_path in split_images:
shutil.copy2(img_path, img_out / img_path.name)
label_path = Path(labels_dir) / f"{img_path.stem}.txt"
if label_path.exists():
shutil.copy2(label_path, lbl_out / label_path.name)
print(f"Split: {len(splits['train'])} train, {len(splits['val'])} val, {len(splits['test'])} test")
# Usage
split_dataset("images/", "labels/", "dataset_split/")
Key Takeaways
- YOLO format for Ultralytics training. COCO format for everything else.
- Know the three coordinate conventions: YOLO (normalized center), COCO (absolute min + size), VOC (absolute min/max). Mixing them up is the number one annotation export bug.
- Export to COCO when in doubt — it preserves the most information and converts to other formats easily.
- Always split your dataset before training. 80/10/10 is a reasonable default.
In the next lesson, we load custom ONNX models into AnyLabeling for domain-specific auto-labeling.