mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-15 15:45:27 +03:00
improved length and character by character confidence
This commit is contained in:
parent
a96442ea13
commit
606eef1c58
@ -1,3 +1,4 @@
|
|||||||
|
import logging
|
||||||
import math
|
import math
|
||||||
from typing import List, Tuple
|
from typing import List, Tuple
|
||||||
|
|
||||||
@ -10,6 +11,8 @@ from frigate.comms.inter_process import InterProcessRequestor
|
|||||||
from frigate.config.semantic_search import LicensePlateRecognitionConfig
|
from frigate.config.semantic_search import LicensePlateRecognitionConfig
|
||||||
from frigate.embeddings.functions.onnx import GenericONNXEmbedding, ModelTypeEnum
|
from frigate.embeddings.functions.onnx import GenericONNXEmbedding, ModelTypeEnum
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class LicensePlateRecognition:
|
class LicensePlateRecognition:
|
||||||
def __init__(
|
def __init__(
|
||||||
@ -194,7 +197,7 @@ class LicensePlateRecognition:
|
|||||||
|
|
||||||
if results:
|
if results:
|
||||||
license_plates = [""] * len(rotated_images)
|
license_plates = [""] * len(rotated_images)
|
||||||
average_confidences = [0.0] * len(rotated_images)
|
average_confidences = [[0.0]] * len(rotated_images)
|
||||||
areas = [0] * len(rotated_images)
|
areas = [0] * len(rotated_images)
|
||||||
|
|
||||||
# map results back to original image order
|
# map results back to original image order
|
||||||
@ -204,7 +207,7 @@ class LicensePlateRecognition:
|
|||||||
height, width = rotated_images[original_idx].shape[:2]
|
height, width = rotated_images[original_idx].shape[:2]
|
||||||
area = height * width
|
area = height * width
|
||||||
|
|
||||||
average_confidence = sum(conf) / len(conf) if conf else 0
|
average_confidence = conf
|
||||||
|
|
||||||
# TODO: remove
|
# TODO: remove
|
||||||
if False:
|
if False:
|
||||||
|
|||||||
@ -78,7 +78,7 @@ class EmbeddingMaintainer(threading.Thread):
|
|||||||
self.requires_license_plate_detection = (
|
self.requires_license_plate_detection = (
|
||||||
"license_plate" not in self.config.model.all_attributes
|
"license_plate" not in self.config.model.all_attributes
|
||||||
)
|
)
|
||||||
self.detected_license_plates: dict[str, float] = {}
|
self.detected_license_plates: dict[str, dict[str, any]] = {}
|
||||||
self.license_plate_recognition = LicensePlateRecognition(
|
self.license_plate_recognition = LicensePlateRecognition(
|
||||||
self.lpr_config, self.requestor
|
self.lpr_config, self.requestor
|
||||||
)
|
)
|
||||||
@ -556,27 +556,59 @@ class EmbeddingMaintainer(threading.Thread):
|
|||||||
if license_plates:
|
if license_plates:
|
||||||
for plate, confidence, text_area in zip(license_plates, confidences, areas):
|
for plate, confidence, text_area in zip(license_plates, confidences, areas):
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"Detected text: {plate} (average confidence: {confidence:.2f}, area: {text_area} pixels)"
|
f"Detected text: {plate} (average confidence: {(sum(confidence) / len(confidence)):.2f}, area: {text_area} pixels)"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
# no plates found
|
# no plates found
|
||||||
logger.debug("No text detected")
|
logger.debug("No text detected")
|
||||||
return
|
return
|
||||||
|
|
||||||
if confidences[0] < self.lpr_config.threshold or (
|
top_plate, top_char_confidences = license_plates[0], confidences[0]
|
||||||
id in self.detected_license_plates
|
avg_confidence = sum(top_char_confidences) / len(top_char_confidences)
|
||||||
and confidences[0] <= self.detected_license_plates[id]
|
|
||||||
):
|
# Check if we have a previously detected plate for this ID
|
||||||
|
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_avg_confidence = sum(prev_char_confidences) / len(
|
||||||
|
prev_char_confidences
|
||||||
|
)
|
||||||
|
|
||||||
|
# Define conditions for keeping the previous plate
|
||||||
|
shorter_than_previous = len(top_plate) < len(prev_plate)
|
||||||
|
lower_avg_confidence = avg_confidence <= prev_avg_confidence
|
||||||
|
|
||||||
|
# Compare character-by-character confidence where possible
|
||||||
|
min_length = min(len(top_plate), len(prev_plate))
|
||||||
|
char_confidence_comparison = sum(
|
||||||
|
1
|
||||||
|
for i in range(min_length)
|
||||||
|
if top_char_confidences[i] <= prev_char_confidences[i]
|
||||||
|
)
|
||||||
|
worse_char_confidences = char_confidence_comparison >= min_length / 2
|
||||||
|
|
||||||
|
if shorter_than_previous or (
|
||||||
|
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}"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Check against minimum confidence threshold
|
||||||
|
if avg_confidence < self.lpr_config.threshold:
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"Recognized license plate top score {confidences[0]} is less than threshold ({self.config.lpr.threshold}) / previous license plate score ({self.detected_license_plates.get(id)})."
|
f"Average confidence {avg_confidence} is less than threshold ({self.lpr_config.threshold})"
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Determine subLabel based on known plates
|
# Determine subLabel based on known plates
|
||||||
# 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 = license_plates[0]
|
sub_label = top_plate
|
||||||
for label, plates in self.lpr_config.known_plates.items():
|
for label, plates in self.lpr_config.known_plates.items():
|
||||||
if license_plates[0] in plates:
|
if top_plate in plates:
|
||||||
sub_label = label
|
sub_label = label
|
||||||
break
|
break
|
||||||
|
|
||||||
@ -586,12 +618,15 @@ class EmbeddingMaintainer(threading.Thread):
|
|||||||
json={
|
json={
|
||||||
"camera": obj_data.get("camera"),
|
"camera": obj_data.get("camera"),
|
||||||
"subLabel": sub_label,
|
"subLabel": sub_label,
|
||||||
"subLabelScore": confidences[0],
|
"subLabelScore": avg_confidence,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
if resp.status_code == 200:
|
if resp.status_code == 200:
|
||||||
self.detected_license_plates[id] = confidences[0]
|
self.detected_license_plates[id] = {
|
||||||
|
"plate": top_plate,
|
||||||
|
"char_confidences": top_char_confidences,
|
||||||
|
}
|
||||||
|
|
||||||
def _create_thumbnail(self, yuv_frame, box, height=500) -> Optional[bytes]:
|
def _create_thumbnail(self, yuv_frame, box, height=500) -> Optional[bytes]:
|
||||||
"""Return jpg thumbnail of a region of the frame."""
|
"""Return jpg thumbnail of a region of the frame."""
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user