Skip to main content

annofmt

Immutable geometry types and utilities for computer-vision annotations. Zero dependencies, fully typed, Python 3.12+.

Install

uv add annofmt
# or
pip install annofmt
# or straight from the repo
uv add git+https://github.com/peachfuzz11/annofmt.git

Quickstart

from annofmt.annotation import Annotation
from annofmt.geometry.bbox import BBox
from annofmt.geometry.rbbox import RBBox
from annofmt.geometry.segm import Segm
from annofmt.tag import Tag

bbox = BBox(x=30, y=50, w=40, h=20)   # center + extent
bbox.x_min                            # derived corner values

# Build from whichever coordinate layout you already have
BBox.from_xywh(30, 50, 40, 20)        # center x, center y, w, h (native, YOLO-style)
BBox.from_x1y1x2y2(10, 40, 50, 60)    # corners: left, top, right, bottom edge (Pascal VOC)
BBox.from_x1x2y1y2(10, 50, 40, 60)    # x range then y range: left, right, top, bottom edge
BBox.from_x1y1wh(10, 40, 40, 20)      # top-left corner (x1, y1) + w, h (COCO)

# ...and read any layout back out as a plain tuple
bbox.to_xywh()                        # (center x, center y, w, h)
bbox.to_x1y1x2y2()                    # (left, top, right, bottom edge)
bbox.to_x1x2y1y2()                    # (left, right, top, bottom edge)
bbox.to_x1y1wh()                      # (x1, y1, w, h)

# Normalized coordinates in [0, 1] relative to image dimensions
bbox_normalized = bbox.normalize(Height, Width)
# Denormalize back to pixel coordinates
bbox_denormalized = bbox_normalized.denormalize(Height, Width)

rotated = RBBox.from_degrees(x=30, y=50, w=40, h=20, degrees=25)   # same xywh, plus `a`
rotated.corners()
rotated.to_bbox()                     # lossy enclosing axis-aligned box

segm = Segm.from_polygon([(0, 0), (9, 0), (9, 9), (5, 5), (0, 9)])
segm.indices                          # integer pixel-index rings
segm.to_rle(height=10, width=10)      # COCO-style column-major run-length counts
Segm.from_rle(runs, 10, 10)           # ...and back to rings

annotation = Annotation(geometry=segm).add_tag(Tag("person", score=0.98))
annotation.bbox                       # works for every geometry type

All types are immutable: operations return new instances and never mutate the receiver.

Geometry types

BBox is the base class; storage is always center-plus-extent (x, y, w, h).

Type Extra storage Description
BBox — axis-aligned box; corners are derived properties
RBBox a adds rotation in radians; corners become the enclosing box
Segm indices polygon rings over integer pixel indices; x/y/w/h hold the enclosing box

Conversion matrix

From \ To BBox RBBox Segm
BBox — unavailable (rotation cannot be invented) exact rectangle ring (Segm.from_bbox)
RBBox enclosing box (to_bbox, lossy) — corner ring (Segm.from_rbbox, rounded to lattice)
Segm enclosing box (to_bbox, lossy) minimum-area rect (as_rbbox, lossy) —

IoU is defined only between two geometries of the same type and raises TypeError otherwise. Convert explicitly first when a cross-type comparison is really wanted (e.g. compare every geometry's to_bbox()).

Coordinate layouts

BBox stores center-plus-extent, but you rarely have data in that form. Each from_* classmethod builds a box from a named coordinate layout and each to_* method returns that layout as a plain tuple. The method name spells out the argument order — x1/y1 are the top-left corner (left and top edge), x2/y2 the bottom-right corner (right and bottom edge):

Constructor Accessor Arguments
BBox.from_xywh bbox.to_xywh center x, center y, width, height (native, YOLO-style)
BBox.from_x1y1x2y2 bbox.to_x1y1x2y2 x1, y1, x2, y2 — left, top, right, bottom edge (Pascal VOC)
BBox.from_x1x2y1y2 bbox.to_x1x2y1y2 x1, x2, y1, y2 — left, right, top, bottom edge
BBox.from_x1y1wh bbox.to_x1y1wh x1, y1, width, height — top-left corner + size (COCO)

from_x1y1x2y2 / from_x1x2y1y2 accept the two edges in either order. The classmethods are inherited by RBBox (angle defaults to 0). Every constructor and accessor takes / preserves meta.

Conventions

  • Angles: stored in radians, canonically wrapped to [-pi, pi). Build with from_degrees, read via .angle_deg / .angle_rad.
  • Indices: Segm coordinates are integer pixel indices; fractional input is rejected. Vertices sit on the integer lattice.
  • Rasterization: pixels are unit squares centered at (col + 0.5, row + 0.5); rings combine under an even-odd rule, so nested rings act as holes regardless of winding order.
  • RLE: COCO-style column-major counts starting with zeros; to_rle(height, width) / from_rle(runs, height, width) round-trip.
  • Immutability: every operation yields a new instance.

Metadata

Release files for annofmt 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for annofmt 0.2.0
File Size Uploaded
annofmt-0.2.0.tar.gz 32.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for annofmt 0.2.0
File Interpreter ABI Platform
annofmt-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 39.4 kB

Release files / annofmt-0.2.0.tar.gz

Download URL annofmt-0.2.0.tar.gz
Size 32.2 kB
Tags Source
SHA-256 checksum
How to use checksums
a4e971647b390119c7f5a88fdde990a47d4a38c167e9382e17ee8f5a5aeaaec9
BLAKE2b-256 checksum
How to use checksums
0976b47ff13e8c95e1eebff4a7883166583999f1bc508ffd9e5d28b20f69e016
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.10 {"installer":{"name":"uv","version":"0.12.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / annofmt-0.2.0-py3-none-any.whl

Download URL annofmt-0.2.0-py3-none-any.whl
Size 7.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
040e3a060ad8c89547605fc35739dddb235a4eb50c6c1f62528aa7b604e78404
BLAKE2b-256 checksum
How to use checksums
128b43a8e01654afe3b088c37b05ab7b9a5e3f0c97c1f2f742ef15215d35b6b0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.10 {"installer":{"name":"uv","version":"0.12.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page