Vision reuse

Reuse in front of a vision model. NeuraFrame™ sits between your app and any vision model served over HTTP (ResNet, YOLO, RF-DETR, a custom classifier or detector) and reuses the model's own answer whenever an image recurs, so the heavy model runs once per distinct scene and every repeat or near-repeat is served from memory.

Connecting your model: HTTP or ONNX

NeuraFrame™ always sits in front of your model over HTTP. It does not replace your model or bundle one, and there is no separate ONNX loader inside the gateway: your model runs where it runs, and NeuraFrame™ is the reuse-aware proxy in front of it. Point the gateway's upstream at wherever your model listens, and every miss is forwarded there unchanged.

Your model is…How to connect
Already an HTTP endpoint (a served classifier or detector, a cloud vision API, NVIDIA Triton, TorchServe, a small web app)Set gateway.upstream_url to its base URL. Nothing else to build.
An ONNX model (a .onnx file you run with onnxruntime)Serve it behind a small HTTP endpoint (NVIDIA Triton, or a few lines of onnxruntime plus a web server) and point gateway.upstream_url at that. NeuraFrame™ then reuses in front of it exactly like any HTTP model. The vision benchmark (vision_bench.py, set NF_RESNET_ONNX) drives a real ONNX ResNet end to end this way.

Either way the reuse layer is identical. Scene mode reuses per entity and region regardless of how the model is hosted: with a whole-image model it reuses the scene safely and escalates any material change; with a model you can query about a region (a detector, or any crop-answerable endpoint) it also sends only the changed crop, for the largest pixel savings.

What it does

Four reuse modes, differing in what each keys on, from the whole image up to a thing followed across a video (plus off to disable reuse):

ModeReuses whenBest for
exactthe identical image comes backre-sent frames, cached requests
neara near-identical image comes back (a recurring view, a re-encoded frame)real streams, where most frames are small variations of ones already seen
scenea known entity recurs, even moved, rotated, rescaled, relit, or partly changedrecurring cameras and monitoring in front of a detector; reuse per region and escalate only what changed
continuousvideo: the same thing continues across frames as the camera or object moves, is briefly occluded, or comes backlive feeds, drones and robots, moving-camera walkthroughs, 360 / equirectangular; classify a thing once and follow it, not every frame
offnever (every image reaches the model)disabling reuse

The model's response is replayed opaquely, so this works the same for a classifier (a label) or a detector (bounding boxes): whatever JSON the model returned is what gets replayed. Novel images always reach the model. NeuraFrame™ never invents an answer.

How near reuse works

On each image NeuraFrame™ computes a compact perceptual code, looks it up in an approximate-nearest-neighbour index for the closest image already seen, and if the closest match is within the configured similarity threshold, replays the stored response without calling the model. Otherwise the request is forwarded and the new image and response are remembered.

Scene mode: reuse by what is in the image, not just the whole image

Exact and near reuse key on the whole frame, so any real change to the image is a miss and the entire image goes back to the model. Scene mode reuses at the level of the things in the image. It keeps a visual memory of the entities it has seen and, on each new image, works out what is the same, what merely moved, and what genuinely changed, then reuses the known parts and sends the model only the small unresolved region. In scene mode NeuraFrame™:

Because it escalates only the small unresolved crop instead of the whole frame, scene mode sends the model a fraction of the pixels a whole-image cache sends, while never serving a stale answer over a real change. On a recurring, monitoring-style stream it sent about one percent of the pixels a near-duplicate cache sends at a safe threshold, with zero stale answers over material changes. The benefit is largest for recurring cameras, video, and repeated-object workflows in front of a heavy model, and smallest for streams of unique, unrelated images. Scene mode suits a model you can query about a region (a detector, or any endpoint that accepts a crop), since its advantage is sending small regions rather than whole frames. Labels are optional throughout: NeuraFrame™ recognises a structure whether or not it has a name, so a missing or changed label never triggers a repeat call.

Continuous mode: video, not a pile of frames

