Skip to main content

visionstyle — expressive computer-vision styling

Beautiful, fully configurable bounding boxes for object detection.
Boxes, labels, fills, glow, glass, film grain and tracking trails, described by one Style,
tuned live in the Studio, saved as YAML and rendered with one call.

PyPI version Python versions CI License

Website · Quickstart · Styles · Studio · Python API · CLI · Changelog

A rainy Manhattan street at night annotated with the cinematic preset: amber and teal rounded frames with pill labels around pedestrians, a bus and cars
YOLO26n detections on a rainy Manhattan crossing, rendered with style="cinematic".

Quickstart

pip install "visionstyle[yolo]"
import cv2
import visionstyle as vs
from ultralytics import YOLO

frame = cv2.imread("street.jpg")
result = YOLO("yolo26n.pt")(frame)[0]

dets = vs.Detections.from_ultralytics(result)
cv2.imwrite("out.jpg", vs.annotate(frame, dets, style="cinematic"))

No model handy? visionstyle render sample -s neon -o out.jpg renders a bundled photo with its shipped detections.

visionstyle only draws, so any detector works: pass boxes as lists, NumPy arrays or torch tensors (see Python API).

Install options

Command Adds
pip install visionstyle The renderer: NumPy, OpenCV (headless), Pillow, pydantic, PyYAML
pip install "visionstyle[yolo]" Ultralytics YOLO for from_ultralytics, the CLI --model flag and video tracking
pip install "visionstyle[studio]" FastAPI + Uvicorn for the Studio web app
pip install "visionstyle[all]" Everything above

Python 3.10 – 3.13.

Why visionstyle

  • One object describes the look. A Style covers boxes, strokes, fills, line patterns, labels, effects and trails. Every option is a typed, validated attribute, and the whole thing round-trips to YAML.
  • Twenty-two presets to start from. Use one by name, or copy its YAML and make it yours.
  • Looks the same at any resolution. Sizes are in reference pixels and scale with the frame, and each object's outline and label scale with its size, so distant objects stay light.
  • Built for video. Keep one Annotator per stream and you get tracking trails, marching dashes, hue cycling and pulses that carry across frames.
  • A Studio to design in. Tune a style visually on your own image or video. The Python package renders every preview, so what you see is exactly what annotate() produces.

What it can draw

Nine looks, each built to show off a different part of Style: box shapes, line patterns, fills, label treatments, effects and trails. Every tile is rendered by the package itself, and the style behind each one is in docs/showcase.py if you want to borrow it.

Nine annotation styles in a 3 by 3 grid: corner brackets with center marks, a reticle HUD with hatch fill, rounded boxes with gradient fill and glow, multicolor dashed outlines, frosted glass, neon gradient outlines, tracking trails, a spotlight that dims the background, and confidence-colored boxes with vertical tags

Presets

Twenty-two ready-made presets to start from. Each one is a plain YAML file you can copy and edit (see all of them on the same scene).

Twelve general-purpose looks:

Preset Look Preset Look
default Clean rectangle, solid tag neon Glowing hue-cycling gradient outlines
minimal Hairline outline, bare text hud Double frame, reticle marks, inside mono labels, dotted trails
corners Thin L-brackets, monospace tag cinematic Rounded amber/teal frames, gradient fill, pill labels, glow, filmic grade
rounded Rounded corners, gradient tint, pill label tracking Bold per-track trails, id-first labels
dashed Dashed perimeter with marching ants spotlight Dims everything outside the detections
glass Frosted-glass fill and label confidence Stroke and tag color follow the confidence score

Ten built for a job, a field or an audience:

Preset For Look
target Following one subject Red lock-on brackets that pulse, center cross, track trail, dimmed frame
redact Anonymizing people, faces, plates Blurs the inside of each box and marks it REDACTED
review Auditing labels and model output Class id, name and score on every box, uniform sizes, tinted fill
safety PPE, intrusion and restricted-zone alerts Amber/black hazard-tape outline, hatch fill, loud tag
broadcast Sports and TV graphics No boxes: a glowing path at each player's feet and a number bubble
cctv Security and surveillance Grayscale grainy frame, phosphor-green boxes and ID tags
traffic Traffic and smart-city monitoring Vehicles amber, people cyan, two-wheelers lime
documentary Wildlife, nature, editorial video Thin cream brackets, underlined names, warm film grade
blueprint Robotics and technical write-ups Cool desaturated frame, fine dashed boxes, center marks, [class id] tags
high-contrast Projectors, outdoor screens, low vision Thick yellow outlines with a dark halo, large black-on-yellow tags

target draws every detection it's given, so pass only the one you're following (for example dets.subset(dets.track_id == 3)), or hide the others in the Studio's Objects tab.

visionstyle presets list
visionstyle presets show cinematic
visionstyle presets export cinematic -o my-look.yaml

Studio

Design a style visually on your own image, video and model, then save it as a preset the package loads by name.

pip install "visionstyle[studio,yolo]"
visionstyle studio          # opens http://127.0.0.1:8420

The visionstyle Studio: a tracked street video with the cinematic preset in the preview, the timeline below it, and the style library and design sections on the right

  1. Source. Pick a bundled scene or upload an image or video, set the confidence threshold and run detection. Videos are tracked once, up to a minute long, and the detections are saved with the video, so restyling, scrubbing and moving the confidence slider replay them without running the model again. Longer uploads can be trimmed to their first minute. The sample video ships with its tracks; tracking a new video needs the yolo extra.
  2. Design. Start from a preset, then adjust box, stroke, fill, line, label, effects, tracking and global settings, or search for any setting by name. Save next to the Style menu stores the look as a named preset.
  3. Objects. Filter by class, hide objects or isolate a single track. Scrub or play the timeline, and save the annotated frame from the preview menu.
  4. Export. Copy or download the YAML, a self-contained Python snippet, or a prompt for AI coding tools.

Saved presets go to ~/.visionstyle/presets and load by name anywhere on that machine with vs.Style.preset("my-look"). To keep them in a project instead, run visionstyle studio --presets-dir ./styles, commit styles/<name>.yaml, and load it with vs.Style.load("styles/my-look.yaml") (or set VISIONSTYLE_PRESETS_DIR=./styles to load by name).

Keyboard shortcuts
Key Action
Space Play / pause
← / → Previous / next frame
Shift + ← / → Jump ten frames
R Reset the style

Focused controls keep their own keyboard behavior.

Python API

import cv2
import visionstyle as vs

frame = cv2.imread("street.jpg")

# 1. Detections: boxes in pixels, everything else optional
dets = vs.Detections(
    xyxy=[[590, 650, 720, 1040], [1060, 660, 1520, 1000]],
    class_name=["person", "car"],
    confidence=[0.93, 0.88],
    track_id=[14, 31],
)
# or: dets = vs.Detections.from_ultralytics(model.predict(frame)[0])

# 2. A style: preset name, YAML path, or built in code
style = vs.Style.preset("cinematic")
style.label.components = ["track_id", "text"]   # every option is a typed attribute
style.trail.enabled = True

# 3. Render. Keep one Annotator per video stream so trails and animations carry across frames.
annotator = vs.Annotator(style)
out = annotator.annotate(frame, dets)

# One-liner for stills
out = vs.annotate(frame, dets, style="minimal")

xyxy is pixel x1, y1, x2, y2; Detections.from_xywh, from_xywh_topleft and from_dicts cover other formats. Frames are BGR uint8 like OpenCV; pass rgb=True for RGB arrays.

What you can configure

Section Options
Box rectangle, rounded (radius), corners (bracket length, curved elbows), reticle, none; double line; center mark
Stroke Thickness, opacity, color (palette per class/track, confidence ramp, or any hex/rgb/name)
Fill On/off, opacity, color, solid / gradient (5 directions) / hatch
Line solid / dashed / dotted, dash and gap sizes, multi-color segments or perimeter gradient, animation march / hue_cycle / pulse
Label Ordered components (text, confidence, track_id, class_id, custom template), 9 anchors × inside/outside, vertical tags on the sides, fonts (Inter, JetBrains Mono or your .ttf), size, weight, uppercase, solid / pill / glass / underline / none backgrounds, border, padding, formats
Effects Glow, shadow, frosted glass, spotlight dimming, vignette, film grain, color grade
Tracking Trail length, anchor (feet/center/top), solid / dotted / dashed / ribbon, fade and taper, smoothing, glow, points
Global Palette (built-in or custom list), per-class color overrides, confidence threshold, resolution scaling, per-object scaling, fps
How sizes scale

