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.
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.
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.
- Process every frame, the default. Result blocks track the frame count. Right choice when every frame carries inspection value.
- 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.
- 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.
- Interface
- GigE
- Resolution
- 6-10 MP
- Sensor format
- 1/2.4"
- Shutter
- Rolling
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.
- LAN ports
- 5+ LAN ports
- USB 3 ports
- 3-4 USB 3 ports
- PoE
- PoE camera ports
- Light outputs
- 8 built-in channels
Tighter cells and smaller cabinets get the same loop from two smaller controllers:
- LAN ports
- 5+ LAN ports
- USB 3 ports
- 3-4 USB 3 ports
- LAN ports
- 3-4 LAN ports
- USB 3 ports
- 2 USB 3 ports
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.



