fastlabelcontours
Fast direct contour extraction from 2D integer label images.
fastlabelcontours traces every nonzero label directly from one integer label map.
It does not create a full binary mask for each instance.
import numpy as np
from fastlabelcontours import contours
labels = np.array(
[[0, 7, 7],
[0, 7, 0],
[9, 9, 0]],
dtype=np.uint32,
)
result = contours(labels)
The result is a compact ragged representation:
ids: observed nonzero labels, sorted ascendingpoints: concatenated(x, y)pixel-edge verticescontour_offsets: slicespointsinto individual contourslabel_offsets: slices contours into labelsis_hole: marks inner boundaries
Contours are implicitly closed; the first point is not repeated. Coordinates follow exact pixel edges, so signed contour area sums to the number of pixels carrying each label. Diagonal-only contact does not merge components.
Why
A common implementation repeatedly materializes labels == label and calls a contour
routine once per instance. Even a better implementation still has to discover each
instance bounding box, crop it, materialize a binary mask, and invoke the contour tracer
once per object.
fastlabelcontours instead scans the label image once and traces label boundaries
directly in C++.
On a local 2048 x 2048 synthetic blob mask with 4096 instances:
| Method | Median time | Relative to fastlabelcontours |
|---|---|---|
fastlabelcontours |
~25 ms | 1.0x |
| SciPy bbox discovery + cropped OpenCV | ~55 ms | ~2.2x slower |
Rasterio features.shapes |
~105 ms | ~4.2x slower |
full-image labels == id + OpenCV per instance |
~4.95 s | ~199x slower |
The bbox-cropped OpenCV result is the most useful baseline: it avoids rescanning the full image for every label and still takes roughly twice as long in this workload. Exact results are machine- and data-dependent; run the included benchmark on your own masks.
Installation
pip install fastlabelcontours
Until wheels are published, install from source with a C++17 compiler:
pip install .
API
from fastlabelcontours import contours
result = contours(labels)
# contour i
points_i = result.points[result.contour_offsets[i] : result.contour_offsets[i + 1]]
# contours belonging to label j
first = result.label_offsets[j]
last = result.label_offsets[j + 1]
Inputs must be 2D NumPy arrays with dtype uint32 or uint64. Label 0 is background.
The public API copies non-contiguous inputs to contiguous storage before entering the C++
core.
Geometry semantics
- Coordinates are integer
(x, y)pixel-edge vertices, not pixel centers. - Contours are implicitly closed.
- Outer contours have positive signed area; holes have negative signed area.
is_holerecords the same distinction explicitly.- A label may have multiple disconnected outer contours.
- Connectivity is 4-connected, so diagonal-only contact does not merge components.
- No simplification is performed; the output represents exact raster boundaries.
Scope
fastlabelcontours deliberately stays narrow:
- 2D
uint32/uint64label images - background label
0 - CPU only
- NumPy as the only runtime dependency
- exact contours, including holes and disconnected components
- no polygon simplification or general geometry operations
Development
python -m pip install -e '.[dev,benchmark]'
pytest
ruff check .
mypy src/fastlabelcontours
python benchmarks/benchmark_contours.py --size 2048 --instances 4096
Build and validate release artifacts with:
python -m build
python -m twine check dist/*
cibuildwheel configuration for CPython 3.10-3.13 on Linux, macOS, and Windows is
included in pyproject.toml for producing binary wheels.
License
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fastlabelcontours-0.1.0.tar.gz.
File metadata
- Download URL: fastlabelcontours-0.1.0.tar.gz
- Upload date:
- Size: 14.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.11.23 {"installer":{"name":"uv","version":"0.11.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
00a3f7b8245f8585ea55dda6b49da23a6ac371c8ecdd95fd7f8a9e843a2175a8
|
|
| MD5 |
f1d31def39f10688022e837f322d873c
|
|
| BLAKE2b-256 |
27c97e7489d72b66792c3e66a4f111fe1059691c827bd7df9116fdaec574f2e4
|
File details
Details for the file fastlabelcontours-0.1.0-cp312-cp312-macosx_11_0_arm64.whl.
File metadata
- Download URL: fastlabelcontours-0.1.0-cp312-cp312-macosx_11_0_arm64.whl
- Upload date:
- Size: 22.2 kB
- Tags: CPython 3.12, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.11.23 {"installer":{"name":"uv","version":"0.11.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d13775aee6ae66d9acc7efb9d80a438f673ee79e592c4f0217845fd9b5c76aa3
|
|
| MD5 |
095e20a6c8ae4023c8a57e7b15bd23d0
|
|
| BLAKE2b-256 |
dbf9670fb4e9edde31b29404b9e65b3bb155b654681c3d7cbf690fe3d724cd73
|