rightwayup
Python package and CLI for RightWayUp, a neural network model by ORTUS AI that estimates how far an image is rotated from upright, over the full 360° at 1° resolution, and abstains when an image has no clear "up".
pip install rightwayup
rightwayup predict frame.jpg # angle, confidence, abstain flag
rightwayup fix photo.jpg --snap 90 --out upright/ # writes the upright image; leaves it alone if it abstains
rightwayup predict frames/*.jpg --tier nano --batch --batch-size 64 --json
from rightwayup import Orienter
o = Orienter(tier="max") # weights download from Hugging Face on first use
r = o.predict("frame.jpg") # r.angle_cw, r.confidence, r.abstain, r.routed
upright = o.correct("photo.jpg", snap=90)
results = Orienter(tier="fast", batch=True).predict_batch(["a.jpg", "b.jpg"], batch_size=64)
angle_cw is the clockwise rotation of the image content; turning the image counter-clockwise by angle_cw makes
it upright (r.correction_ccw). abstain is true when the image has no reliable "up" (the angle is still
reported); correct() then returns the image unchanged unless force=True.
Tiers
| Tier | Model | Input | Laptop CPU, one image¹ | Notes |
|---|---|---|---|---|
pico |
ViT-S/14, fill-drop | 70 px | 3.21 ms | smallest and least accurate; development numbers only |
nano |
ViT-S/14, fill-drop | 112 px | 7.73 ms | camera fleets and edge devices |
fast |
ViT-S/14, fill-drop | 224 px | 29.7 ms | quick general default |
balanced |
Fast → Max for ~10% | 224 → 280 px | 62.2 ms (derived) | cascade |
pro |
Fast → Max for ~20% | 224 → 280 px | 94.8 ms (derived) | cascade |
max (default) |
ViT-L/14 on every image | 280 px | 326 ms | most accurate |
¹ Intel Core i7-1260P, ONNX Runtime INT8, 4 threads, batch 1. Cascade shares are those of the calibration data; on photos and thermal images Balanced and Pro route more (10–33% / 30–80% on the sealed test sets). Accuracy tables, GPU and Apple timings: model card.
Options
| Argument (Python / CLI) | Values |
|---|---|
tier / --tier |
pico, nano, fast, balanced, pro, max (default) |
device / --device |
auto (CUDA if available, else CPU), cpu, cuda, tensorrt, coreml |
precision / --precision |
auto (INT8 on CPU, FP16 on GPU), fp32, fp16, int8 |
batch / --batch |
False (default): one-image files, fastest for single images; True: batch-capable files for predict_batch throughput. Same answers. |
abstain / --abstain |
standard (about 90% of calibration images answered), strict (at most 1% wrong on calibration images, never looser than standard), off |
model_dir / --model-dir |
folder with the ONNX files (or set RIGHTWAYUP_MODEL_DIR); default: download from the Hugging Face Hub |
threads |
ONNX Runtime intra-op threads |
predict_batch(images, batch_size=16) accepts file paths, PIL images or NumPy arrays. rightwayup fix also takes
--min-angle (treat smaller corrections as upright, default 1.0°) and --force; it exits with status 2 if it left
any image unchanged because the model abstained.
Abstain and route thresholds were fixed on calibration data only, separately for each file format (FP32, FP16, INT8, and the batch-capable files); the package applies the thresholds of the format it loads.
Files and formats
The weights repository ortusai/rightwayup holds, for every model, ONNX
FP32 / FP16 / INT8 files (pico-s70-*, nano-s112-*, fast-s224-*, max-l280-*), batch-capable ONNX files for
Pico, Nano and Fast (*-batch-*), a full-token Pico build for ONNX Runtime Web (pico-s70-web-*), and Core ML
packages for Apple silicon (coreml/*-b1.mlpackage, *-b16.mlpackage). The package uses the ONNX files; tiers.json
in the weights repository documents the preprocessing and every threshold for use without Python.
Known limitations
- Thermal images: accuracy on unseen thermal cameras varies widely and confidence is not reliable there; use
maxand do not rely on the abstain flag alone. - Clean photos with small tiers:
nanoandfastare less accurate than Woehrer 2026 on clean everyday photos; useproormaxfor photo apps. - Pico is weak on strongly rolled CCTV (41.1% on one held-out camera rolled about 36°).
- Rotation corners: images turned by software get flat-colour corners; black, white and grey corners are handled
by every tier, but a sky-blue fill can flip
nanoby 180°. - No "up": straight-down aerial images and featureless close-ups have no defined "up"; use the abstain flag.
- Max is not the fast tier: per image it is slower than Woehrer 2026 on CPUs and most GPUs.
No telemetry: the only network calls go to Hugging Face to fetch the weight files (and check cached copies). Pass
model_dir= or set HF_HUB_OFFLINE=1 to run fully offline.
- Write-up and video: https://cheqit.ortusai.io/resources/rightwayup/
- Code, results, technical report and data provenance: https://github.com/ortusaitech/rightwayup
- Weights (all six tiers): https://huggingface.co/ortusai/rightwayup
Apache-2.0. Built by ORTUS AI, the team behind CHEQIT camera-health monitoring.
Release files for rightwayup 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| rightwayup-1.0.0.tar.gz | 19.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| rightwayup-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 35.5 kB
Release files / rightwayup-1.0.0.tar.gz
| Download URL | rightwayup-1.0.0.tar.gz |
|---|---|
| Size | 19.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
25b73cb34d7dc68d241934604928d2e20515e3e9e0fa8537e80334d51fa1b534
|
|
BLAKE2b-256 checksum How to use checksums |
aa86088bd25f44fb971ed8ed20c717a5383ec48dff03ec5aabc025bfd2651722
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / rightwayup-1.0.0-py3-none-any.whl
| Download URL | rightwayup-1.0.0-py3-none-any.whl |
|---|---|
| Size | 16.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
694aa8b27f6dd229ab811eecb1962af0e1fb508c3c23f11609a6adc00ab657db
|
|
BLAKE2b-256 checksum How to use checksums |
67f4b79294c988146c1deca3ee0ee8fa7c4b9f90b0adac165c5c2d69d06c00cc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|