From 9971d31101dcd602515e20b5bdbfed1f64ca1fdb Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Tue, 18 Mar 2025 17:29:25 -0600 Subject: [PATCH] Add per-camera face and lpr configs --- docs/docs/configuration/reference.md | 17 +++++++++++--- frigate/config/camera/camera.py | 6 +++++ frigate/config/classification.py | 17 ++++++++++++++ frigate/config/config.py | 28 ++++++++++++----------- frigate/data_processing/real_time/face.py | 9 +++++++- 5 files changed, 60 insertions(+), 17 deletions(-) diff --git a/docs/docs/configuration/reference.md b/docs/docs/configuration/reference.md index 9a880aade..2bdf842e0 100644 --- a/docs/docs/configuration/reference.md +++ b/docs/docs/configuration/reference.md @@ -543,12 +543,23 @@ semantic_search: model_size: "small" # Optional: Configuration for face recognition capability +# NOTE: Can (enabled, min_area) be overridden at the camera level face_recognition: # Optional: Enable semantic search (default: shown below) enabled: False - # Optional: Set the model size used for embeddings. (default: shown below) - # NOTE: small model runs on CPU and large model runs on GPU - model_size: "small" + # Optional: Minimum face distance score required to save the attempt (default: shown below) + min_score: 0.8 + # Optional: Minimum face detection score required to detect a face (default: shown below) + # NOTE: This only applies when not running a Frigate+ model + detection_threshold: 0.7 + # Optional: Minimum face distance score required to be considered a match (default: shown below) + recognition_threshold: 0.9 + # Optional: Min area of detected face box to consider running face recognition (default: shown below) + min_area: 500 + # Optional: Save images of recognized faces for training (default: shown below) + save_attempts: True + # Optional: Apply a blur quality filter to adjust confidence based on the blur level of the image (default: shown below) + blur_confidence_filter: True # Optional: Configuration for license plate recognition capability lpr: diff --git a/frigate/config/camera/camera.py b/frigate/config/camera/camera.py index 2d928661e..6d21d6be1 100644 --- a/frigate/config/camera/camera.py +++ b/frigate/config/camera/camera.py @@ -19,6 +19,10 @@ from frigate.util.builtin import ( from ..base import FrigateBaseModel from .audio import AudioConfig from .birdseye import BirdseyeCameraConfig +from ..classification import ( + CameraFaceRecognitionConfig, + CameraLicensePlateRecognitionConfig, +) from .detect import DetectConfig from .ffmpeg import CameraFfmpegConfig, CameraInput from .genai import GenAICameraConfig @@ -52,6 +56,7 @@ class CameraConfig(FrigateBaseModel): detect: DetectConfig = Field( default_factory=DetectConfig, title="Object detection configuration." ) + face_recognition: CameraFaceRecognitionConfig = Field(default_factory=CameraFaceRecognitionConfig, title="Face recognition config.") ffmpeg: CameraFfmpegConfig = Field(title="FFmpeg configuration for the camera.") genai: GenAICameraConfig = Field( default_factory=GenAICameraConfig, title="Generative AI configuration." @@ -59,6 +64,7 @@ class CameraConfig(FrigateBaseModel): live: CameraLiveConfig = Field( default_factory=CameraLiveConfig, title="Live playback settings." ) + lpr: CameraLicensePlateRecognitionConfig = Field(default_factory=CameraLicensePlateRecognitionConfig, title="LPR config.") motion: Optional[MotionConfig] = Field( None, title="Motion detection configuration." ) diff --git a/frigate/config/classification.py b/frigate/config/classification.py index 30cd12b7c..45ac876a6 100644 --- a/frigate/config/classification.py +++ b/frigate/config/classification.py @@ -6,6 +6,8 @@ from pydantic import Field from .base import FrigateBaseModel __all__ = [ + "CameraFaceRecognitionConfig", + "CameraLicensePlateRecognitionConfig", "FaceRecognitionConfig", "SemanticSearchConfig", "LicensePlateRecognitionConfig", @@ -78,6 +80,13 @@ class FaceRecognitionConfig(FrigateBaseModel): ) +class CameraFaceRecognitionConfig(FrigateBaseModel): + enabled: bool = Field(default=False, title="Enable face recognition.") + min_area: int = Field( + default=500, title="Min area of face box to consider running face recognition." + ) + + class LicensePlateRecognitionConfig(FrigateBaseModel): enabled: bool = Field(default=False, title="Enable license plate recognition.") detection_threshold: float = Field( @@ -112,3 +121,11 @@ class LicensePlateRecognitionConfig(FrigateBaseModel): known_plates: Optional[Dict[str, List[str]]] = Field( default={}, title="Known plates to track (strings or regular expressions)." ) + + +class CameraLicensePlateRecognitionConfig(FrigateBaseModel): + enabled: bool = Field(default=False, title="Enable license plate recognition.") + min_area: int = Field( + default=1000, + title="Minimum area of license plate to begin running recognition.", + ) diff --git a/frigate/config/config.py b/frigate/config/config.py index ce59e6733..f77a83f28 100644 --- a/frigate/config/config.py +++ b/frigate/config/config.py @@ -331,19 +331,6 @@ class FrigateConfig(FrigateBaseModel): default_factory=TelemetryConfig, title="Telemetry configuration." ) tls: TlsConfig = Field(default_factory=TlsConfig, title="TLS configuration.") - classification: ClassificationConfig = Field( - default_factory=ClassificationConfig, title="Object classification config." - ) - semantic_search: SemanticSearchConfig = Field( - default_factory=SemanticSearchConfig, title="Semantic search configuration." - ) - face_recognition: FaceRecognitionConfig = Field( - default_factory=FaceRecognitionConfig, title="Face recognition config." - ) - lpr: LicensePlateRecognitionConfig = Field( - default_factory=LicensePlateRecognitionConfig, - title="License Plate recognition config.", - ) ui: UIConfig = Field(default_factory=UIConfig, title="UI configuration.") # Detector config @@ -395,6 +382,21 @@ class FrigateConfig(FrigateBaseModel): title="Global timestamp style configuration.", ) + # Classification Config + classification: ClassificationConfig = Field( + default_factory=ClassificationConfig, title="Object classification config." + ) + semantic_search: SemanticSearchConfig = Field( + default_factory=SemanticSearchConfig, title="Semantic search configuration." + ) + face_recognition: FaceRecognitionConfig = Field( + default_factory=FaceRecognitionConfig, title="Face recognition config." + ) + lpr: LicensePlateRecognitionConfig = Field( + default_factory=LicensePlateRecognitionConfig, + title="License Plate recognition config.", + ) + camera_groups: Dict[str, CameraGroupConfig] = Field( default_factory=dict, title="Camera group configuration" ) diff --git a/frigate/data_processing/real_time/face.py b/frigate/data_processing/real_time/face.py index acb891449..568a4f202 100644 --- a/frigate/data_processing/real_time/face.py +++ b/frigate/data_processing/real_time/face.py @@ -289,6 +289,9 @@ class FaceRealTimeProcessor(RealTimeProcessorApi): def process_frame(self, obj_data: dict[str, any], frame: np.ndarray): """Look for faces in image.""" + if not self.config.cameras[obj_data["camera"]].face_recognition.enabled: + return + start = datetime.datetime.now().timestamp() id = obj_data["id"] @@ -349,7 +352,11 @@ class FaceRealTimeProcessor(RealTimeProcessorApi): face_box = face.get("box") # check that face is valid - if not face_box or area(face_box) < self.config.face_recognition.min_area: + if ( + not face_box + or area(face_box) + < self.config.cameras[obj_data["camera"]].face_recognition.min_area + ): logger.debug(f"Invalid face box {face}") return