From 900f148aa0d8da3f58198ef337bc4c964e78ef32 Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Wed, 26 Mar 2025 09:13:04 -0600 Subject: [PATCH] Rewrite build model task to be asynchronous so it doesn't block the pipeline --- frigate/data_processing/common/face/model.py | 77 +++++++++++++------- 1 file changed, 51 insertions(+), 26 deletions(-) diff --git a/frigate/data_processing/common/face/model.py b/frigate/data_processing/common/face/model.py index 20db5173e..bb0c67324 100644 --- a/frigate/data_processing/common/face/model.py +++ b/frigate/data_processing/common/face/model.py @@ -1,5 +1,7 @@ import logging import os +import queue +import threading from abc import ABC, abstractmethod import cv2 @@ -206,46 +208,69 @@ class ArcFaceRecognizer(FaceRecognizer): super().__init__(config) self.mean_embs: dict[int, np.ndarray] = {} self.face_embedder: ArcfaceEmbedding = ArcfaceEmbedding() + self.model_builder_queue: queue.Queue | None = None def clear(self) -> None: self.mean_embs = {} + def run_build_task(self) -> None: + self.model_builder_queue = queue.Queue() + + def build_model(): + face_embeddings_map: dict[str, list[np.ndarray]] = {} + idx = 0 + + dir = "/media/frigate/clips/faces" + for name in os.listdir(dir): + if name == "train": + continue + + face_folder = os.path.join(dir, name) + + if not os.path.isdir(face_folder): + continue + + face_embeddings_map[name] = [] + for image in os.listdir(face_folder): + img = cv2.imread(os.path.join(face_folder, image)) + + if img is None: + continue + + img = self.align_face(img, img.shape[1], img.shape[0]) + emb = self.face_embedder([img])[0].squeeze() + face_embeddings_map[name].append(emb) + + idx += 1 + + self.model_builder_queue.put(face_embeddings_map) + + thread = threading.Thread(target=build_model) + thread.start() + def build(self): if not self.landmark_detector: self.init_landmark_detector() return None - face_embeddings_map: dict[str, list[np.ndarray]] = {} - idx = 0 - - dir = "/media/frigate/clips/faces" - for name in os.listdir(dir): - if name == "train": - continue - - face_folder = os.path.join(dir, name) - - if not os.path.isdir(face_folder): - continue - - face_embeddings_map[name] = [] - for image in os.listdir(face_folder): - img = cv2.imread(os.path.join(face_folder, image)) - - if img is None: - continue - - img = self.align_face(img, img.shape[1], img.shape[0]) - emb = self.face_embedder([img])[0].squeeze() - face_embeddings_map[name].append(emb) - - idx += 1 + if self.model_builder_queue is not None: + try: + face_embeddings_map: dict[str, list[np.ndarray]] = ( + self.model_builder_queue.get(timeout=0.1) + ) + self.model_builder_queue = None + except queue.Empty: + return + else: + self.run_build_task() + return if not face_embeddings_map: return for name, embs in face_embeddings_map.items(): - self.mean_embs[name] = stats.trim_mean(embs, 0.15) + if embs: + self.mean_embs[name] = stats.trim_mean(embs, 0.15) logger.debug("Finished building ArcFace model")