Skip to main content
Panlabel converts between different object detection annotation formats using an intermediate representation (IR). This enables N×M format conversions with only 2N converters - similar to how Pandoc converts between document formats.

Basic Conversion

The convert command translates datasets from one format to another:
panlabel convert --from coco --to yolo --input dataset.json --output ./yolo_dataset
For supported formats and their capabilities, run:
panlabel list-formats

Common Conversion Workflows

1

COCO to YOLO

Convert a COCO JSON file to YOLO directory structure:
panlabel convert \
  --from coco \
  --to yolo \
  --input annotations.json \
  --output ./yolo_dataset
This creates a YOLO directory with labels/ subdirectory containing normalized center-format .txt files.
2

YOLO to COCO

Convert a YOLO directory to COCO JSON:
panlabel convert \
  --from yolo \
  --to coco \
  --input ./yolo_dataset \
  --output annotations.json \
  --allow-lossy
Note: YOLO → COCO conversion is lossy because YOLO lacks dataset-level metadata.
3

Pascal VOC to COCO

Convert Pascal VOC XML annotations to COCO:
panlabel convert \
  --from voc \
  --to coco \
  --input ./VOC_dataset \
  --output annotations.json \
  --allow-lossy
VOC attributes like pose, truncated, difficult, and occluded are preserved as annotation attributes in the IR but may be dropped depending on the target format.
4

Label Studio to IR JSON

Convert Label Studio task export to lossless IR JSON:
panlabel convert \
  --from label-studio \
  --to ir-json \
  --input tasks.json \
  --output dataset.json
IR JSON is Panlabel’s canonical format and preserves all information.

Lossiness and the --allow-lossy Flag

Not all annotation formats carry the same information. When you convert between formats, some fields may not have an equivalent in the target format - that’s what Panlabel calls lossiness. Rather than silently dropping data, Panlabel tells you exactly what would be lost and requires you to opt in with --allow-lossy.

Lossiness Categories

Formats are classified by their information preservation relative to the IR:
FormatLossinessNotes
ir-jsonLosslessCanonical representation, preserves everything
cocoConditionalLossless for basic detection, may lose custom attributes
cvatLossyDrops dataset-level metadata
label-studioLossyDrops dataset metadata; rotations flattened to axis-aligned boxes
tfodLossyDrops dataset metadata, category supercategories, and images without annotations
yoloLossyDrops all dataset-level and image-level metadata
vocLossyDrops dataset-level metadata and some image metadata
The format-level classification is a general capability signal. Conversions are actually blocked only when the conversion report contains one or more warning severity issues for your specific dataset.

Example: Blocked Conversion

When converting COCO to YOLO without --allow-lossy:
panlabel convert --from coco --to yolo --input dataset.json --output ./yolo_out
Output:
Error: Conversion blocked: dataset information would be lost

Conversion Report:
  Warning: drop_dataset_info - Dataset-level metadata (description, version, etc.) will be dropped
  Warning: drop_category_supercategory - Category supercategory fields will be dropped
  Info: yolo_writer_float_precision - YOLO normalized coordinates use 6 decimal places

Use --allow-lossy to proceed with this conversion.

Stable Issue Codes

Every conversion report includes stable issue codes designed for programmatic use:

Warning Codes (Block Conversion)

CodeMeaning
drop_dataset_infoDataset-level metadata is dropped
drop_licensesLicense list is dropped
drop_image_metadataImage metadata fields (license/date) are dropped
drop_category_supercategoryCategory supercategory is dropped
drop_annotation_confidenceAnnotation confidence values are dropped
drop_annotation_attributesAnnotation attributes are dropped
drop_images_without_annotationsImages without annotations will not appear (TFOD behavior)
label_studio_rotation_droppedRotated boxes flattened to axis-aligned envelopes

Info Codes (Never Block)

Info codes document deterministic policies and never block conversion. Examples:
  • yolo_writer_float_precision - YOLO normalized float precision policy
  • yolo_writer_empty_label_files - Empty label files created for unannotated images
  • voc_reader_coordinate_policy - VOC coordinate handling (no 0/1-based adjustment)
  • tfod_writer_row_order - TFOD writer deterministic row order
Run with --report json to get machine-readable issue codes for programmatic use:
panlabel convert --from coco --to yolo \
  --input dataset.json \
  --output ./yolo_out \
  --report json

Conversion Reports

Every conversion generates a report explaining what happened.

Text Report (Default)

panlabel convert --from coco --to yolo \
  --input dataset.json \
  --output ./yolo_out \
  --allow-lossy
Output:
Converted dataset.json (coco) -> ./yolo_out (yolo)

Conversion Report:
  Images: 100 → 100
  Categories: 5 → 5
  Annotations: 450 → 450

Warnings:
  • drop_dataset_info: Dataset-level metadata will be dropped
  • drop_category_supercategory: Category supercategory fields will be dropped

Info:
  • yolo_writer_float_precision: YOLO coordinates written with 6 decimal places
  • yolo_writer_empty_label_files: Empty .txt files created for images without annotations

JSON Report

For programmatic consumption:
panlabel convert --from coco --to yolo \
  --input dataset.json \
  --output ./yolo_out \
  --allow-lossy \
  --report json
Output:
{
  "from": "coco",
  "to": "yolo",
  "input": {
    "images": 100,
    "categories": 5,
    "annotations": 450
  },
  "output": {
    "images": 100,
    "categories": 5,
    "annotations": 450
  },
  "issues": [
    {
      "severity": "warning",
      "code": "drop_dataset_info",
      "message": "Dataset-level metadata will be dropped"
    },
    {
      "severity": "info",
      "code": "yolo_writer_float_precision",
      "message": "YOLO coordinates written with 6 decimal places"
    }
  ]
}

Best Practices

Use IR JSON as an Interchange Format

When performing multiple conversions, use ir-json as an intermediate step to preserve maximum information:
# Step 1: Convert to IR JSON (lossless)
panlabel convert --from label-studio --to ir-json \
  --input tasks.json --output dataset_ir.json

# Step 2: Convert IR to target format
panlabel convert --from ir-json --to coco \
  --input dataset_ir.json --output annotations.json

Validate Before Converting

By default, Panlabel validates input before conversion. Use --strict to treat warnings as errors:
panlabel convert --from coco --to yolo \
  --input dataset.json \
  --output ./yolo_out \
  --strict \
  --allow-lossy
To skip validation entirely (not recommended):
panlabel convert --from coco --to yolo \
  --input dataset.json \
  --output ./yolo_out \
  --no-validate \
  --allow-lossy
Using --no-validate may result in invalid output if your input dataset has errors. Only use this for trusted inputs where validation is a performance bottleneck.

Understand Your Format’s Limitations

Before converting, check what information your target format can preserve:
panlabel list-formats
If you need to preserve dataset metadata, confidence scores, or custom attributes, consider using ir-json or coco as your target format.

Inspect Conversion Reports Programmatically

For automation pipelines, parse JSON reports to make decisions:
import subprocess
import json

result = subprocess.run([
    'panlabel', 'convert',
    '--from', 'coco', '--to', 'yolo',
    '--input', 'dataset.json',
    '--output', './yolo_out',
    '--report', 'json',
    '--allow-lossy'
], capture_output=True, text=True)

report = json.loads(result.stdout)

# Check for specific warnings
for issue in report['issues']:
    if issue['code'] == 'drop_annotation_confidence':
        print("Warning: Confidence scores will be lost")
  • validate - Validate datasets before conversion
  • stats - Analyze dataset statistics
  • diff - Compare datasets before and after conversion
  • list-formats - View all supported formats

Build docs developers (and LLMs) love