mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-20 13:54:36 +01:00
Fixes (#18117)
* face library i18n fixes * face library i18n fixes * add ability to use ctrl/cmd S to save in the config editor * Use datetime as ID * Update metrics inference speed to start with 0 ms * fix android formatted thumbnail * ensure role is comma separated and stripped correctly * improve face library deletion - add a confirmation dialog - add ability to select all / delete faces in collections * Implement lazy loading for video previews * Force GPU for large embedding model * GPU is required * settings i18n fixes * Don't delete train tab * webpush debugging logs * Fix incorrectly copying zones * copy path data * Ensure that cache dir exists for Frigate+ * face docs update * Add description to upload image step to clarify the image * Clean up --------- Co-authored-by: Nicolas Mowen <nickmowen213@gmail.com>
This commit is contained in:
@@ -25,7 +25,7 @@ from frigate.comms.event_metadata_updater import (
|
||||
from frigate.const import CLIPS_DIR
|
||||
from frigate.embeddings.onnx.lpr_embedding import LPR_EMBEDDING_SIZE
|
||||
from frigate.types import TrackedObjectUpdateTypesEnum
|
||||
from frigate.util.builtin import EventsPerSecond
|
||||
from frigate.util.builtin import EventsPerSecond, InferenceSpeed
|
||||
from frigate.util.image import area
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -36,8 +36,10 @@ WRITE_DEBUG_IMAGES = False
|
||||
class LicensePlateProcessingMixin:
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.plate_rec_speed = InferenceSpeed(self.metrics.alpr_speed)
|
||||
self.plates_rec_second = EventsPerSecond()
|
||||
self.plates_rec_second.start()
|
||||
self.plate_det_speed = InferenceSpeed(self.metrics.yolov9_lpr_speed)
|
||||
self.plates_det_second = EventsPerSecond()
|
||||
self.plates_det_second.start()
|
||||
self.event_metadata_publisher = EventMetadataPublisher()
|
||||
@@ -1157,22 +1159,6 @@ class LicensePlateProcessingMixin:
|
||||
# 5. Return True if previous plate scores higher
|
||||
return prev_score > curr_score
|
||||
|
||||
def __update_yolov9_metrics(self, duration: float) -> None:
|
||||
"""
|
||||
Update inference metrics.
|
||||
"""
|
||||
self.metrics.yolov9_lpr_speed.value = (
|
||||
self.metrics.yolov9_lpr_speed.value * 9 + duration
|
||||
) / 10
|
||||
|
||||
def __update_lpr_metrics(self, duration: float) -> None:
|
||||
"""
|
||||
Update inference metrics.
|
||||
"""
|
||||
self.metrics.alpr_speed.value = (
|
||||
self.metrics.alpr_speed.value * 9 + duration
|
||||
) / 10
|
||||
|
||||
def _generate_plate_event(self, camera: str, plate: str, plate_score: float) -> str:
|
||||
"""Generate a unique ID for a plate event based on camera and text."""
|
||||
now = datetime.datetime.now().timestamp()
|
||||
@@ -1228,7 +1214,7 @@ class LicensePlateProcessingMixin:
|
||||
f"{camera}: YOLOv9 LPD inference time: {(datetime.datetime.now().timestamp() - yolov9_start) * 1000:.2f} ms"
|
||||
)
|
||||
self.plates_det_second.update()
|
||||
self.__update_yolov9_metrics(
|
||||
self.plate_det_speed.update(
|
||||
datetime.datetime.now().timestamp() - yolov9_start
|
||||
)
|
||||
|
||||
@@ -1319,7 +1305,7 @@ class LicensePlateProcessingMixin:
|
||||
f"{camera}: YOLOv9 LPD inference time: {(datetime.datetime.now().timestamp() - yolov9_start) * 1000:.2f} ms"
|
||||
)
|
||||
self.plates_det_second.update()
|
||||
self.__update_yolov9_metrics(
|
||||
self.plate_det_speed.update(
|
||||
datetime.datetime.now().timestamp() - yolov9_start
|
||||
)
|
||||
|
||||
@@ -1433,7 +1419,7 @@ class LicensePlateProcessingMixin:
|
||||
camera, id, license_plate_frame
|
||||
)
|
||||
self.plates_rec_second.update()
|
||||
self.__update_lpr_metrics(datetime.datetime.now().timestamp() - start)
|
||||
self.plate_rec_speed.update(datetime.datetime.now().timestamp() - start)
|
||||
|
||||
if license_plates:
|
||||
for plate, confidence, text_area in zip(license_plates, confidences, areas):
|
||||
|
||||
@@ -5,9 +5,7 @@ import datetime
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import random
|
||||
import shutil
|
||||
import string
|
||||
from typing import Optional
|
||||
|
||||
import cv2
|
||||
@@ -27,7 +25,7 @@ from frigate.data_processing.common.face.model import (
|
||||
FaceRecognizer,
|
||||
)
|
||||
from frigate.types import TrackedObjectUpdateTypesEnum
|
||||
from frigate.util.builtin import EventsPerSecond
|
||||
from frigate.util.builtin import EventsPerSecond, InferenceSpeed
|
||||
from frigate.util.image import area
|
||||
|
||||
from ..types import DataProcessorMetrics
|
||||
@@ -58,6 +56,7 @@ class FaceRealTimeProcessor(RealTimeProcessorApi):
|
||||
self.person_face_history: dict[str, list[tuple[str, float, int]]] = {}
|
||||
self.recognizer: FaceRecognizer | None = None
|
||||
self.faces_per_second = EventsPerSecond()
|
||||
self.inference_speed = InferenceSpeed(self.metrics.face_rec_speed)
|
||||
|
||||
download_path = os.path.join(MODEL_CACHE_DIR, "facedet")
|
||||
self.model_files = {
|
||||
@@ -155,9 +154,7 @@ class FaceRealTimeProcessor(RealTimeProcessorApi):
|
||||
|
||||
def __update_metrics(self, duration: float) -> None:
|
||||
self.faces_per_second.update()
|
||||
self.metrics.face_rec_speed.value = (
|
||||
self.metrics.face_rec_speed.value * 9 + duration
|
||||
) / 10
|
||||
self.inference_speed.update(duration)
|
||||
|
||||
def process_frame(self, obj_data: dict[str, any], frame: np.ndarray):
|
||||
"""Look for faces in image."""
|
||||
@@ -343,11 +340,7 @@ class FaceRealTimeProcessor(RealTimeProcessorApi):
|
||||
|
||||
return {"success": True, "score": score, "face_name": sub_label}
|
||||
elif topic == EmbeddingsRequestEnum.register_face.value:
|
||||
rand_id = "".join(
|
||||
random.choices(string.ascii_lowercase + string.digits, k=6)
|
||||
)
|
||||
label = request_data["face_name"]
|
||||
id = f"{label}-{rand_id}"
|
||||
|
||||
if request_data.get("cropped"):
|
||||
thumbnail = request_data["image"]
|
||||
@@ -376,7 +369,9 @@ class FaceRealTimeProcessor(RealTimeProcessorApi):
|
||||
|
||||
# write face to library
|
||||
folder = os.path.join(FACE_DIR, label)
|
||||
file = os.path.join(folder, f"{id}.webp")
|
||||
file = os.path.join(
|
||||
folder, f"{label}_{datetime.datetime.now().timestamp()}.webp"
|
||||
)
|
||||
os.makedirs(folder, exist_ok=True)
|
||||
|
||||
# save face image
|
||||
|
||||
@@ -7,7 +7,9 @@ from multiprocessing.sharedctypes import Synchronized
|
||||
|
||||
class DataProcessorMetrics:
|
||||
image_embeddings_speed: Synchronized
|
||||
image_embeddings_eps: Synchronized
|
||||
text_embeddings_speed: Synchronized
|
||||
text_embeddings_eps: Synchronized
|
||||
face_rec_speed: Synchronized
|
||||
face_rec_fps: Synchronized
|
||||
alpr_speed: Synchronized
|
||||
@@ -16,15 +18,15 @@ class DataProcessorMetrics:
|
||||
yolov9_lpr_pps: Synchronized
|
||||
|
||||
def __init__(self):
|
||||
self.image_embeddings_speed = mp.Value("d", 0.01)
|
||||
self.image_embeddings_speed = mp.Value("d", 0.0)
|
||||
self.image_embeddings_eps = mp.Value("d", 0.0)
|
||||
self.text_embeddings_speed = mp.Value("d", 0.01)
|
||||
self.text_embeddings_speed = mp.Value("d", 0.0)
|
||||
self.text_embeddings_eps = mp.Value("d", 0.0)
|
||||
self.face_rec_speed = mp.Value("d", 0.01)
|
||||
self.face_rec_speed = mp.Value("d", 0.0)
|
||||
self.face_rec_fps = mp.Value("d", 0.0)
|
||||
self.alpr_speed = mp.Value("d", 0.01)
|
||||
self.alpr_speed = mp.Value("d", 0.0)
|
||||
self.alpr_pps = mp.Value("d", 0.0)
|
||||
self.yolov9_lpr_speed = mp.Value("d", 0.01)
|
||||
self.yolov9_lpr_speed = mp.Value("d", 0.0)
|
||||
self.yolov9_lpr_pps = mp.Value("d", 0.0)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user