Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion viseron/components/compreface/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""CompreFace face recognition."""

import logging
from typing import Any

Expand Down Expand Up @@ -134,7 +135,7 @@ def setup_domains(vis: Viseron, config: dict[str, Any]) -> None:
if not config.get(CONFIG_FACE_RECOGNITION, None):
return

for camera_identifier in config[CONFIG_FACE_RECOGNITION][CONFIG_CAMERAS].keys():
for camera_identifier in config[CONFIG_FACE_RECOGNITION][CONFIG_CAMERAS]:
setup_domain(
vis,
COMPONENT,
Expand All @@ -148,3 +149,10 @@ def setup_domains(vis: Viseron, config: dict[str, Any]) -> None:
)
],
)


def unload(vis: Viseron) -> bool:
"""Unload the compreface component."""
if COMPONENT in vis.data:
del vis.data[COMPONENT]
return True
34 changes: 19 additions & 15 deletions viseron/components/compreface/face_recognition.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
"""CompreFace face recognition."""

from __future__ import annotations

import logging
import os
from typing import TYPE_CHECKING, Any

import cv2
import numpy as np
from compreface import CompreFace
from compreface.service.recognition_service import RecognitionService

from viseron.domains.face_recognition import AbstractFaceRecognition
from viseron.domains.face_recognition.binary_sensor import FaceDetectionBinarySensor
from viseron.domains.face_recognition.const import CONFIG_FACE_RECOGNITION_PATH
from viseron.domains.face_recognition.const import CONFIG_FACE_RECOGNITION_PATH, DOMAIN
from viseron.helpers import calculate_absolute_coords, get_image_files_in_folder

from .const import (
Expand All @@ -32,14 +31,17 @@
)

if TYPE_CHECKING:
import numpy as np
from compreface.service.recognition_service import RecognitionService

from viseron import Viseron
from viseron.domains.object_detector.detected_object import DetectedObject
from viseron.domains.post_processor import PostProcessorFrame

LOGGER = logging.getLogger(__name__)


def setup(vis: Viseron, config, identifier) -> bool:
def setup(vis: Viseron, config: dict[str, Any], identifier: str) -> bool:
"""Set up the CompreFace face_recognition domain."""
FaceRecognition(vis, config, identifier)

Expand All @@ -49,13 +51,15 @@ def setup(vis: Viseron, config, identifier) -> bool:
class FaceRecognition(AbstractFaceRecognition):
"""CompreFace face recognition processor."""

def __init__(self, vis: Viseron, config, camera_identifier) -> None:
def __init__(
self, vis: Viseron, config: dict[str, Any], camera_identifier: str
) -> None:
super().__init__(
vis,
COMPONENT,
config[CONFIG_FACE_RECOGNITION],
camera_identifier,
not config[CONFIG_FACE_RECOGNITION][CONFIG_USE_SUBJECTS],
generate_entities=not config[CONFIG_FACE_RECOGNITION][CONFIG_USE_SUBJECTS],
)

if COMPONENT not in self._vis.data:
Expand Down Expand Up @@ -93,11 +97,13 @@ def update_subject_entities(self) -> list:
added_subjects.append(f"{self._camera.identifier}_{subject}")
self._vis.add_entity(
COMPONENT,
FaceDetectionBinarySensor(self._vis, self._camera, subject),
binary_sensor,
DOMAIN,
self._camera.identifier,
)
return added_subjects

def preprocess(self, frame) -> np.ndarray:
def preprocess(self, frame: np.ndarray) -> np.ndarray:
"""Preprocess frame."""
return frame

Expand All @@ -120,8 +126,8 @@ def face_recognition(
detections = self.recognition_service.recognize(
cv2.imencode(".jpg", cropped_frame)[1].tobytes(),
)
except Exception as error: # pylint: disable=broad-except
self._logger.error("Error calling compreface: %s", error, exc_info=True)
except Exception: # pylint: disable=broad-except
self._logger.exception("Error calling compreface")
return

self._logger.debug(f"CompreFace response: {detections}")
Expand Down Expand Up @@ -161,7 +167,7 @@ def face_recognition(
class CompreFaceService:
"""CompreFace service."""

def __init__(self, config: dict[str, Any]):
def __init__(self, config: dict[str, Any]) -> None:
options = {
CONFIG_LIMIT: config[CONFIG_FACE_RECOGNITION][CONFIG_LIMIT],
CONFIG_DET_PROB_THRESHOLD: config[CONFIG_FACE_RECOGNITION][
Expand Down Expand Up @@ -200,7 +206,7 @@ def recognition_service(self) -> RecognitionService:
class CompreFaceTrain:
"""Train CompreFace to recognize faces."""

def __init__(self, vis: Viseron, config) -> None:
def __init__(self, vis: Viseron, config: dict[str, Any]) -> None:
self._config = config
self._vis = vis

Expand Down Expand Up @@ -264,7 +270,5 @@ def train(self) -> None:
LOGGER.debug(f"CompreFace response: {result}")
if "message" in result:
LOGGER.warning(
"Image {} not suitable for training: {}".format(
img_path, result
)
f"Image {img_path} not suitable for training: {result}"
)
9 changes: 5 additions & 4 deletions viseron/domains/face_recognition/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@

import voluptuous as vol

from viseron.domains.camera.shared_frames import SharedFrame
from viseron.domains.object_detector.detected_object import DetectedObject
from viseron.domains.post_processor import (
BASE_CONFIG_SCHEMA,
AbstractPostProcessor,
Expand Down Expand Up @@ -47,6 +45,8 @@

if TYPE_CHECKING:
from viseron import Viseron
from viseron.domains.camera.shared_frames import SharedFrame
from viseron.domains.object_detector.detected_object import DetectedObject

BASE_CONFIG_SCHEMA = BASE_CONFIG_SCHEMA.extend(
{
Expand Down Expand Up @@ -122,6 +122,7 @@ def __init__(
component: str,
config: dict,
camera_identifier: str,
*,
generate_entities: bool = True,
) -> None:
super().__init__(vis, config, camera_identifier)
Expand All @@ -137,7 +138,7 @@ def __init__(
camera_identifier,
)

def __post_init__(self, *args, **kwargs):
def __post_init__(self, *args, **kwargs) -> None:
"""Post init hook."""
self._vis.register_domain(DOMAIN, self._camera_identifier, self)

Expand Down Expand Up @@ -228,7 +229,7 @@ def unknown_face_found(
if self._config[CONFIG_SAVE_UNKNOWN_FACES]:
self._save_face(face_dict, coordinates, shared_frame)

def expire_face(self, face) -> None:
def expire_face(self, face: str) -> None:
"""Expire no longer found face."""
self._logger.debug(f"Expiring face {face}")
self._vis.dispatch_event(
Expand Down
3 changes: 2 additions & 1 deletion viseron/domains/face_recognition/binary_sensor.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Binary sensor that represents face recognition."""

from __future__ import annotations

from typing import TYPE_CHECKING
Expand Down Expand Up @@ -50,7 +51,7 @@ def _is_on(self):
return self._detected

@property
def extra_attributes(self):
def extra_attributes(self) -> dict:
"""Return entity attributes."""
if self._face:
return {
Expand Down
Loading