mirror of
				https://github.com/blakeblackshear/frigate.git
				synced 2025-10-27 10:52:11 +01:00 
			
		
		
		
	Use regular expressions for plate matching (#14727)
This commit is contained in:
		
							parent
							
								
									a0c35101fb
								
							
						
					
					
						commit
						8bb037f82e
					
				@ -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.
 | 
			
		||||
 | 
			
		||||
@ -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",
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
@ -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})
 | 
			
		||||
 | 
			
		||||
@ -3,6 +3,7 @@
 | 
			
		||||
import base64
 | 
			
		||||
import logging
 | 
			
		||||
import os
 | 
			
		||||
import re
 | 
			
		||||
import threading
 | 
			
		||||
from multiprocessing.synchronize import Event as MpEvent
 | 
			
		||||
from pathlib import Path
 | 
			
		||||
@ -23,7 +24,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
 | 
			
		||||
@ -683,13 +684,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(
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user