diff --git a/docs/docs/configuration/license_plate_recognition.md b/docs/docs/configuration/license_plate_recognition.md index b2fbb6214..a2b976726 100644 --- a/docs/docs/configuration/license_plate_recognition.md +++ b/docs/docs/configuration/license_plate_recognition.md @@ -26,7 +26,7 @@ lpr: Several options are available to fine-tune the LPR feature. For example, you can adjust the `min_area` setting, which defines the minimum size in pixels a license plate must be before LPR runs. The default is 500 pixels. -Additionally, you can define `known_plates`, allowing Frigate to label tracked vehicles with custom sub_labels when a recognized plate is detected. This information is then accessible in the UI, filters, and notifications. +Additionally, you can define `known_plates` as strings or regular expressions, allowing Frigate to label tracked vehicles with custom sub_labels when a recognized plate is detected. This information is then accessible in the UI, filters, and notifications. ```yaml lpr: @@ -37,12 +37,9 @@ lpr: - "ABC-1234" - "ABC-I234" Johnny: - - "JHN-1234" - - "JMN-1234" - - "JHN-I234" + - "J*N-*234" # Using wildcards for H/M and 1/I Sally: - - "SLL-1234" - - "5LL-1234" + - "[S5]LL-1234" # Matches SLL-1234 and 5LL-1234 ``` In this example, "Wife's Car" will appear as the label for any vehicle matching the plate "ABC-1234." The model might occasionally interpret the digit 1 as a capital I (e.g., "ABC-I234"), so both variations are listed. Similarly, multiple possible variations are specified for Johnny and Sally. diff --git a/frigate/embeddings/embeddings.py b/frigate/embeddings/embeddings.py index 23b8aa7ee..255b72cb2 100644 --- a/frigate/embeddings/embeddings.py +++ b/frigate/embeddings/embeddings.py @@ -154,7 +154,7 @@ class Embeddings: "detection.onnx": "https://github.com/hawkeye217/paddleocr-onnx/raw/refs/heads/master/models/detection.onnx" }, model_size="large", - model_type=ModelTypeEnum.alpr_detect, + model_type=ModelTypeEnum.lpr_detect, requestor=self.requestor, device="CPU", ) @@ -166,7 +166,7 @@ class Embeddings: "classification.onnx": "https://github.com/hawkeye217/paddleocr-onnx/raw/refs/heads/master/models/classification.onnx" }, model_size="large", - model_type=ModelTypeEnum.alpr_classify, + model_type=ModelTypeEnum.lpr_classify, requestor=self.requestor, device="CPU", ) @@ -178,7 +178,7 @@ class Embeddings: "recognition.onnx": "https://github.com/hawkeye217/paddleocr-onnx/raw/refs/heads/master/models/recognition.onnx" }, model_size="large", - model_type=ModelTypeEnum.alpr_recognize, + model_type=ModelTypeEnum.lpr_recognize, requestor=self.requestor, device="CPU", ) diff --git a/frigate/embeddings/functions/onnx.py b/frigate/embeddings/functions/onnx.py index 035dc1cc2..7375cf40e 100644 --- a/frigate/embeddings/functions/onnx.py +++ b/frigate/embeddings/functions/onnx.py @@ -38,9 +38,9 @@ class ModelTypeEnum(str, Enum): face = "face" vision = "vision" text = "text" - alpr_detect = "alpr_detect" - alpr_classify = "alpr_classify" - alpr_recognize = "alpr_recognize" + lpr_detect = "lpr_detect" + lpr_classify = "lpr_classify" + lpr_recognize = "lpr_recognize" class GenericONNXEmbedding: @@ -142,11 +142,11 @@ class GenericONNXEmbedding: self.feature_extractor = self._load_feature_extractor() elif self.model_type == ModelTypeEnum.face: self.feature_extractor = [] - elif self.model_type == ModelTypeEnum.alpr_detect: + elif self.model_type == ModelTypeEnum.lpr_detect: self.feature_extractor = [] - elif self.model_type == ModelTypeEnum.alpr_classify: + elif self.model_type == ModelTypeEnum.lpr_classify: self.feature_extractor = [] - elif self.model_type == ModelTypeEnum.alpr_recognize: + elif self.model_type == ModelTypeEnum.lpr_recognize: self.feature_extractor = [] self.runner = ONNXModelRunner( @@ -223,17 +223,17 @@ class GenericONNXEmbedding: frame = np.expand_dims(frame, axis=0) return [{"input_2": frame}] - elif self.model_type == ModelTypeEnum.alpr_detect: + elif self.model_type == ModelTypeEnum.lpr_detect: preprocessed = [] for x in raw_inputs: preprocessed.append(x) return [{"x": preprocessed[0]}] - elif self.model_type == ModelTypeEnum.alpr_classify: + elif self.model_type == ModelTypeEnum.lpr_classify: processed = [] for img in raw_inputs: processed.append({"x": img}) return processed - elif self.model_type == ModelTypeEnum.alpr_recognize: + elif self.model_type == ModelTypeEnum.lpr_recognize: processed = [] for img in raw_inputs: processed.append({"x": img}) diff --git a/frigate/embeddings/alpr/alpr.py b/frigate/embeddings/lpr/lpr.py similarity index 100% rename from frigate/embeddings/alpr/alpr.py rename to frigate/embeddings/lpr/lpr.py diff --git a/frigate/embeddings/maintainer.py b/frigate/embeddings/maintainer.py index 325a2e8dd..f5fb7cc7c 100644 --- a/frigate/embeddings/maintainer.py +++ b/frigate/embeddings/maintainer.py @@ -3,6 +3,7 @@ import base64 import logging import os +import re import threading from multiprocessing.synchronize import Event as MpEvent from typing import Optional @@ -22,7 +23,7 @@ from frigate.comms.events_updater import EventEndSubscriber, EventUpdateSubscrib from frigate.comms.inter_process import InterProcessRequestor from frigate.config import FrigateConfig from frigate.const import CLIPS_DIR, FRIGATE_LOCALHOST, UPDATE_EVENT_DESCRIPTION -from frigate.embeddings.alpr.alpr import LicensePlateRecognition +from frigate.embeddings.lpr.lpr import LicensePlateRecognition from frigate.events.types import EventTypeEnum from frigate.genai import get_genai_client from frigate.models import Event @@ -651,13 +652,16 @@ class EmbeddingMaintainer(threading.Thread): ) return - # Determine subLabel based on known plates + # Determine subLabel based on known plates, use regex matching # Default to the detected plate, use label name if there's a match - sub_label = top_plate - for label, plates in self.lpr_config.known_plates.items(): - if top_plate in plates: - sub_label = label - break + sub_label = next( + ( + label + for label, plates in self.lpr_config.known_plates.items() + if any(re.match(f"^{plate}$", top_plate) for plate in plates) + ), + top_plate, + ) # Send the result to the API resp = requests.post(