← VV AI Video Tracking YOLOv8 / object tracking
○ Idle Architecture ↓

Video intelligence.
Evidence you can inspect.

Analyse uploaded footage or inspect live camera frames. Object labels and model scores are observations—not proof of danger or a guarantee of safety.

LOCAL PILOT / CAMERA FRAMES

See what the model sees.

Camera frames are sent to your configured video service only after you start. They are analysed in memory; this mode does not record a video or detect crimes.

Open VVGov demonstration ↗

Your camera is off.

Not running

Frames are sampled sequentially, up to once per second. Actual speed depends on hardware. A displayed score is not an accuracy measurement.

    ISOLATED GOVERNMENT DEMONSTRATION

    From review to a local queue.

    Test automatic assignment to the nearest fictional station. No real station is contacted and no emergency service is dispatched.

    No demonstration event submitted.

    For a real deployment: validate a cabin-specific event model, calibrate escalation thresholds and agree a response workflow with the department. The current object detector does not recognise assault.

    Drop a video here or click to browse

    MP4, MOV, AVI — the pipeline will detect, track, and export JSON

    One timeline, two synchronized layers

    The video layer and SVG HUD layer are synchronized through video.currentTime. The overlay is a transparent div positioned absolutely over the video element. On each requestAnimationFrame, the renderer reads video.currentTime, looks up the closest track frame, interpolates positions, and updates box positions via CSS transforms.

    01 / VIDEO LAYER

    HTML5 Video

    Standard element with native controls. The timeupdate event and requestAnimationFrame loop drive the overlay sync.

    02 / HUD LAYER

    Absolute-positioned overlay

    A div with pointer-events: none sits on top. Individual detection boxes have pointer-events: auto so they remain interactive.

    03 / SYNC

    currentTime lookup

    Each frame, the renderer finds track observations whose timestamp t is closest to video.currentTime and interpolates between the two nearest samples.

    Backend AI pipeline

    The Python backend decodes the video with OpenCV, runs YOLOv8 detection on sampled frames, applies a ByteTrack-inspired IoU tracker for identity persistence, normalizes all coordinates to 0..1, and exports a JSON payload.

    01 / DECODE

    OpenCV frame extraction

    cv2.VideoCapture reads frames. Only 1 in every sample_rate frames is processed to balance accuracy and speed.

    02 / DETECT

    YOLOv8 inference

    Each sampled frame is passed to the YOLOv8 model. Detections below conf_threshold are discarded. COCO class labels are attached.

    03 / TRACK

    Class-consistent track association

    A two-stage IoU matcher assigns detections to existing tracks. High-confidence detections match first (IoU ≥ 0.5), then low-confidence (IoU ≥ 0.3). Unmatched detections spawn new tracks.

    04 / NORMALIZE

    Coordinate normalization

    Box coordinates are divided by video dimensions to produce 0..1 values. This makes the payload resolution-independent.

    05 / EXPORT

    JSON serialization

    The ai-video-tracks.v1 payload is written to disk. The frontend loads it via fetch() and renders overlays.

    The tracking data contract

    The ai-video-tracks.v1 payload defines a stable interface between the Python backend and the JavaScript frontend. All coordinates are normalized 0..1. Timestamps are in seconds, aligned to video frame rate.

    { "schema": "ai-video-tracks.v1", "video": { "width": 1920, "height": 1080, "fps": 30.0, "duration": 12.5, "frame_count": 375 }, "pipeline": { "detector": "YOLOv8 (yolov8n.pt)", "tracker": "Two-stage IoU tracker", "sample_rate": 5, "conf_threshold": 0.4 }, "tracks": [ { "id": 1, "label": "person", "frames": [ { "t": 0.0, "x": 0.12, "y": 0.34, "w": 0.08, "h": 0.15, "score": 0.92 }, { "t": 0.1667, "x": 0.13, "y": 0.35, "w": 0.08, "h": 0.15, "score": 0.89 } ] } ], "stats": { "total_tracks": 3, "total_detections": 142, "labels": ["car", "person"] } }

    Frontend renderer

    The renderer runs on requestAnimationFrame, reads video.currentTime, performs binary search on each track's frame array, interpolates between the two nearest observations, and positions SVG boxes via CSS transforms.

    01 / LOOKUP

    Binary search by timestamp

    Each track's frames array is sorted by t. A binary search finds the two frames bracketing video.currentTime.

    02 / INTERPOLATE

    Linear interpolation

    Between two frame samples, box position is linearly interpolated: pos = f0 + (f1 - f0) * alpha where alpha = (now - t0) / (t1 - t0).

    03 / RENDER

    CSS transform positioning

    Each box is a div positioned with left, top, width, height as percentages. This avoids SVG reflow overhead.

    04 / LIFECYCLE

    Box creation and removal

    Boxes are created when a track first appears and reused across frames. When a track has no observation near currentTime, its box is hidden via display: none.

    Detection boxes become interface

    Detection boxes are not passive overlays — they are interactive DOM elements. Hover, keyboard focus, and click all produce meaningful responses.

    01 / HOVER

    Eased hover state

    On hover, the box scales to 1.02 with a 150ms ease transition. A glow ring appears via box-shadow. The label becomes fully opaque.

    02 / KEYBOARD

    Focus navigation

    Boxes are tabindex="0". :focus-visible shows a blue outline. Arrow keys move between boxes; Enter selects.

    03 / CLICK

    Selection and custom events

    Clicking a box dispatches a det-select custom event with the track ID. The sidebar highlights the selected track and the info panel shows its details.

    04 / A11Y

    Reduced motion

    When prefers-reduced-motion: reduce is active, all transitions and transforms are disabled. Boxes appear instantly without animation.

    Pilot configuration

    SAMPLING

    Sample rate: 1 in 5 frames

    sample_rate=5 processes 6 samples/sec in a 30fps file. Fast motion can be missed between samples; evaluate sampling against the events you need to observe.

    CONFIDENCE

    Confidence threshold: 0.4

    0.4 is the current pilot threshold, not a validated optimum. Measure missed objects and false detections on representative footage before choosing a deployment threshold.

    PERSISTENCE

    Tracker: max_lost=30, min_hits=3

    A track may be retained internally for 30 sampled updates; it is hidden while unmatched. Three consecutive matches are required before display. At 30fps with sample_rate=5, 30 updates represent about five seconds.

    CORS

    Same-origin or explicit CORS

    In production, the JSON payload is served from the same origin as the video. Cross-origin setups require Access-Control-Allow-Origin headers.

    SECURITY

    Input validation

    Uploads are capped at 100 MB; inference is serialised and temporary media is removed. The local pilot does not provide process sandboxing or production tenant isolation.

    PAYLOAD SIZE

    Payload size varies with activity

    More objects, more sampled frames and longer clips produce larger results. Measure payload size and processing latency using your own footage.

    Implementation plan

    PHASE 1

    Video ingestion

    Set up file upload endpoint. Validate file type and size. Store in temp directory. Return a job ID.

    PHASE 2

    Pipeline execution

    Run pipeline.py as a background task. Stream progress via WebSocket or polling. Store output JSON alongside the video.

    PHASE 3

    Frontend integration

    Load video + JSON. Initialize renderer. Wire up controls (play, seek, conf filter, labels toggle). Test on real footage.

    PHASE 4

    QA and deployment

    Test with diverse videos (night, rain, crowded). Verify interpolation smoothness. Deploy behind Nginx with CORS headers. Monitor payload sizes.