All sizes are in reference pixels at about 1080p and scale automatically with the frame (style.scale = "auto"), so one style looks the same on a webcam and a 4K photo.

On top of that, strokes and label tags scale with each detected object's size (style.object_scale, on by default): far-away objects get thin outlines and small tags, close-up ones get heavier outlines and larger text. Tune strength and min_factor / max_factor, restrict it with apply_to: box | label, or set enabled: false for constant sizes.

Save and share styles

style.save("my_style.yaml")                 # anywhere
style.save_preset("my-look")                # ~/.visionstyle/presets/my-look.yaml
vs.Style.preset("my-look")                  # found by name from now on
vs.presets.list()                           # built-in + yours

Presets are looked up in $VISIONSTYLE_PRESETS_DIR, then ~/.visionstyle/presets, then the built-ins, then as a file path.

CLI

visionstyle render photo.jpg -s neon --model yolo26n.pt -o out.jpg
visionstyle render clip.mp4  -s tracking --model yolo26n.pt --track -o out.mp4
visionstyle render 0         -s hud --model yolo26n.pt --track -o webcam.mp4   # webcam index
visionstyle render photo.jpg -d detections.json -s corners                    # no model needed
visionstyle gallery photo.jpg --model yolo26n.pt -o gallery.png               # every preset at once
visionstyle presets list | show NAME | export NAME -o my.yaml
visionstyle schema -o style.schema.json

detections.json is a list of {"xyxy": [...], "class_name": "...", "confidence": 0.9, "track_id": 1}.

Development

uv sync --all-extras --group dev
uv run pytest && uv run ruff check . && uv run mypy src

cd studio && npm install
npm run dev            # Vite dev server on :5173, proxying /api to :8420
npm run build          # -> src/visionstyle/studio/static (bundled into the wheel)

When src/visionstyle/style/schema.py changes, regenerate the frontend schema and types:

uv run visionstyle schema -o studio/schema.json && (cd studio && npm run gen:types)
Releasing and the website

Releases. Bump __version__ in src/visionstyle/__init__.py, add a section to CHANGELOG.md, then tag vX.Y.Z and push the tag. release.yml builds the Studio and the wheel, checks them, publishes to PyPI through trusted publishing and creates a GitHub release.

Website. The project site deploys from site/ through GitHub Actions on every push to main; see site/README.md.

Credits

Sample photos: see CREDITS.md. Fonts: Inter and JetBrains Mono, both under the SIL Open Font License.

Author

Built by Basel Mather. See more of my work at baselhusam.com.

Released under the MIT License.

Metadata

Release files for visionstyle 0.1.1

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

Source distribution (sdist)

Source distribution for visionstyle 0.1.1
File Size Uploaded
visionstyle-0.1.1.tar.gz 4.3 MB Details

Built distribution (wheel)

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

Total release size: 8.6 MB

Release files / visionstyle-0.1.1.tar.gz

Download URL visionstyle-0.1.1.tar.gz
Size 4.3 MB
Tags Source
SHA-256 checksum
How to use checksums
4c0f4a957436700ec56d9460e46f2a16fa29a60c72259ccec91dd263cce33ad2
BLAKE2b-256 checksum
How to use checksums
0631073236242a253407320d8b34c9cfbedb019ea08546747c8ee607234b0698
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 27, 2026.

Transparency log

Release files / visionstyle-0.1.1-py3-none-any.whl

Download URL visionstyle-0.1.1-py3-none-any.whl
Size 4.3 MB
Tags Python 3
SHA-256 checksum
How to use checksums
a7127604a2ced57323bbfa04c7c8c22e66f447df08c0192948348fa407a97eb8
BLAKE2b-256 checksum
How to use checksums
7de927a8d8db891e34e071106012523ce583994846e10436f03ff84cb044348c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 27, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.1 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