From decc8aa391fe71bf08fc33467889ff30bba30ada Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Sun, 29 Mar 2026 11:12:01 -0600 Subject: [PATCH] Incrase frequency of secondary pipeline updates (#22673) * Incrase frequency of secondary pipeline updates when an object needs it * Handle buffer timestamps correctly * Consider LP that are not sub label --- frigate/camera/state.py | 49 +++++++++++++++++-- .../post/review_descriptions.py | 7 ++- 2 files changed, 49 insertions(+), 7 deletions(-) diff --git a/frigate/camera/state.py b/frigate/camera/state.py index 7355afe6b..a203264a6 100644 --- a/frigate/camera/state.py +++ b/frigate/camera/state.py @@ -54,6 +54,28 @@ class CameraState: self.ptz_autotracker_thread = ptz_autotracker_thread self.prev_enabled = self.camera_config.enabled + # Minimum object area thresholds for fast-tracking updates to secondary + # face/LPR pipelines when using a model without built-in detection. + self.face_recognition_min_obj_area: int = 0 + self.lpr_min_obj_area: int = 0 + + if ( + self.camera_config.face_recognition.enabled + and "face" not in config.objects.all_objects + ): + # A face is roughly 1/8 of person box area; use a conservative + # multiplier so fast-tracking starts slightly before the optimal zone + self.face_recognition_min_obj_area = ( + self.camera_config.face_recognition.min_area * 6 + ) + + if ( + self.camera_config.lpr.enabled + and "license_plate" not in self.camera_config.objects.track + ): + # A plate is a smaller fraction of a vehicle box; use ~20x multiplier + self.lpr_min_obj_area = self.camera_config.lpr.min_area * 20 + def get_current_frame(self, draw_options: dict[str, Any] = {}) -> np.ndarray: with self.current_frame_lock: frame_copy = np.copy(self._current_frame) @@ -372,13 +394,30 @@ class CameraState: updated_obj.last_updated = frame_time - # if it has been more than 5 seconds since the last thumb update - # and the last update is greater than the last publish or - # the object has changed significantly or - # the object moved enough to update the path + # Determine the staleness threshold for publishing updates. + # Fast-track to 1s for objects in the optimal size range for + # secondary face/LPR recognition that don't yet have a sub_label. + obj_area = updated_obj.obj_data.get("area", 0) + obj_label = updated_obj.obj_data.get("label") + publish_threshold = 5 + + if ( + obj_label == "person" + and self.face_recognition_min_obj_area > 0 + and obj_area >= self.face_recognition_min_obj_area + and updated_obj.obj_data.get("sub_label") is None + ) or ( + obj_label in ("car", "motorcycle") + and self.lpr_min_obj_area > 0 + and obj_area >= self.lpr_min_obj_area + and updated_obj.obj_data.get("sub_label") is None + and updated_obj.obj_data.get("recognized_license_plate") is None + ): + publish_threshold = 1 + if ( ( - frame_time - updated_obj.last_published > 5 + frame_time - updated_obj.last_published > publish_threshold and updated_obj.last_updated > updated_obj.last_published ) or significant_update diff --git a/frigate/data_processing/post/review_descriptions.py b/frigate/data_processing/post/review_descriptions.py index 1eda8ee8f..9cfdd42c5 100644 --- a/frigate/data_processing/post/review_descriptions.py +++ b/frigate/data_processing/post/review_descriptions.py @@ -149,10 +149,13 @@ class ReviewDescriptionProcessor(PostProcessorApi): additional_buffer_per_side = (MIN_RECORDING_DURATION - duration) / 2 buffer_extension = min(5, additional_buffer_per_side) + final_data["start_time"] -= buffer_extension + final_data["end_time"] += buffer_extension + thumbs = self.get_recording_frames( camera, - final_data["start_time"] - buffer_extension, - final_data["end_time"] + buffer_extension, + final_data["start_time"], + final_data["end_time"], height=480, # Use 480p for good balance between quality and token usage )