From 6f24f5a595e61541d129f114eb30b244c6563d82 Mon Sep 17 00:00:00 2001 From: Jozef Huscava <48366209+JoeApo108@users.noreply.github.com> Date: Tue, 14 Jul 2026 00:45:29 +0200 Subject: [PATCH] Convert face crops to RGB before embedding (#23712) * Convert face crops to RGB before embedding Face crops flow through the cv2 pipeline as BGR arrays, but _process_image passes ndarrays to PIL without any channel conversion, so the FaceNet and ArcFace embedders receive BGR input while both models expect RGB. The error is symmetric between enrollment and recognition so it partially cancels, but it still costs accuracy. * Move BGR to RGB conversion into a shared helper Deduplicate the channel swap from both _preprocess_inputs methods into a BaseEmbedding._bgr_to_rgb static helper, as suggested in review. --- frigate/embeddings/onnx/base_embedding.py | 6 ++++++ frigate/embeddings/onnx/face_embedding.py | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/frigate/embeddings/onnx/base_embedding.py b/frigate/embeddings/onnx/base_embedding.py index c0bd58475b..5b514d1f60 100644 --- a/frigate/embeddings/onnx/base_embedding.py +++ b/frigate/embeddings/onnx/base_embedding.py @@ -57,6 +57,12 @@ class BaseEmbedding(ABC): def _preprocess_inputs(self, raw_inputs: Any) -> Any: pass + @staticmethod + def _bgr_to_rgb(frame: Any) -> Any: + if isinstance(frame, np.ndarray) and frame.ndim == 3: + return np.ascontiguousarray(frame[:, :, ::-1]) + return frame + def _process_image(self, image, output: str = "RGB") -> Image.Image: if isinstance(image, str): if image.startswith("http"): diff --git a/frigate/embeddings/onnx/face_embedding.py b/frigate/embeddings/onnx/face_embedding.py index 75dfedc94d..31d2bd2066 100644 --- a/frigate/embeddings/onnx/face_embedding.py +++ b/frigate/embeddings/onnx/face_embedding.py @@ -73,7 +73,7 @@ class FaceNetEmbedding(BaseEmbedding): self.tensor_output_details = self.runner.get_output_details() def _preprocess_inputs(self, raw_inputs): - pil = self._process_image(raw_inputs[0]) + pil = self._process_image(self._bgr_to_rgb(raw_inputs[0])) # handle images larger than input size width, height = pil.size @@ -159,7 +159,7 @@ class ArcfaceEmbedding(BaseEmbedding): ) def _preprocess_inputs(self, raw_inputs): - pil = self._process_image(raw_inputs[0]) + pil = self._process_image(self._bgr_to_rgb(raw_inputs[0])) # handle images larger than input size width, height = pil.size