System designExplainer

YOLO demo output explained: one result per processed frame

Darknet's YOLO detector demo prints one output block per processed frame, not on a timer. Read the FPS lines, predict result counts and change the output rate.

LumaSpec Vision9 min read Share on LinkedIn

On this page 9 sections
  1. 01One result block per processed frame, not per interval
  2. 02Why 2241 lines came out of a 1416-frame clip
  3. 03The first FPS line is a warm-up artifact
  4. 04From FPS lines to run time and result interval
  5. 05Changing the result rate: three levers, one decision
  6. 06The same pacing law on production hardware
  7. 07Where one-block-per-frame bends
  8. 08Checks before you commit the numbers
  9. 09Questions

Run Darknet's detector demo on a video file and the console fills with FPS: lines interleaved with detections such as car:91%. If you went looking for the setting that reports results every second, there is none: the demo prints one result block for every frame it processes, so output pacing follows your inference speed, not the clock. This page explains the loop behind those lines, why 2241 printed lines can come out of a 1416-frame clip, why the first FPS number looks absurd, and the arithmetic that turns a log into run time and result interval. It closes with the decision that matters for inspection work: how to deliberately get more or fewer results per part.

One result block per processed frame, not per interval

detector demo is a loop with three steps: fetch one frame, run the network on it once, print. The print writes one FPS: measurement, then one line for each detection above the confidence threshold — car:80%, person:98%, and so on. The loop lives in the framework's demo source, the demo.c file that ships with the code, so read it once and the pacing contract is plain: read a video, process each frame, output that frame's detections.

Two consequences follow. The number of result blocks equals the number of frames actually processed, never the number of seconds in the clip. And the video's own frame rate has no say in pacing: 30 fps is a playback property, while the loop pulls frames as fast as decoding delivers them. It never fetches extra frames to fill a quota, and it never waits for a time boundary before printing.

FPS lines = frames processed (one per frame) detection lines = detections above threshold (zero or more per frame) total lines = frames processed + total detections

Why 2241 lines came out of a 1416-frame clip

Count lines, not seconds, and the numbers reconcile. Take the reported run: a 1416-frame clip, 30 fps on the container, 2241 printed lines. If every frame was processed, 1416 of those lines are FPS: measurements.

That leaves 2241 − 1416 = 825 detection lines, or 825 / 1416 ≈ 0.58 detections per frame across the clip — what a street scene produces as cars and people drift in and out of view. The split is illustrative: it assumes each frame was processed once and every FPS: line was counted once. If your own log shows fewer FPS: lines than frames, frames were dropped during decode, and counting result blocks beats dividing clip length by 30. Reported capture metadata deserves the same suspicion, as when OpenCV returns a frame rate of zero shows.

The first FPS line is a warm-up artifact

FPS:12052.6 measures nothing real. The rate is computed from a timing baseline that does not yet represent a full frame interval, so the divisor collapses and the print spikes. Discard the first two or three FPS: lines; they are warm-up.

The steady lines in the sample run — 6.9, 6.4, 8.6, 8.0, 4.9, 8.7 — average (6.9 + 6.4 + 8.6 + 8.0 + 4.9 + 8.7) / 6 = 7.25 fps. Call the throughput about 7 fps and expect single frames to scatter between 4.9 and 8.7. That scatter, not the clip, sets the run-time spread you will see.

From FPS lines to run time and result interval

Three conversions turn a log into commitments. The footage length belongs to the file, and it is the only one that uses the container's 30 fps. The run time and the result interval belong to your hardware and use the measured rate alone.

footage length (s) = frame count / container frame rate run time (s) = frames processed / measured FPS result interval (s) = 1 / measured FPS

The 4.9–8.7 fps scatter moves the run time between 1416 / 8.7 ≈ 163 s and 1416 / 4.9 ≈ 289 s, so quote the 202 s figure as a midpoint rather than a promise. Doubling throughput halves it: at 14 fps the same clip takes 1416 / 14 ≈ 101 s, with a result every 1 / 14 ≈ 0.07 s.

Changing the result rate: three levers, one decision

The demo's command line takes the data file, the network configuration, the weights and the video path — and no output-interval flag among them. The lever is always the frame supply or the detector's speed.

  1. Process every frame, the default. Result blocks track the frame count. Right choice when every frame carries inspection value.
  2. Detect every Nth frame. Keep fetching every frame but run detection only on every Nth, and output falls to frame count / N. Size N from the job: N = frames captured per part / results required per part. A stream delivering 15 frames per part that needs 3 checks per part detects every 5th frame (15 / 3 = 5) and returns 3 results.
  3. Raise the measured FPS. A smaller network input or a lighter model processes the same frames faster, printing more blocks per second and shortening the run. The same lever shows up outside deep learning, in shrinking the search area to lift a slow update rate.

Fix N from the inspection requirement first, then spend the throughput you have left on input resolution or a heavier model. Starting from the model and hoping the pacing works out is how stations end up a frame behind the line.

The same pacing law on production hardware

