From ce3496868f8e2f88d6e0a202d2045f50d5a90c91 Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Mon, 28 Oct 2024 11:49:12 -0500 Subject: [PATCH] LPR improvements (#14641) --- frigate/embeddings/alpr/alpr.py | 19 ++++++++++++++++++- frigate/embeddings/maintainer.py | 15 +++++++++++---- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/frigate/embeddings/alpr/alpr.py b/frigate/embeddings/alpr/alpr.py index b91a50e3a..16eba9989 100644 --- a/frigate/embeddings/alpr/alpr.py +++ b/frigate/embeddings/alpr/alpr.py @@ -13,6 +13,8 @@ from frigate.embeddings.embeddings import Embeddings logger = logging.getLogger(__name__) +MIN_PLATE_LENGTH = 3 + class LicensePlateRecognition: def __init__( @@ -197,7 +199,22 @@ class LicensePlateRecognition: average_confidences[original_idx] = average_confidence areas[original_idx] = area - return license_plates, average_confidences, areas + # Filter out plates that have a length of less than 3 characters + # Sort by area, then by plate length, then by confidence all desc + sorted_data = sorted( + [ + (plate, conf, area) + for plate, conf, area in zip( + license_plates, average_confidences, areas + ) + if len(plate) >= MIN_PLATE_LENGTH + ], + key=lambda x: (x[2], len(x[0]), x[1]), + reverse=True, + ) + + if sorted_data: + return map(list, zip(*sorted_data)) return [], [], [] diff --git a/frigate/embeddings/maintainer.py b/frigate/embeddings/maintainer.py index 2084e6b7a..325a2e8dd 100644 --- a/frigate/embeddings/maintainer.py +++ b/frigate/embeddings/maintainer.py @@ -598,7 +598,11 @@ class EmbeddingMaintainer(threading.Thread): logger.debug("No text detected") return - top_plate, top_char_confidences = license_plates[0], confidences[0] + top_plate, top_char_confidences, top_area = ( + license_plates[0], + confidences[0], + areas[0], + ) avg_confidence = ( (sum(top_char_confidences) / len(top_char_confidences)) if top_char_confidences @@ -609,6 +613,7 @@ class EmbeddingMaintainer(threading.Thread): if id in self.detected_license_plates: prev_plate = self.detected_license_plates[id]["plate"] prev_char_confidences = self.detected_license_plates[id]["char_confidences"] + prev_area = self.detected_license_plates[id]["area"] prev_avg_confidence = ( (sum(prev_char_confidences) / len(prev_char_confidences)) if prev_char_confidences @@ -618,6 +623,7 @@ class EmbeddingMaintainer(threading.Thread): # Define conditions for keeping the previous plate shorter_than_previous = len(top_plate) < len(prev_plate) lower_avg_confidence = avg_confidence <= prev_avg_confidence + smaller_area = top_area < prev_area # Compare character-by-character confidence where possible min_length = min(len(top_plate), len(prev_plate)) @@ -628,13 +634,13 @@ class EmbeddingMaintainer(threading.Thread): ) worse_char_confidences = char_confidence_comparison >= min_length / 2 - if shorter_than_previous or ( + if (shorter_than_previous or smaller_area) and ( lower_avg_confidence and worse_char_confidences ): logger.debug( f"Keeping previous plate. New plate stats: " - f"length={len(top_plate)}, avg_conf={avg_confidence:.2f} " - f"vs Previous: length={len(prev_plate)}, avg_conf={prev_avg_confidence:.2f}" + f"length={len(top_plate)}, avg_conf={avg_confidence:.2f}, area={top_area} " + f"vs Previous: length={len(prev_plate)}, avg_conf={prev_avg_confidence:.2f}, area={prev_area}" ) return @@ -667,6 +673,7 @@ class EmbeddingMaintainer(threading.Thread): self.detected_license_plates[id] = { "plate": top_plate, "char_confidences": top_char_confidences, + "area": top_area, } def _create_thumbnail(self, yuv_frame, box, height=500) -> Optional[bytes]: