Skip to content

Commit a010b85

Browse files
raullenchaiclaude
andcommitted
Fix front-door friction surfaced by usability test
- README headline quickstart now runs on a bare `pip install trio-retina` (numpy only): a stand-in ScriptedDetector emits a real retina.event stream with no model, GPU, or video file. The YOLO + video_frames form moves to a clearly-labeled "▶ with a real model + video" [yolo] block below it. - CountRule: threshold is now positional, so CountRule(3) works (previously a confusing TypeError from the keyword-only arg); CountRule(threshold=3) unchanged. Added a positional test. - SECURITY.md: supported-versions wording updated from "early development (0.0.x)" to the current 0.2.x line; trust model unchanged. - CHANGELOG: terse Changed / Fixed lines under [Unreleased]. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 962acdc commit a010b85

6 files changed

Lines changed: 318 additions & 18 deletions

File tree

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,19 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
1111
- Colab notebooks (`notebooks/`): runnable, zero-install quickstart, camera→webhook,
1212
and from-Supervision demos that print `retina.event` JSON on synthetic input.
1313

14+
### Changed
15+
16+
- `CountRule(threshold)` now accepts `threshold` positionally, so `CountRule(3)`
17+
works; `CountRule(threshold=3)` is unchanged.
18+
- README headline quickstart now runs on a bare `pip install trio-retina` (numpy
19+
only, no model / video) via a stand-in detector, with the YOLO + `video_frames`
20+
form moved to a clearly-labeled `[yolo]` block below it.
21+
22+
### Fixed
23+
24+
- `CountRule(3)` no longer raises a confusing `TypeError` from the keyword-only
25+
`threshold` (front-door friction for new users).
26+
1427
## [0.2.0] — 2026-06-17
1528

1629
### Added

README.md

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,49 @@ pip install 'trio-retina[all]' # everything
3434

3535
## 🔥 quickstart
3636

37+
Runs on a bare `pip install trio-retina` (numpy only) — no model, no GPU, no video file. A stand-in detector walks one "person" across a dock zone; Retina emits the real `retina.event` stream:
38+
39+
```python
40+
import numpy as np
41+
42+
from retina import CountRule, IoUTracker, Retina, Zone, ZoneRule
43+
from retina.detect import Detection
44+
45+
46+
class ScriptedDetector:
47+
"""A stand-in model: one 'person' walking across a dock zone."""
48+
49+
def __init__(self):
50+
self._xs = list(range(0, 102, 6))
51+
52+
def __call__(self, frame):
53+
x = self._xs.pop(0) if self._xs else 100
54+
return [Detection(label="person", bbox=(x - 10, 40, x + 10, 60), confidence=0.9)]
55+
56+
57+
dock = Zone("dock", [(40, 0), (60, 0), (60, 100), (40, 100)])
58+
59+
cam = Retina(
60+
source_id="cam_01",
61+
detector=ScriptedDetector(),
62+
tracker=IoUTracker(min_hits=2),
63+
rules=[
64+
ZoneRule(dock, classes={"person"}, dwell_s=2.0),
65+
CountRule(1, classes={"person"}),
66+
],
67+
)
68+
69+
frames = [(np.zeros((100, 100, 3), dtype=np.uint8), float(i)) for i in range(18)]
70+
for event in cam.run(frames):
71+
print(event.to_json())
72+
# {"type":"count.threshold","t":1.0,"src":"cam_01","n":1,"frame":1,...}
73+
# {"type":"zone.enter","t":7.0,"src":"cam_01","id":1,"label":"person",...}
74+
# {"type":"zone.dwell","t":7.0,...,"zone":"dock","dur":2.0,...}
75+
# {"type":"zone.exit","t":7.0,...,"zone":"dock","dur":3.0,...}
76+
```
77+
78+
**▶ with a real model + video**`pip install 'trio-retina[yolo]'` (add `[video]` for the frame source), then point it at your clip:
79+
3780
```python
3881
from retina import Retina, Zone, ZoneRule, YoloDetector
3982
from retina.sources import video_frames
@@ -45,13 +88,13 @@ cam = Retina(
4588
detector=YoloDetector("yolo11n.pt", classes={"person"}),
4689
rules=[ZoneRule(dock, classes={"person"}, dwell_s=30)],
4790
)
48-
for event in cam.run(video_frames("dock.mp4")):
91+
for event in cam.run(video_frames("your.mp4")):
4992
print(event.to_json())
5093
# {"type":"zone.dwell","t":1718254799.8,"src":"cam_01","id":42,
5194
# "label":"person","zone":"dock","dur":31.0,"conf":0.91}
5295
```
5396

54-
No model, no GPU? The [`examples/`](examples/) quickstarts run on synthetic detections `git clone` the repo (they ship with the source, not the wheel) and start with `python examples/quickstart.py` (the forecast / video demos need `[video]` + a clip).
97+
More no-model examples ship with the source (not the wheel) `git clone` the repo and run `python examples/quickstart.py` (the forecast / video demos need `[video]` + a clip).
5598

5699
**▶️ Or run it in your browser — no install:**
57100

SECURITY.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
## Supported versions
44

5-
Retina is in early development (`0.0.x`). Security fixes are applied to the latest
6-
release on the `main` branch.
5+
Retina is on the `0.2.x` line. Security fixes are applied to the latest release
6+
on the `main` branch.
77

88
## Reporting a vulnerability
99

retina/rules.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,8 +269,8 @@ class CountRule(_RuleBase):
269269

270270
def __init__(
271271
self,
272-
*,
273272
threshold: int,
273+
*,
274274
src: str | None = None,
275275
classes: set[str] | None = None,
276276
zone: Zone | None = None,

0 commit comments

Comments
 (0)