On a line the law is identical: one result per acquired image, delivered at the rate inference completes. A camera feeding 30 fps into a detector that finishes 7 fps builds a queue frame by frame, and the general case is worked through in acquisition faster than processing: closing the frame-rate gap. The remedy is the same N decision or a faster runtime, chosen on hardware that matches the loop.

For defect calls rather than object boxes, the same per-frame question runs through adding AI surface inspection to cameras you already have. On-device detection lives in the smart cameras category, filterable by resolution and interface in the camera finder.

The MV-SC5060XM-08M-WBN from the SC5000X line carries a 6 MP mono sensor over GigE in an M12 mount, so fetch, detect and report run behind the lens.

Smart cameras & vision sensorsHikrobot MV-SC5060XM-08M-WBN SC5000X series Smart Camera, 6 MP, Mono, 8 mm focal length, M12-mountMV-SC5060XM-08M-WBN
Interface
GigE
Resolution
6-10 MP
Sensor format
1/2.4"
Shutter
Rolling
$1,629.00View part

Custom frameworks want PC-class inference beside the cameras, which is what the vision controllers category is for. The MV-VC5525-256G70-NN pairs an Intel Core i5 with 32 GB of memory and a 256 GB SSD, plus PoE camera ports and eight built-in light channels, so grabbing, lighting and detection share one box.

Vision controllersHikrobot MV-VC5525-256G70-NN VC5000 Vision Controller, 12th-I5, 32GB+256G SSD, Supported PCIEMV-VC5525-256G70-NN
LAN ports
5+ LAN ports
USB 3 ports
3-4 USB 3 ports
PoE
PoE camera ports
Light outputs
8 built-in channels
$4,479.00 · quotedView and quoteBuild a system with it

Tighter cells and smaller cabinets get the same loop from two smaller controllers:

Vision controllersHikrobot MV-VAC3504X-128G01 AI inference terminal 3504X single cardMV-VAC3504X-128G01
LAN ports
5+ LAN ports
USB 3 ports
3-4 USB 3 ports
$3,929.00 · quotedView and quote
Vision controllersHikrobot MV-VC2140-128G40-1T VC2100 Vision Controller, N97, 8GB+128G SSD+ 1THDDMV-VC2140-128G40-1T
LAN ports
3-4 LAN ports
USB 3 ports
2 USB 3 ports
$1,679.00View part

Where one-block-per-frame bends

Three cases move the count. Decode or grab failures drop frames, so FPS: lines fall below the clip's frame count; count blocks instead of dividing by 30. Triggered camera streams make the result rate equal the trigger rate, and the container rate never appears at all. And stdout is a diagnostics channel, not an interface: class lines and FPS: lines interleave, so parse the log for debugging only. To measure what your loop really achieves, use the method in measuring camera frame rate from timestamped frames.

Checks before you commit the numbers

  • Discard the first two or three FPS: lines; the 12052.6-style spike is warm-up, not throughput.
  • Average at least ten steady lines and use the mean, never the fastest.
  • Expected line count = frames processed + detections above threshold; a clean 1416-frame run shows 1416 FPS: lines.
  • Convert once, then quote: run time = frames / mean FPS, result interval = 1 / mean FPS.
  • Fix the skip factor N from results required per part before the first deployment, not after the first slow run.

From here the move is short: point the same loop at a camera instead of a file, size the smart camera or controller for the measured fps with margin, and take the frame budget through the system configurator before ordering. More pacing and throughput write-ups sit on the systems topic page, and the quote form turns a settled frame budget into a build.

Questions

Does the Darknet demo report detections once per second?

No. The demo loop runs fetch, detect, print once for every frame it takes from the video, so results arrive once per processed frame in wall-clock terms. At a measured 7 fps that is one block about every 0.14 s; at 20 fps, one every 0.05 s. The input file's 30 fps label only sets playback length — 1416 frames at 30 fps is 47.2 s of footage — and none of that schedules the prints.

Why does the console show more lines than the video has frames?

Each processed frame prints one FPS line plus one line for every detection above the confidence threshold, so a frame holding a car and a person adds three lines. For the 1416-frame clip: 2241 printed lines − 1416 FPS lines = 825 detection lines, about 0.58 detections per frame on average. Count only the FPS: lines when you need the processed-frame total.

How do I get a detection every N frames instead of every frame?

There is no results-per-second switch on the command line; change the frame supply instead. Keep fetching every frame but run detection and printing only on every Nth: the output count becomes frame count / N. Size N from the job with N = frames captured per part / results required per part — a stream delivering 15 frames per part that needs 3 checks per part detects every 5th frame and returns 3 results.

What does the FPS:12052.6 line at the start mean?

It is a timing measurement taken before a full frame interval exists, so the divisor is far too small and the printed rate is meaningless. Discard the first two or three FPS lines, then average at least ten steady lines from the middle of the run. The mean, not the fastest line, is what your cycle-time and run-time math should use.

Can a 7 fps detector keep up with a 30 fps production stream?

No. Completing about 7 detections per second against a 30 fps stream queues frames at 30 − 7 = 23 per second, so lag grows until memory fills. Match the rates instead: shrink the network input, run a lighter model, or detect every Nth frame so the loop drains as fast as the camera delivers. The same arithmetic governs smart cameras and controllers.