Skip to content

Commit 4607a68

Browse files
MagicalTuxclaude
andcommitted
demo: capture now records what the HUD shows (tracked codes + composited overlay)
The capture saved the raw video frame (no HUD) and logged raw locator hits, so it could not show whether the on-screen reticle noise was actually filtered. It now composites the HUD onto the PNG and logs the tracked/filtered candidate set (with hit counts) as 'tracked', keeping raw locator output under 'rawLocate' for reference. A capture now reflects exactly what the user sees. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 8560aa3 commit 4607a68

1 file changed

Lines changed: 13 additions & 4 deletions

File tree

web/index.html

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -614,14 +614,23 @@ <h2>Decode an image</h2>
614614
scratch.width = pw; scratch.height = ph;
615615
const sctx = scratch.getContext('2d', { willReadFrequently: true });
616616
sctx.drawImage(video, 0, 0, pw, ph);
617+
// Composite the HUD exactly as drawn on screen (processed-resolution, so scale 1:1)
618+
// so the saved PNG shows what you actually see — the tracked reticles and locks, not
619+
// the raw locator hits.
620+
const rbox = b => ({ x0: Math.round(b.x0), y0: Math.round(b.y0), x1: Math.round(b.x1), y1: Math.round(b.y1) });
621+
renderHUD(sctx, pw, ph, acquiring, lastDecoded, 1, 1, performance.now());
617622
// Reuse the live pipeline's already-computed state (off-thread) — never re-decode
618623
// synchronously here, which would freeze the UI on a busy 1080p frame.
619624
const report = {
620625
capturedAt: new Date().toISOString(),
621626
video: { width: vw, height: vh },
622627
processed: { width: pw, height: ph },
623-
locate: liveCands.map(c => ({ family: c.family, corners: c.corners.map(p => [Math.round(p[0]), Math.round(p[1])]) })),
624-
decode: lastDecoded.map(r => ({ symbology: r.symbology, text: r.text, box: r.box || null })),
628+
// What the HUD actually draws: candidate tracks that survived the noise filter.
629+
tracked: acquiring.map(t => ({ box: rbox(t.box), hits: t.hits })),
630+
decode: lastDecoded.map(r => ({ symbology: r.symbology, text: r.text, box: r.box ? rbox(r.box) : null })),
631+
// Raw locator output for reference (pre display-filter; favours recall, so noisy).
632+
rawLocateCount: liveCands.length,
633+
rawLocate: liveCands.map(c => ({ family: c.family, corners: c.corners.map(p => [Math.round(p[0]), Math.round(p[1])]) })),
625634
userAgent: navigator.userAgent,
626635
};
627636
const n = (window.__capN = (window.__capN || 0) + 1);
@@ -631,7 +640,7 @@ <h2>Decode an image</h2>
631640
`captured frame ${pw}×${ph}${liveCands.length} located, ${lastDecoded.length} decoded (saved PNG + JSON)`;
632641
};
633642

634-
let liveCands = [], liveScale = [1, 1], lastLocate = 0, lastMs = 0;
643+
let liveCands = [], acquiring = [], liveScale = [1, 1], lastLocate = 0, lastMs = 0;
635644
function loop(ts) {
636645
if (!running) { return; }
637646
requestAnimationFrame(loop);
@@ -688,7 +697,7 @@ <h2>Decode an image</h2>
688697
// Ease located-candidate tracks too, and only surface the ones that have persisted
689698
// past the noise threshold — this is what the acquiring reticles are drawn from.
690699
for (const t of candTracks) t.box = boxLerp(t.box, t.target, 0.35);
691-
const acquiring = candTracks.filter(t => t.hits >= CAND_MIN_HITS);
700+
acquiring = candTracks.filter(t => t.hits >= CAND_MIN_HITS);
692701
document.getElementById('cam-result').textContent =
693702
lastDecoded.length ? lastDecoded.map(r => `${r.symbology}: ${r.text}`).join('\n') : '';
694703

0 commit comments

Comments
 (0)