pyronear / pyronear/pyro-annotator

Import: sibling boxes from others_bboxes — lane coverage audit, silent drops, and cross-alert lanes

Open
#266 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
0
Forks
1
Avg merge
1d 2h
Merged PRs (30d)
2

Description

Context

While reviewing imported sequences, some sibling boxes (from the alert API's others_bboxes) appeared in the annotation UI without a corresponding object lane. This issue documents an investigation of how the object-split import currently handles siblings, verified against the code (synthetic repro) and a DB audit (2026-08-04, local stack, 474 sequences imported 2026-08-03).

How it works today

object_split.split_all_records merges each fetched sequence's bbox + others_bboxes per frame and replays pyro-api's association rule offline (object_clustering.cluster_objects: attach on any-pixel overlap, spawn a new object once 3 overlapping unassigned boxes accumulate within 300s). Each clustered object becomes its own annotation sequence (primary keeps the raw alert id; siblings get synthetic ids sharing platform_alert_id). A sibling group whose own boxes match another fetched alert sequence's boxes is skipped (cross-dedup) — the lane is expected to come from that other sequence.

Findings

1. Below-threshold siblings are dropped silently — and stripped from display (bug).
When at least one object spawns, sibling boxes that never reach the 3-in-300s threshold are dropped with no log line and no stat counter. Worse, the split rewrites detection_others_bboxes from clustered objects only (object_split.py:209-213), so the dropped boxes also vanish from the read-only sibling display. Annotators lose the visual hint entirely, and the DB retains no trace of them (cannot be quantified after the fact). Verified with a synthetic repro: a sibling present on 2 frames produces no lane and empty others_bboxes in every emitted record.

2. DB audit: no visible sibling is truly lane-less, but 44% have their lane under a different alert (relates #262).
Of 2,106 visible sibling-box occurrences across 103 sequences:

  • 1,178 (56%) have their lane in the same platform_alert_id group (synthetic sibling sequence next to the primary).
  • 928 (44%, across 50 sequences) have their lane only under a different platform_alert_id — cross-deduped siblings that the alert API materialized as their own alert. Since the UI groups lanes by platform_alert_id, these render as grey sibling boxes with no lane in that alert's lane list, which looks exactly like "sibling not imported as a lane".
  • 0 occurrences lack a spatially overlapping lane in some same-camera, same-day sequence.

Example verified end-to-end: bidon-ldd-01 alerts 55855/55856/55857/55861 (2026-07-28) — four objects, each imported as its own sequence, each seeing the others' boxes as siblings, no shared platform_alert_id.

3. --frames-limit 30 truncation. The owner of a sibling box can have its imported detections capped at 30 frames, so later frames of a neighboring sequence show its boxes with no temporally matching lane detections (e.g. seq alert 55861 shows 55855's box after 08:40 while 55855's imported frames stop at 08:30).

4. Cross-run dedup gap (already documented in object_split.py). Cross-dedup only works within one run; sequences split across a date-range boundary into different runs are not deduplicated.

Recommendation

Keep the 3-detection spawn threshold — it matches the platform's object definition, and the audit shows the alert API reliably materializes real siblings as their own alert sequences. Lowering it would create lanes from partial evidence and increase cross-run duplicate lanes (finding 4). Instead:

  1. Surface cross-alert sibling lanes in the same view (#262) — this addresses 100% of the visible gap.
  2. Preserve unclustered boxes in the rewritten others_bboxes so below-threshold siblings stay visible read-only (missed-smoke flag remains usable).
  3. Count dropped boxes in split_stats and log them so drops are no longer silent.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in object_split.py, especially split_all_records and the rewrite around lines 209-213, then trace object_clustering.cluster_objects and split_stats. Reproduce the two-frame sibling case described in the issue and inspect how cross-alert lanes are displayed under #262. Done means below-threshold boxes remain visible, drops are counted and logged, and cross-alert sibling lanes are surfaced in the same view.

Written by the indexing model from the issue text.

Assessment

Tech stack
python, typescript
Domain
backend, frontend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.