Use regular expressions for plate matching (#14727)

This commit is contained in:
Josh Hawkins 2024-11-01 18:43:21 -05:00 committed by Nicolas Mowen
parent 6d6a07ff2c
commit 9d5d8ddbb2
5 changed files with 26 additions and 25 deletions

View File

@ -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. 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 ```yaml
lpr: lpr:
@ -37,12 +37,9 @@ lpr:
- "ABC-1234" - "ABC-1234"
- "ABC-I234" - "ABC-I234"
Johnny: Johnny:
- "JHN-1234" - "J*N-*234" # Using wildcards for H/M and 1/I
- "JMN-1234"
- "JHN-I234"
Sally: Sally:
- "SLL-1234" - "[S5]LL-1234" # Matches SLL-1234 and 5LL-1234
- "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. 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.

View File

@ -154,7 +154,7 @@ class Embeddings:
"detection.onnx": "https://github.com/hawkeye217/paddleocr-onnx/raw/refs/heads/master/models/detection.onnx" "detection.onnx": "https://github.com/hawkeye217/paddleocr-onnx/raw/refs/heads/master/models/detection.onnx"
}, },
model_size="large", model_size="large",
model_type=ModelTypeEnum.alpr_detect, model_type=ModelTypeEnum.lpr_detect,
requestor=self.requestor, requestor=self.requestor,
device="CPU", device="CPU",
) )
@ -166,7 +166,7 @@ class Embeddings:
"classification.onnx": "https://github.com/hawkeye217/paddleocr-onnx/raw/refs/heads/master/models/classification.onnx" "classification.onnx": "https://github.com/hawkeye217/paddleocr-onnx/raw/refs/heads/master/models/classification.onnx"
}, },
model_size="large", model_size="large",
model_type=ModelTypeEnum.alpr_classify, model_type=ModelTypeEnum.lpr_classify,
requestor=self.requestor, requestor=self.requestor,
device="CPU", device="CPU",
) )
@ -178,7 +178,7 @@ class Embeddings:
"recognition.onnx": "https://github.com/hawkeye217/paddleocr-onnx/raw/refs/heads/master/models/recognition.onnx" "recognition.onnx": "https://github.com/hawkeye217/paddleocr-onnx/raw/refs/heads/master/models/recognition.onnx"
}, },
model_size="large", model_size="large",
model_type=ModelTypeEnum.alpr_recognize, model_type=ModelTypeEnum.lpr_recognize,
requestor=self.requestor, requestor=self.requestor,
device="CPU", device="CPU",
) )

View File

@ -38,9 +38,9 @@ class ModelTypeEnum(str, Enum):
face = "face" face = "face"
vision = "vision" vision = "vision"
text = "text" text = "text"
alpr_detect = "alpr_detect" lpr_detect = "lpr_detect"
alpr_classify = "alpr_classify" lpr_classify = "lpr_classify"
alpr_recognize = "alpr_recognize" lpr_recognize = "lpr_recognize"
class GenericONNXEmbedding: class GenericONNXEmbedding:
@ -142,11 +142,11 @@ class GenericONNXEmbedding:
self.feature_extractor = self._load_feature_extractor() self.feature_extractor = self._load_feature_extractor()
elif self.model_type == ModelTypeEnum.face: elif self.model_type == ModelTypeEnum.face:
self.feature_extractor = [] self.feature_extractor = []
elif self.model_type == ModelTypeEnum.alpr_detect: elif self.model_type == ModelTypeEnum.lpr_detect:
self.feature_extractor = [] self.feature_extractor = []
elif self.model_type == ModelTypeEnum.alpr_classify: elif self.model_type == ModelTypeEnum.lpr_classify:
self.feature_extractor = [] self.feature_extractor = []
elif self.model_type == ModelTypeEnum.alpr_recognize: elif self.model_type == ModelTypeEnum.lpr_recognize:
self.feature_extractor = [] self.feature_extractor = []
self.runner = ONNXModelRunner( self.runner = ONNXModelRunner(
@ -223,17 +223,17 @@ class GenericONNXEmbedding:
frame = np.expand_dims(frame, axis=0) frame = np.expand_dims(frame, axis=0)
return [{"input_2": frame}] return [{"input_2": frame}]
elif self.model_type == ModelTypeEnum.alpr_detect: elif self.model_type == ModelTypeEnum.lpr_detect:
preprocessed = [] preprocessed = []
for x in raw_inputs: for x in raw_inputs:
preprocessed.append(x) preprocessed.append(x)
return [{"x": preprocessed[0]}] return [{"x": preprocessed[0]}]
elif self.model_type == ModelTypeEnum.alpr_classify: elif self.model_type == ModelTypeEnum.lpr_classify:
processed = [] processed = []
for img in raw_inputs: for img in raw_inputs:
processed.append({"x": img}) processed.append({"x": img})
return processed return processed
elif self.model_type == ModelTypeEnum.alpr_recognize: elif self.model_type == ModelTypeEnum.lpr_recognize:
processed = [] processed = []
for img in raw_inputs: for img in raw_inputs:
processed.append({"x": img}) processed.append({"x": img})

View File

@ -3,6 +3,7 @@
import base64 import base64
import logging import logging
import os import os
import re
import threading import threading
from multiprocessing.synchronize import Event as MpEvent from multiprocessing.synchronize import Event as MpEvent
from typing import Optional 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.comms.inter_process import InterProcessRequestor
from frigate.config import FrigateConfig from frigate.config import FrigateConfig
from frigate.const import CLIPS_DIR, FRIGATE_LOCALHOST, UPDATE_EVENT_DESCRIPTION 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.events.types import EventTypeEnum
from frigate.genai import get_genai_client from frigate.genai import get_genai_client
from frigate.models import Event from frigate.models import Event
@ -651,13 +652,16 @@ class EmbeddingMaintainer(threading.Thread):
) )
return 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 # Default to the detected plate, use label name if there's a match
sub_label = top_plate sub_label = next(
for label, plates in self.lpr_config.known_plates.items(): (
if top_plate in plates: label
sub_label = label for label, plates in self.lpr_config.known_plates.items()
break if any(re.match(f"^{plate}$", top_plate) for plate in plates)
),
top_plate,
)
# Send the result to the API # Send the result to the API
resp = requests.post( resp = requests.post(