Metadata-Version: 2.4
Name: rightwayup
Version: 1.0.0
Summary: RightWayUp: full-circle image roll estimation with calibrated abstention, by ORTUS AI
Author: ORTUS AI
License-Expression: Apache-2.0
Project-URL: Homepage, https://cheqit.ortusai.io/resources/rightwayup/
Project-URL: Source, https://github.com/ortusaitech/rightwayup
Project-URL: Model weights, https://huggingface.co/ortusai
Project-URL: Issues, https://github.com/ortusaitech/rightwayup/issues
Keywords: image orientation,rotation estimation,upright,cctv,onnx,computer vision
Classifier: Programming Language :: Python :: 3
Classifier: Operating System :: OS Independent
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: Topic :: Scientific/Engineering :: Image Recognition
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
License-File: NOTICE
Requires-Dist: numpy>=1.23
Requires-Dist: pillow>=9.4
Requires-Dist: onnxruntime>=1.18
Requires-Dist: huggingface_hub>=0.20
Provides-Extra: test
Requires-Dist: pytest>=7; extra == "test"
Dynamic: license-file

# 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".

```bash
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
```

```python
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](https://github.com/ortusaitech/rightwayup/blob/main/MODEL-CARD.md).

## 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](https://huggingface.co/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
  `max` and do not rely on the abstain flag alone.
- **Clean photos with small tiers:** `nano` and `fast` are less accurate than Woehrer 2026 on clean everyday photos;
  use `pro` or `max` for 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 `nano` by 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](https://ortusai.io), the team behind CHEQIT camera-health monitoring.
