Skip to content

feat(center-stage): multi-person group framing + shot-size headroom + lead-room#118

Merged
TCVinNYC merged 2 commits into
mainfrom
feat/group-framing-composition
Jun 25, 2026
Merged

feat(center-stage): multi-person group framing + shot-size headroom + lead-room#118
TCVinNYC merged 2 commits into
mainfrom
feat/group-framing-composition

Conversation

@TCVinNYC

Copy link
Copy Markdown
Member

What & why

Adds the marquee Center-Stage feature AutoPTZ lacked — multi-person framing — plus two composition-polish knobs, all in the digital framer path (no physical-PTZ controller changes). Every default reproduces prior behaviour exactly.

D1 — Multi-person group framing (union bbox)

  • New tracking.group_framing: bool = False toggle (off → no behaviour change).
  • union_bbox() pure helper in digital_framer.py + CameraWorker._group_union_bbox() over the live confident, non-lost TrackInfo boxes.
  • desired_crop now sizes the crop to fit the subject both vertically and horizontally, so a WIDE union auto-widens (zoom out) to keep everyone in shot — still aspect-locked and capped by max_frac. Tall single-person boxes stay height-driven exactly as before.
  • Group-vs-explicit-lock rule: an explicitly locked target (by track id OR configured identity) always wins — Center Stage keeps following that one person even with group mode on. Group framing applies only when no explicit target is locked. The existing trusted_bbox fallback for single-target churn is preserved.

D2 — Shot-size-aware headroom

  • _CENTERSTAGE_FRAMING carries a per-preset headroom: face 0.06 → head_shoulders 0.08 → upper_body 0.10 (unchanged midpoint) → full_body 0.14. Closer shots get less margin above the head, full-body more.
  • _framed_output sets DigitalFramer.headroom from the active preset, the same way fill/max_frac are already wired (live, no restart).

D2 — Subtle digital lead-room ("nose room")

  • New tracking.lead_room: float = 0.0 gain (default off / centred, lead=0 reproduces prior framing).
  • DigitalFramer tracks an EMA of the framed subject's centre velocity and offsets the crop centre toward the motion, capped to 12% of the crop so it can't destabilise framing.

Tests

  • union_bbox / _group_union_bbox (pure) tested directly; group crop frames the UNION and is wider than any single box; lost people ignored.
  • Explicit-lock-wins rule tested (locked id and locked identity-via-trusted-bbox both beat the group union).
  • Headroom-by-preset: more headroom lifts the crop; framer field is applied.
  • Lead-room: subject moving right shifts the crop centre right; lead=0 → centred as before; default stays subtle.
  • All existing digital_framer tests (dead-zone hold, aspect lock, split size smoothing) preserved.

Gates

  • ruff check / ruff format --check: clean
  • mypy autoptz/engine/runtime/ autoptz/config/ (strict): clean
  • pytest tests/: 1325 passed
  • python -m autoptz --selftest: all checks passed

🤖 Generated with Claude Code

TCVinNYC and others added 2 commits June 25, 2026 14:04
… lead-room

Digital framer path only (no physical-PTZ controller changes).

D1 — Multi-person group framing (union bbox):
- new tracking.group_framing toggle (default False = no behaviour change)
- union_bbox() pure helper + CameraWorker._group_union_bbox() over the live
  confident, non-lost TrackInfo list
- desired_crop now sizes the crop to fit the subject both vertically and
  horizontally, so a WIDE union auto-widens (zoom out) to keep everyone in
  shot — still aspect-locked and capped by max_frac. Tall single-person boxes
  stay height-driven exactly as before.
- Explicit lock wins: a locked target (by track id or configured identity)
  always keeps following that one person, even with group mode on; group
  framing applies only when no explicit target is locked. trusted_bbox
  fallback for single-target churn is preserved.

D2 — Shot-size-aware headroom:
- _CENTERSTAGE_FRAMING carries a per-preset headroom (face 0.06 →
  head_shoulders 0.08 → upper_body 0.10 → full_body 0.14); _framed_output
  sets DigitalFramer.headroom from the active preset alongside fill/max_frac.

D2 — Subtle digital lead-room ("nose room"):
- new tracking.lead_room gain (default 0.0 = off/centred, exactly as before).
  DigitalFramer tracks an EMA of the subject-centre velocity and offsets the
  crop centre toward the motion, capped to 12% of the crop so it can't
  destabilise framing.

All existing digital_framer tests (dead-zone hold, aspect lock, split size
smoothing) preserved. Gates: ruff/format clean, mypy strict clean, 1325
pytest passed, selftest passed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…oup union

Review of PR #118 found two minors:
- Lock-wins leak: an explicit lock with no live track and no trusted_bbox fell
  through to the group union. Now an explicit lock returns None instead — it
  always wins, even transiently.
- The width-aware crop sizing now requires fit_width=True (passed only for a
  multi-person union via _digital_target_is_group); single-person / non-group
  framing stays strictly height-only, byte-identical to prior behavior.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@TCVinNYC TCVinNYC merged commit 88da0ce into main Jun 25, 2026
3 checks passed
@TCVinNYC TCVinNYC deleted the feat/group-framing-composition branch June 25, 2026 22:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant