The engine was searching an empty room fifteen times a second
Measured rather than guessed, and the first guess was wrong. Wall clock said H.265 decode cost 58 ms a frame; cap.read() blocks until the next frame arrives, so that was the frame interval, not work. As CPU time: decode 3.7 ms, detection 31.0 ms - and detection ran on every frame whether or not anything was in front of the camera, 6,649 of 8,634 frames with faces_seen 0 and active_tracks 0 throughout. detect_threads: OpenCV spreads a small repeated job over eight threads, costing 31.0 ms of CPU for 8.9 ms of wall. One thread costs 15.3 ms for 15.3 ms, against a 66 ms budget at 15 fps. Half the CPU for latency nothing can notice. motion_gate: a 160x90 greyscale absdiff, 0.1 ms against detection's 15. Consulted only while no track is open; forced to look every motion_max_skip frames; compared against the last frame SEARCHED so a slow drift cannot creep under the threshold; and a threshold above this camera's measured noise and far below a person, so anything ambiguous detects. tests/test_motion_gate.py pins each of those rather than the saving, including asserting the longest run of skips rather than the total - counting the total would pass a gate that slept forty frames and then looked forty times. Together 80% -> 16% of a core, detection skipped on 92% of frames. faces_seen is still 0 and the gate is not why: run directly over the same frames the detector finds nothing at threshold 0.50 either. The placement is the limit, as recorded; the CPU was being spent to rediscover that fifteen times a second. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KGcjxF1cNLcuwc3DAPcnfj
This commit is contained in:
@@ -132,6 +132,29 @@ class AppSection(BaseModel):
|
||||
# on changes what the system is under GDPR and India's DPDP, so it has to
|
||||
# be a decision somebody makes rather than one they inherit.
|
||||
store_faces: bool = False
|
||||
# How many threads OpenCV may use for detection. Measured on the office
|
||||
# camera (800x448 sub-stream): the default of 8 costs 31 ms of CPU per
|
||||
# frame for 8.9 ms of wall time, while ONE thread costs 15.3 ms of CPU for
|
||||
# 15.3 ms of wall - half the CPU for 6 ms more latency, against a 66 ms
|
||||
# frame budget at 15 fps. The default is wrong here because OpenCV sizes it
|
||||
# for one big job on an idle machine, and this is a small job repeated
|
||||
# forever on a machine also running the recogniser, the tracker and three
|
||||
# other cameras. 0 leaves OpenCV's own default alone.
|
||||
detect_threads: int = 1
|
||||
# Skip detection on frames where nothing has changed and nothing is being
|
||||
# tracked. A shop is empty most of the day and a frame of an empty room
|
||||
# costs exactly as much to search as a busy one. See CameraWorker.run for
|
||||
# why this cannot lose a face.
|
||||
motion_gate: bool = True
|
||||
# Mean absolute difference, 0-255, over a 160x90 greyscale thumbnail. 1.0
|
||||
# is well below the noise floor of a real camera - measured on this one,
|
||||
# an empty room varies by ~0.3 between frames - so it triggers on movement
|
||||
# rather than on sensor noise, and anything ambiguous detects.
|
||||
motion_threshold: float = 1.0
|
||||
# Detect at least this often regardless of the gate, so a change the
|
||||
# thumbnail cannot see - someone entering at the far edge, a slow lean into
|
||||
# frame - is still found within a second.
|
||||
motion_max_skip: int = 12
|
||||
|
||||
|
||||
class ApiSection(BaseModel):
|
||||
|
||||
Reference in New Issue
Block a user