Scene mode treats each image on its own. Continuous mode treats a video (a live feed or a recorded file) as one connected experience. It carries what it has seen from frame to frame, so a thing that has already been classified is followed as it moves rather than re-sent every frame. On each new frame it estimates how the camera moved, predicts where the known things went, and asks the model only about a feature that is genuinely new or has materially changed. This is the mode for cameras that pan and walk, for drones and robots, and for moving through a space. In continuous mode NeuraFrame™:

The same safety rule as scene mode holds throughout: a material change is always escalated, never silently reused, and a thing that only lacks a name is never re-sent just for that. Continuous mode is the natural fit for a video model you can query about a region; it sends the model a small crop for a new or changed feature and reuses everything else it is already following.

Two ways to run it. Live, as a gateway mode: set neuraframe vision mode continuous and stream your frames through the gateway in order, tagging each request with an X-NeuraFrame-Stream header so frames from the same camera are followed together. Or over a file or feed, with the bundled runner nf_continuous.py, which reads a video file, an RTSP or camera feed, or a folder of frames, calls your model (or an OpenAI-style VLM) only when a track needs it, and writes a run report plus optional feature-track, timeline, and unknown-region exports.

# over a recorded file or a live feed, with the runner:
python3 nf_continuous.py --mode continuous --input walk.mp4 \
    --teacher http://127.0.0.1:8080/detect --lookahead 8 \
    --export-feature-tracks --export-timeline
python3 nf_continuous.py --mode continuous --input rtsp://cam/live --equirect   # 360 feed
python3 nf_continuous.py --mode continuous --input frames/ --max-ai-calls 20    # folder of frames, capped

The runner ships in the Studio package alongside the gateway. The full runner options (--device, --teacher / --teacher-model, --equirect, --lookahead, --max-ai-calls, --offline, --output, and the --export-* flags) are listed by python3 nf_continuous.py --help.

Getting the tracking out: by time, as it goes

Continuous mode does not just save model calls; it builds a record of what it saw, when. Every dial below is optional and off by default, so you take exactly the visibility you need and nothing you do not. What the tracker keeps for each thing it follows: its identity across frames, a progressive label, its status (active, occluded, closed), its condition, its full time-ordered path, and its best (representative) view with the time that view was captured. There are three ways to reach it.

1. A live event stream, as it happens. With the runner, --emit-events <file|-> writes one JSON line per frame the moment the frame is processed (- means stdout), so you can watch or pipe the tracking live without waiting for the run to end. Each line carries the frame number, source time, camera-motion state, the number of active tracks, and, for every thing in view, its track id, current label, the route the tracker took (reused, escalated, watching), and its box. This is the time-ordered tracking, frame by frame:

python3 nf_continuous.py --mode continuous --input walk.mp4 --emit-events -
# {"frame": 12, "t": 11, "motion": "sideways", "active_tracks": 2,
#  "routes": [{"track": "track_0001", "label": "valve", "route": "REUSE_AND_UPDATE_LOCATION", "bbox": [..]}]}

2. Export files at the end of a run (with --output <dir>), each opt-in:

FlagWritesContains
--export-feature-tracksfeature_tracks.jsonone record per thing followed: identity, label and confidence, status, first / last / best-view times, best-view box, condition, revisits, model calls and calls avoided.
--export-trajectorytrajectories.jsoneach track's complete path over time: its box at every frame it was seen. Also adds the path into feature_tracks.json.
--export-timelinetimeline.jsonthe whole run as a per-frame list (motion and routes), the same events as the live stream, gathered into one file.
--save-representative-framesviews/ + views_index.jsonthe actual best-view image of each tracked thing, saved as a PNG named by track and time, with an index.
--export-unknownsunknowns.jsonthe things it recognised and followed but that have no name yet (visually known, unnamed).

3. Live, from the gateway. When you stream frames through the gateway in continuous mode, each response carries an X-NeuraFrame-Tracking header with the same compact per-frame readout (motion, active tracks, and each track's id, label, route and box), so an HTTP client gets the same visibility as the runner without changing its request. The gateway also keeps a per-stream workspace (its neuraframe vision memory file) with the current tracks, their best views, and the latest frame summary, readable on demand. Best-view images are kept in memory by default; on a very long live stream you can turn that off with the keep_best_view_images knob to save memory while still getting metrics and trajectories.

Continuous mode is an early release. It is validated and safe by the same rule as the rest of NeuraFrame™ (a material change is never silently reused), and we are actively refining it as more people run it on their own video; if you put it to work on your footage we would genuinely value your feedback on what helped and what you needed that was not there.

Enable it

Point your app's base URL at the NeuraFrame™ Gateway and set the upstream to your vision model (see Configuration & profiles), then configure vision reuse from the CLI:

neuraframe vision on                 # turn on image reuse
neuraframe vision mode near          # off | exact | near | scene | continuous
neuraframe vision mode scene         # reuse by entities and regions, escalate only what changed
neuraframe vision mode continuous    # video: follow a thing across frames (tag each frame with X-NeuraFrame-Stream)
neuraframe vision threshold 90       # near-match strictness, 0..100 (higher = stricter)
neuraframe vision memory             # what the visual memory knows and what it has avoided sending
neuraframe vision status             # show current settings
sudo systemctl restart neuraframe-studio

If your endpoint takes the image as a base64 field inside a JSON body rather than a raw image POST, tell NeuraFrame™ where to find it, and set which request paths are vision endpoints if they are not the defaults (/v1/vision, /predict, /infer, /detect, /classify):

neuraframe vision field instances.0.image     # dotted path to the base64 image field
neuraframe vision match /v2/detect,/api/predict

Choosing the mode and threshold

WorkloadSuggested startWhy
Classification (ResNet and similar)mode near, threshold 88A small change to an image rarely changes the class, so near-duplicate reuse is safe at a looser threshold.
Detection (YOLO, RF-DETR)mode near, threshold 95Boxes are position sensitive, so only reuse when the scene is genuinely unchanged. If objects move a lot, use mode exact until you have tuned the threshold on your own stream.
Everything novelleave onExpect little saving; nothing is free when there is nothing to reuse. The saving scales with how often scenes recur.

All controls

Every setting can be set from the CLI (it writes the config; restart the service to apply) or edited directly in the gateway config. Restart after a change.

ControlCLIConfig keyDefault
Enable / disableneuraframe vision on / offvision.enabledoff
Turn vision reuse on or off.
Modeneuraframe vision mode <off|exact|near|scene|continuous>vision.modenear
How reuse decides: exact byte-identical repeats, near near-duplicate whole images, scene per entity and region, continuous follow things across video frames, off never.
Stream id (continuous)-X-NeuraFrame-Stream headerdefault
Request header that tags which camera / stream a frame belongs to, so frames from the same source are followed together. Set it per stream in your client.
Continuous knobsneuraframe vision continuous [<knob> <value>]vision.<knob>see below
The video-mode dials. Run with no arguments to list them with current values and defaults. Knobs: equirect (on/off, 360 wrap), lookahead_frames (recorded look-ahead; 0 = decide live), max_ai_calls / max_full_frame_calls (per-stream caps, 0 = unlimited), minimum_track_frames (persistence gate: raise to suppress moving background, lower to react faster), miss_to_close (occlusion / leave-and-return tolerance), confidence_threshold, min_classify_area_frac (ignore specks), urgent_area_frac (live: escalate a sudden big change at once), keep_best_view_images (keep each thing's best-view image; off saves memory on very long streams). The detector region path is the shared boxes knob above.
Tracking readout (continuous)-X-NeuraFrame-Tracking response header-
Each continuous-mode response carries a compact per-frame tracking summary (camera motion, active tracks, and each track's id, label, route, and box). The per-stream workspace (neuraframe vision memory) also holds current tracks, best views, and the latest frame summary. The nf_continuous.py runner exposes the same data as a live event stream (--emit-events) and as export files (--export-feature-tracks, --export-trajectory, --export-timeline, --save-representative-frames, --export-unknowns).
Near thresholdneuraframe vision threshold <0-100>vision.threshold90
Near-match strictness, higher is stricter. Applies to near mode.
Image fieldneuraframe vision field <dotted.path>vision.image_fieldraw body
Where the base64 image sits in a JSON request body, e.g. instances.0.image. Leave empty for a raw image POST.
Vision pathsneuraframe vision match <p1,p2,…>vision.match/v1/vision,/predict,…
Which request paths are treated as vision endpoints. Default: /v1/vision,/predict,/infer,/detect,/classify.
Detector boxesneuraframe vision boxes <dotted.path|off>vision.boxes_fieldoff
Turns on the region path for detectors: the dotted path to the list of detections in the model's response (e.g. detections). Off keeps safe whole-image reuse.
Box formatneuraframe vision box_format <fmt>vision.box_formatxyxy_abs
Coordinate convention: xyxy, xywh, or cxcywh, each _abs (pixels) or _norm (0..1).
Box keyneuraframe vision box_key <name>vision.box_keybox
The key holding the box inside each detection item, e.g. box or bbox.
Workspaceneuraframe vision memory--
Show what scene mode knows (entities, concepts, instances) and what it has avoided sending.
Statusneuraframe vision status--
Print the current vision settings.
Upstream modelneuraframe config set gateway.upstream_url <url>gateway.upstream_url-
Where your model listens: an HTTP model, or your ONNX model served behind HTTP.

Equivalent config block:

"gateway": {
  "upstream_url": "http://127.0.0.1:8080",   // your model (HTTP, or ONNX served behind HTTP)
  "vision": {
    "enabled": true,
    "mode": "scene",                          // off | exact | near | scene | continuous
    "threshold": 90,                          // near mode strictness
    "image_field": "instances.0.image",       // omit for a raw image POST
    "match": ["/detect", "/classify"],
    "boxes_field": "detections",              // detectors only: enables the region path (pixel savings)
    "box_format": "xyxy_abs",                 // xyxy|xywh|cxcywh, _abs (pixels) or _norm (0..1)
    "box_key": "box"
  }
}

Two ways scene mode reuses, by whether a box format is set. With no boxes_field (a classifier, or any opaque whole-image model) scene mode reuses the whole-image answer only when the scene is unmoved and unchanged, and always escalates a material change: safe, but it forwards the whole image on a miss. With boxes_field set (a detector), it also reuses a moved object's boxes by shifting them (no model call), and on a real change sends only the changed entity's crop and merges the result, which is where the large pixel savings come from. If a response ever fails to parse in the configured format, scene mode falls back to forwarding the whole image, so it can never emit a broken answer.

Measured behaviour

On a recurring stream, near mode makes one model call per distinct scene and reuses the rest at the model's own answer. At 10x recurrence that is roughly 90 percent of model calls avoided at 100 percent agreement with the always-on model. The wall-time speedup grows with how heavy the model is: the more expensive each call, the closer the speedup tracks the calls avoided. See the Benchmarks for the measured ResNet-152 figures.

On a synthetic panning video (a moving camera, one object damaged mid-stream, one object leaving and returning), continuous mode made 3 model calls across 13 frames and sent about 1 percent of the pixels a whole-image cache sends, with zero stale answers over the material change, while a whole-image cache, which cannot follow a thing across a pan, served several stale answers at the same recurrence. It classified each object once, followed both through the pan, and recognised the object that left and came back as the same thing. The comparison harness is vision_bench3.py, re-run on every release.

Requirements and limits

Near and scene modes use numpy and Pillow; if they are not present the gateway degrades cleanly to exact-only reuse. Near reuse is keyed on whole-image appearance. Scene mode reuses per entity and keeps separate instances and concepts, so it recognises the same object moved or changed as well as different instances of the same kind, and escalates only the changed region. Its advantage depends on being able to separate the scene into entities: it is strongest on recurring cameras, monitoring, and repeated objects in front of a region-answerable model, and lighter on dense, cluttered natural scenes. As with all NeuraFrame™ reuse, novel inputs still require the model, a material change is always escalated rather than silently reused, and production use should be validated on your own stream.

Beyond reuse: complex identification

Vision reuse answers "have I seen this before?". Its 0.6.0 sibling answers a bigger question: "what are all the distinct things in this footage, and what does each one mean under MY standard?" You author a codebook (your codes, your grading, your rules), the tracker identifies every distinct thing across the footage with no model calls, and each one is coded once from a dossier of its best views, with every graded attribute a deterministic lookup rather than a model guess. The reuse gate is off by default in that mode and can be turned on. See Complex identification.