Skip to content

Commit

Permalink
Merge pull request #761 from roflcoopter/feature/face-rec-snapshots
Browse files Browse the repository at this point in the history
Face recognition snapshots
  • Loading branch information
roflcoopter authored May 28, 2024
2 parents 8a85f89 + 54c2b2f commit b033778
Show file tree
Hide file tree
Showing 21 changed files with 366 additions and 141 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -418,16 +418,20 @@
{
"type": "boolean",
"name": "save_unknown_faces",
"description": "If true, any unrecognized face will be saved to the folder specified in <code>unknown_faces_path</code>. You can then move this image to the folder of the correct person to improve accuracy.",
"description": "If set to <code>true</code>, any unrecognized faces will be stored in the database, as well as having a snapshot saved. You can then move this image to the folder of the correct person to improve accuracy.",
"optional": true,
"default": false
},
{
"type": "string",
"name": "unknown_faces_path",
"name": {
"type": "deprecated",
"name": "unknown_faces_path",
"value": "Config option 'unknown_faces_path' is deprecated and will be removed in a future version."
},
"description": "Path to folder where unknown faces will be stored.",
"optional": true,
"default": "/config/face_recognition/faces/unknown"
"deprecated": true,
"default": null
},
{
"type": "float",
Expand All @@ -437,6 +441,13 @@
"optional": true,
"default": 5
},
{
"type": "boolean",
"name": "save_faces",
"description": "If set to <code>true</code>, detected faces will be stored in the database, as well as having a snapshot saved.",
"optional": true,
"default": true
},
{
"type": "boolean",
"name": "train",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,16 +80,20 @@
{
"type": "boolean",
"name": "save_unknown_faces",
"description": "If true, any unrecognized face will be saved to the folder specified in <code>unknown_faces_path</code>. You can then move this image to the folder of the correct person to improve accuracy.",
"description": "If set to <code>true</code>, any unrecognized faces will be stored in the database, as well as having a snapshot saved. You can then move this image to the folder of the correct person to improve accuracy.",
"optional": true,
"default": false
},
{
"type": "string",
"name": "unknown_faces_path",
"name": {
"type": "deprecated",
"name": "unknown_faces_path",
"value": "Config option 'unknown_faces_path' is deprecated and will be removed in a future version."
},
"description": "Path to folder where unknown faces will be stored.",
"optional": true,
"default": "/config/face_recognition/faces/unknown"
"deprecated": true,
"default": null
},
{
"type": "float",
Expand All @@ -99,6 +103,13 @@
"optional": true,
"default": 5
},
{
"type": "boolean",
"name": "save_faces",
"description": "If set to <code>true</code>, detected faces will be stored in the database, as well as having a snapshot saved.",
"optional": true,
"default": true
},
{
"type": "boolean",
"name": "train",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -432,16 +432,20 @@
{
"type": "boolean",
"name": "save_unknown_faces",
"description": "If true, any unrecognized face will be saved to the folder specified in <code>unknown_faces_path</code>. You can then move this image to the folder of the correct person to improve accuracy.",
"description": "If set to <code>true</code>, any unrecognized faces will be stored in the database, as well as having a snapshot saved. You can then move this image to the folder of the correct person to improve accuracy.",
"optional": true,
"default": false
},
{
"type": "string",
"name": "unknown_faces_path",
"name": {
"type": "deprecated",
"name": "unknown_faces_path",
"value": "Config option 'unknown_faces_path' is deprecated and will be removed in a future version."
},
"description": "Path to folder where unknown faces will be stored.",
"optional": true,
"default": "/config/face_recognition/faces/unknown"
"deprecated": true,
"default": null
},
{
"type": "float",
Expand All @@ -451,6 +455,13 @@
"optional": true,
"default": 5
},
{
"type": "boolean",
"name": "save_faces",
"description": "If set to <code>true</code>, detected faces will be stored in the database, as well as having a snapshot saved.",
"optional": true,
"default": true
},
{
"type": "boolean",
"name": "train",
Expand Down
19 changes: 15 additions & 4 deletions docs/src/pages/components-explorer/components/dlib/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,16 +59,20 @@
{
"type": "boolean",
"name": "save_unknown_faces",
"description": "If true, any unrecognized face will be saved to the folder specified in <code>unknown_faces_path</code>. You can then move this image to the folder of the correct person to improve accuracy.",
"description": "If set to <code>true</code>, any unrecognized faces will be stored in the database, as well as having a snapshot saved. You can then move this image to the folder of the correct person to improve accuracy.",
"optional": true,
"default": false
},
{
"type": "string",
"name": "unknown_faces_path",
"name": {
"type": "deprecated",
"name": "unknown_faces_path",
"value": "Config option 'unknown_faces_path' is deprecated and will be removed in a future version."
},
"description": "Path to folder where unknown faces will be stored.",
"optional": true,
"default": "/config/face_recognition/faces/unknown"
"deprecated": true,
"default": null
},
{
"type": "float",
Expand All @@ -78,6 +82,13 @@
"optional": true,
"default": 5
},
{
"type": "boolean",
"name": "save_faces",
"description": "If set to <code>true</code>, detected faces will be stored in the database, as well as having a snapshot saved.",
"optional": true,
"default": true
},
{
"type": "select",
"options": [
Expand Down
42 changes: 22 additions & 20 deletions viseron/components/codeprojectai/face_recognition.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,9 @@
import requests
from face_recognition.face_recognition_cli import image_files_in_folder

from viseron.domains.camera.shared_frames import SharedFrame
from viseron.domains.face_recognition import AbstractFaceRecognition
from viseron.domains.face_recognition.const import (
CONFIG_FACE_RECOGNITION_PATH,
CONFIG_SAVE_UNKNOWN_FACES,
)
from viseron.domains.face_recognition.const import CONFIG_FACE_RECOGNITION_PATH
from viseron.helpers import calculate_absolute_coords, letterbox_resize

from .const import (
Expand All @@ -29,7 +27,6 @@
if TYPE_CHECKING:
from viseron import Viseron
from viseron.domains.object_detector.detected_object import DetectedObject
from viseron.domains.post_processor import PostProcessorFrame

LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -57,8 +54,11 @@ def __init__(self, vis: Viseron, config, camera_identifier) -> None:
min_confidence=config[CONFIG_FACE_RECOGNITION][CONFIG_MIN_CONFIDENCE],
)

def face_recognition(self, frame, detected_object: DetectedObject) -> None:
def face_recognition(
self, shared_frame: SharedFrame, detected_object: DetectedObject
) -> None:
"""Perform face recognition."""
frame = self._camera.shared_frames.get_decoded_frame_rgb(shared_frame)
x1, y1, x2, y2 = calculate_absolute_coords(
(
detected_object.rel_x1,
Expand Down Expand Up @@ -91,23 +91,25 @@ def face_recognition(self, frame, detected_object: DetectedObject) -> None:
self.known_face_found(
detection["userid"],
(
detection["x_min"],
detection["y_min"],
detection["x_max"],
detection["y_max"],
detection["x_min"] + x1,
detection["y_min"] + y1,
detection["x_max"] + x2,
detection["y_max"] + y2,
),
shared_frame,
confidence=detection["confidence"],
)
else:
self.unknown_face_found(
(
detection["x_min"] + x1,
detection["y_min"] + y1,
detection["x_max"] + x2,
detection["y_max"] + y2,
),
shared_frame,
confidence=detection["confidence"],
)
elif self._config[CONFIG_SAVE_UNKNOWN_FACES]:
self.unknown_face_found(cropped_frame)

def process(self, post_processor_frame: PostProcessorFrame) -> None:
"""Process received frame."""
decoded_frame = self._camera.shared_frames.get_decoded_frame_rgb(
post_processor_frame.shared_frame
)
for detected_object in post_processor_frame.filtered_objects:
self.face_recognition(decoded_frame, detected_object)


class CodeProjectAITrain:
Expand Down
43 changes: 23 additions & 20 deletions viseron/components/compreface/face_recognition.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,9 @@
from compreface.service import RecognitionService
from face_recognition.face_recognition_cli import image_files_in_folder

from viseron.domains.camera.shared_frames import SharedFrame
from viseron.domains.face_recognition import AbstractFaceRecognition
from viseron.domains.face_recognition.const import (
CONFIG_FACE_RECOGNITION_PATH,
CONFIG_SAVE_UNKNOWN_FACES,
)
from viseron.domains.face_recognition.const import CONFIG_FACE_RECOGNITION_PATH
from viseron.helpers import calculate_absolute_coords

from .const import (
Expand All @@ -35,7 +33,6 @@
if TYPE_CHECKING:
from viseron import Viseron
from viseron.domains.object_detector.detected_object import DetectedObject
from viseron.domains.post_processor import PostProcessorFrame

LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -79,8 +76,11 @@ def __init__(self, vis: Viseron, config, camera_identifier) -> None:
config[CONFIG_FACE_RECOGNITION][CONFIG_API_KEY]
)

def face_recognition(self, frame, detected_object: DetectedObject) -> None:
def face_recognition(
self, shared_frame: SharedFrame, detected_object: DetectedObject
) -> None:
"""Perform face recognition."""
frame = self._camera.shared_frames.get_decoded_frame_rgb(shared_frame)
x1, y1, x2, y2 = calculate_absolute_coords(
(
detected_object.rel_x1,
Expand Down Expand Up @@ -111,24 +111,27 @@ def face_recognition(self, frame, detected_object: DetectedObject) -> None:
self.known_face_found(
subject["subject"],
(
result["box"]["x_min"],
result["box"]["y_min"],
result["box"]["x_max"],
result["box"]["y_max"],
result["box"]["x_min"] + x1,
result["box"]["y_min"] + y1,
result["box"]["x_max"] + x2,
result["box"]["y_max"] + y2,
),
shared_frame,
confidence=subject["similarity"],
extra_attributes=result,
)
else:
self.unknown_face_found(
(
result["box"]["x_min"] + x1,
result["box"]["y_min"] + y1,
result["box"]["x_max"] + x2,
result["box"]["y_max"] + y2,
),
shared_frame,
confidence=subject["similarity"],
extra_attributes=result,
)
elif self._config[CONFIG_SAVE_UNKNOWN_FACES]:
self.unknown_face_found(cropped_frame)

def process(self, post_processor_frame: PostProcessorFrame) -> None:
"""Process received frame."""
decoded_frame = self._camera.shared_frames.get_decoded_frame_rgb(
post_processor_frame.shared_frame
)
for detected_object in post_processor_frame.filtered_objects:
self.face_recognition(decoded_frame, detected_object)


class CompreFaceTrain:
Expand Down
42 changes: 22 additions & 20 deletions viseron/components/deepstack/face_recognition.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,9 @@
import requests
from face_recognition.face_recognition_cli import image_files_in_folder

from viseron.domains.camera.shared_frames import SharedFrame
from viseron.domains.face_recognition import AbstractFaceRecognition
from viseron.domains.face_recognition.const import (
CONFIG_FACE_RECOGNITION_PATH,
CONFIG_SAVE_UNKNOWN_FACES,
)
from viseron.domains.face_recognition.const import CONFIG_FACE_RECOGNITION_PATH
from viseron.helpers import calculate_absolute_coords

from .const import (
Expand All @@ -30,7 +28,6 @@
if TYPE_CHECKING:
from viseron import Viseron
from viseron.domains.object_detector.detected_object import DetectedObject
from viseron.domains.post_processor import PostProcessorFrame

LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -59,8 +56,11 @@ def __init__(self, vis: Viseron, config, camera_identifier) -> None:
min_confidence=config[CONFIG_FACE_RECOGNITION][CONFIG_MIN_CONFIDENCE],
)

def face_recognition(self, frame, detected_object: DetectedObject) -> None:
def face_recognition(
self, shared_frame: SharedFrame, detected_object: DetectedObject
) -> None:
"""Perform face recognition."""
frame = self._camera.shared_frames.get_decoded_frame_rgb(shared_frame)
x1, y1, x2, y2 = calculate_absolute_coords(
(
detected_object.rel_x1,
Expand All @@ -85,23 +85,25 @@ def face_recognition(self, frame, detected_object: DetectedObject) -> None:
self.known_face_found(
detection["userid"],
(
detection["x_min"],
detection["y_min"],
detection["x_max"],
detection["y_max"],
detection["box"]["x_min"] + x1,
detection["box"]["y_min"] + y1,
detection["box"]["x_max"] + x2,
detection["box"]["y_max"] + y2,
),
shared_frame,
confidence=detection["confidence"],
)
else:
self.unknown_face_found(
(
detection["box"]["x_min"] + x1,
detection["box"]["y_min"] + y1,
detection["box"]["x_max"] + x2,
detection["box"]["y_max"] + y2,
),
shared_frame,
confidence=detection["confidence"],
)
elif self._config[CONFIG_SAVE_UNKNOWN_FACES]:
self.unknown_face_found(cropped_frame)

def process(self, post_processor_frame: PostProcessorFrame) -> None:
"""Process received frame."""
decoded_frame = self._camera.shared_frames.get_decoded_frame_rgb(
post_processor_frame.shared_frame
)
for detected_object in post_processor_frame.filtered_objects:
self.face_recognition(decoded_frame, detected_object)


class DeepstackTrain:
Expand Down
Loading

0 comments on commit b033778

Please sign in to comment.