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.
 | 
					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.
 | 
				
			||||||
 | 
				
			|||||||
@ -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",
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
				
			|||||||
@ -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})
 | 
				
			||||||
 | 
				
			|||||||
@ -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 pathlib import Path
 | 
					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.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
 | 
				
			||||||
@ -683,13 +684,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(
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user