mirror of
https://github.com/iperov/DeepFaceLive
synced 2025-08-21 05:53:25 -07:00
FaceAligner: added 'head_mode', can be used with HEAD models.
This commit is contained in:
parent
96931d6619
commit
72166cc190
11 changed files with 177 additions and 40 deletions
|
@ -37,6 +37,7 @@ class FaceAlignerWorker(BackendWorker):
|
|||
cs.face_coverage.call_on_number(self.on_cs_face_coverage)
|
||||
cs.resolution.call_on_number(self.on_cs_resolution)
|
||||
cs.exclude_moving_parts.call_on_flag(self.on_cs_exclude_moving_parts)
|
||||
cs.head_mode.call_on_flag(self.on_cs_head_mode)
|
||||
cs.x_offset.call_on_number(self.on_cs_x_offset)
|
||||
cs.y_offset.call_on_number(self.on_cs_y_offset)
|
||||
|
||||
|
@ -50,6 +51,9 @@ class FaceAlignerWorker(BackendWorker):
|
|||
|
||||
cs.exclude_moving_parts.enable()
|
||||
cs.exclude_moving_parts.set_flag(state.exclude_moving_parts if state.exclude_moving_parts is not None else True)
|
||||
|
||||
cs.head_mode.enable()
|
||||
cs.head_mode.set_flag(state.head_mode if state.head_mode is not None else False)
|
||||
|
||||
cs.x_offset.enable()
|
||||
cs.x_offset.set_config(lib_csw.Number.Config(min=-1, max=1, step=0.01, decimals=2, allow_instant_update=True))
|
||||
|
@ -82,6 +86,12 @@ class FaceAlignerWorker(BackendWorker):
|
|||
self.save_state()
|
||||
self.reemit_frame_signal.send()
|
||||
|
||||
def on_cs_head_mode(self, head_mode):
|
||||
state, cs = self.get_state(), self.get_control_sheet()
|
||||
state.head_mode = head_mode
|
||||
self.save_state()
|
||||
self.reemit_frame_signal.send()
|
||||
|
||||
def on_cs_x_offset(self, x_offset):
|
||||
state, cs = self.get_state(), self.get_control_sheet()
|
||||
cfg = cs.x_offset.get_config()
|
||||
|
@ -113,13 +123,20 @@ class FaceAlignerWorker(BackendWorker):
|
|||
|
||||
if all_is_not_None(state.face_coverage, state.resolution, frame_name, frame_image):
|
||||
for face_id,face_mark in enumerate( bcd.get_face_mark_list() ):
|
||||
face_ulmrks = face_mark.get_face_ulandmarks_by_type(FaceULandmarks.Type.LANDMARKS_2D_468)
|
||||
face_ulmrks = face_mark.get_face_ulandmarks_by_type(FaceULandmarks.Type.LANDMARKS_468)
|
||||
if face_ulmrks is None:
|
||||
face_ulmrks = face_mark.get_face_ulandmarks_by_type(FaceULandmarks.Type.LANDMARKS_2D_68)
|
||||
|
||||
face_ulmrks = face_mark.get_face_ulandmarks_by_type(FaceULandmarks.Type.LANDMARKS_68)
|
||||
|
||||
head_yaw = None
|
||||
if state.head_mode:
|
||||
face_pose = face_mark.get_face_pose()
|
||||
if face_pose is not None:
|
||||
head_yaw = face_pose.as_radians()[1]
|
||||
|
||||
if face_ulmrks is not None:
|
||||
face_image, uni_mat = face_ulmrks.cut(frame_image, state.face_coverage, state.resolution,
|
||||
exclude_moving_parts=state.exclude_moving_parts,
|
||||
head_yaw=head_yaw,
|
||||
x_offset=state.x_offset,
|
||||
y_offset=state.y_offset)
|
||||
|
||||
|
@ -155,6 +172,7 @@ class Sheet:
|
|||
self.face_coverage = lib_csw.Number.Client()
|
||||
self.resolution = lib_csw.Number.Client()
|
||||
self.exclude_moving_parts = lib_csw.Flag.Client()
|
||||
self.head_mode = lib_csw.Flag.Client()
|
||||
self.x_offset = lib_csw.Number.Client()
|
||||
self.y_offset = lib_csw.Number.Client()
|
||||
|
||||
|
@ -164,6 +182,7 @@ class Sheet:
|
|||
self.face_coverage = lib_csw.Number.Host()
|
||||
self.resolution = lib_csw.Number.Host()
|
||||
self.exclude_moving_parts = lib_csw.Flag.Host()
|
||||
self.head_mode = lib_csw.Flag.Host()
|
||||
self.x_offset = lib_csw.Number.Host()
|
||||
self.y_offset = lib_csw.Number.Host()
|
||||
|
||||
|
@ -171,5 +190,6 @@ class WorkerState(BackendWorkerState):
|
|||
face_coverage : float = None
|
||||
resolution : int = None
|
||||
exclude_moving_parts : bool = None
|
||||
head_mode : bool = None
|
||||
x_offset : float = None
|
||||
y_offset : float = None
|
||||
|
|
|
@ -4,9 +4,8 @@ import numpy as np
|
|||
from modelhub import onnx as onnx_models
|
||||
from modelhub import cv as cv_models
|
||||
|
||||
from xlib import cv as lib_cv
|
||||
from xlib import os as lib_os
|
||||
from xlib.facemeta import FaceULandmarks
|
||||
from xlib.facemeta import FaceULandmarks, FacePose
|
||||
from xlib.image import ImageProcessor
|
||||
from xlib.mp import csw as lib_csw
|
||||
from xlib.python import all_is_not_None
|
||||
|
@ -15,7 +14,6 @@ from .BackendBase import (BackendConnection, BackendDB, BackendHost,
|
|||
BackendSignal, BackendWeakHeap, BackendWorker,
|
||||
BackendWorkerState)
|
||||
|
||||
|
||||
class MarkerType(IntEnum):
|
||||
OPENCV_LBF = 0
|
||||
GOOGLE_FACEMESH = 1
|
||||
|
@ -175,9 +173,7 @@ class FaceMarkerWorker(BackendWorker):
|
|||
if is_opencv_lbf:
|
||||
lmrks = self.opencv_lbf.extract(face_image)[0]
|
||||
elif is_google_facemesh:
|
||||
lmrks = self.google_facemesh.extract(face_image)[0][...,0:2]
|
||||
|
||||
lmrks /= (W,H)
|
||||
lmrks = self.google_facemesh.extract(face_image)[0]
|
||||
|
||||
if marker_state.temporal_smoothing != 1:
|
||||
if not is_frame_reemitted or len(self.temporal_lmrks[face_id]) == 0:
|
||||
|
@ -186,11 +182,21 @@ class FaceMarkerWorker(BackendWorker):
|
|||
|
||||
lmrks = np.mean(self.temporal_lmrks[face_id],0 )
|
||||
|
||||
face_ulmrks = FaceULandmarks.create (FaceULandmarks.Type.LANDMARKS_2D_68 if is_opencv_lbf else \
|
||||
FaceULandmarks.Type.LANDMARKS_2D_468 if is_google_facemesh else None, lmrks)
|
||||
if is_google_facemesh:
|
||||
face_mark.set_face_pose(FacePose.from_3D_468_landmarks(lmrks))
|
||||
|
||||
if is_opencv_lbf:
|
||||
lmrks /= (W,H)
|
||||
elif is_google_facemesh:
|
||||
lmrks = lmrks[...,0:2] / (W,H)
|
||||
|
||||
face_ulmrks = FaceULandmarks.create (FaceULandmarks.Type.LANDMARKS_68 if is_opencv_lbf else \
|
||||
FaceULandmarks.Type.LANDMARKS_468 if is_google_facemesh else None, lmrks)
|
||||
|
||||
face_ulmrks = face_ulmrks.transform(face_uni_mat, invert=True)
|
||||
face_mark.add_face_ulandmarks (face_ulmrks)
|
||||
|
||||
|
||||
|
||||
self.stop_profile_timing()
|
||||
self.pending_bcd = bcd
|
||||
|
|
|
@ -24,6 +24,9 @@ class QFaceAligner(QBackendPanel):
|
|||
q_exclude_moving_parts_label = QLabelPopupInfo(label=L('@QFaceAligner.exclude_moving_parts'), popup_info_text=L('@QFaceAligner.help.exclude_moving_parts') )
|
||||
q_exclude_moving_parts = QCheckBoxCSWFlag(cs.exclude_moving_parts, reflect_state_widgets=[q_exclude_moving_parts_label])
|
||||
|
||||
q_head_mode_label = QLabelPopupInfo(label=L('@QFaceAligner.head_mode'), popup_info_text=L('@QFaceAligner.help.head_mode') )
|
||||
q_head_mode = QCheckBoxCSWFlag(cs.head_mode, reflect_state_widgets=[q_head_mode_label])
|
||||
|
||||
q_x_offset_label = QLabelPopupInfo(label=L('@QFaceAligner.x_offset'))
|
||||
q_x_offset = QSpinBoxCSWNumber(cs.x_offset, reflect_state_widgets=[q_x_offset_label])
|
||||
|
||||
|
@ -41,6 +44,9 @@ class QFaceAligner(QBackendPanel):
|
|||
grid_l.addWidget(q_exclude_moving_parts_label, row, 0, alignment=Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter )
|
||||
grid_l.addWidget(q_exclude_moving_parts, row, 1, alignment=Qt.AlignmentFlag.AlignLeft )
|
||||
row += 1
|
||||
grid_l.addWidget(q_head_mode_label, row, 0, alignment=Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter )
|
||||
grid_l.addWidget(q_head_mode, row, 1, alignment=Qt.AlignmentFlag.AlignLeft )
|
||||
row += 1
|
||||
grid_l.addLayout( lib_qt.QXVBoxLayout([q_x_offset_label, q_y_offset_label]), row, 0, alignment=Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter )
|
||||
grid_l.addLayout( lib_qt.QXHBoxLayout([q_x_offset, q_y_offset]), row, 1, alignment=Qt.AlignmentFlag.AlignLeft )
|
||||
row += 1
|
||||
|
|
|
@ -57,9 +57,9 @@ class QBCFaceAlignViewer(lib_qt.QXCollapsibleSection):
|
|||
if all_is_not_None(face_align_image_name):
|
||||
face_image = bcd.get_image(face_align_image_name).copy()
|
||||
|
||||
face_ulmrks = face_align.get_face_ulandmarks_by_type(FaceULandmarks.Type.LANDMARKS_2D_468)
|
||||
face_ulmrks = face_align.get_face_ulandmarks_by_type(FaceULandmarks.Type.LANDMARKS_468)
|
||||
if face_ulmrks is None:
|
||||
face_ulmrks = face_align.get_face_ulandmarks_by_type(FaceULandmarks.Type.LANDMARKS_2D_68)
|
||||
face_ulmrks = face_align.get_face_ulandmarks_by_type(FaceULandmarks.Type.LANDMARKS_68)
|
||||
|
||||
if face_ulmrks is not None:
|
||||
lmrks_layer = np.zeros( (self._preview_width, self._preview_width, 4), dtype=np.uint8)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue