mirror of
https://github.com/iperov/DeepFaceLive
synced 2025-08-14 02:37:01 -07:00
added module: Face Swap (Insight)
This commit is contained in:
parent
c7478635cc
commit
c4511db198
33 changed files with 567 additions and 75 deletions
|
@ -11,18 +11,19 @@ from xlib.qt.widgets.QXLabel import QXLabel
|
|||
from . import backend
|
||||
from .ui.QCameraSource import QCameraSource
|
||||
from .ui.QFaceAligner import QFaceAligner
|
||||
from .ui.QFaceAnimator import QFaceAnimator
|
||||
from .ui.QFaceDetector import QFaceDetector
|
||||
from .ui.QFaceMarker import QFaceMarker
|
||||
from .ui.QFaceMerger import QFaceMerger
|
||||
from .ui.QFaceAnimator import QFaceAnimator
|
||||
from .ui.QFaceSwapper import QFaceSwapper
|
||||
from .ui.QFaceSwapInsight import QFaceSwapInsight
|
||||
from .ui.QFaceSwapDFM import QFaceSwapDFM
|
||||
from .ui.QFileSource import QFileSource
|
||||
from .ui.QFrameAdjuster import QFrameAdjuster
|
||||
from .ui.QStreamOutput import QStreamOutput
|
||||
from .ui.widgets.QBCFaceAlignViewer import QBCFaceAlignViewer
|
||||
from .ui.widgets.QBCFaceSwapViewer import QBCFaceSwapViewer
|
||||
from .ui.widgets.QBCMergedFrameViewer import QBCMergedFrameViewer
|
||||
from .ui.widgets.QBCFrameViewer import QBCFrameViewer
|
||||
from .ui.widgets.QBCMergedFrameViewer import QBCMergedFrameViewer
|
||||
|
||||
|
||||
class QLiveSwap(qtx.QXWidget):
|
||||
|
@ -58,13 +59,13 @@ class QLiveSwap(qtx.QXWidget):
|
|||
face_marker = self.face_marker = backend.FaceMarker (weak_heap=backend_weak_heap, reemit_frame_signal=reemit_frame_signal, bc_in=face_detector_bc_out, bc_out=face_marker_bc_out, backend_db=backend_db)
|
||||
face_aligner = self.face_aligner = backend.FaceAligner (weak_heap=backend_weak_heap, reemit_frame_signal=reemit_frame_signal, bc_in=face_marker_bc_out, bc_out=face_aligner_bc_out, backend_db=backend_db )
|
||||
face_animator = self.face_animator = backend.FaceAnimator (weak_heap=backend_weak_heap, reemit_frame_signal=reemit_frame_signal, bc_in=face_aligner_bc_out, bc_out=face_merger_bc_out, animatables_path=animatables_path, backend_db=backend_db )
|
||||
|
||||
face_swapper = self.face_swapper = backend.FaceSwapper (weak_heap=backend_weak_heap, reemit_frame_signal=reemit_frame_signal, bc_in=face_aligner_bc_out, bc_out=face_swapper_bc_out, dfm_models_path=dfm_models_path, backend_db=backend_db )
|
||||
face_swap_insight = self.face_swap_insight = backend.FaceSwapInsight (weak_heap=backend_weak_heap, reemit_frame_signal=reemit_frame_signal, bc_in=face_aligner_bc_out, bc_out=face_swapper_bc_out, faces_path=animatables_path, backend_db=backend_db )
|
||||
face_swap_dfm = self.face_swap_dfm = backend.FaceSwapDFM (weak_heap=backend_weak_heap, reemit_frame_signal=reemit_frame_signal, bc_in=face_aligner_bc_out, bc_out=face_swapper_bc_out, dfm_models_path=dfm_models_path, backend_db=backend_db )
|
||||
frame_adjuster = self.frame_adjuster = backend.FrameAdjuster(weak_heap=backend_weak_heap, reemit_frame_signal=reemit_frame_signal, bc_in=face_swapper_bc_out, bc_out=frame_adjuster_bc_out, backend_db=backend_db )
|
||||
face_merger = self.face_merger = backend.FaceMerger (weak_heap=backend_weak_heap, reemit_frame_signal=reemit_frame_signal, bc_in=frame_adjuster_bc_out, bc_out=face_merger_bc_out, backend_db=backend_db )
|
||||
stream_output = self.stream_output = backend.StreamOutput (weak_heap=backend_weak_heap, reemit_frame_signal=reemit_frame_signal, bc_in=face_merger_bc_out, save_default_path=userdata_path, backend_db=backend_db)
|
||||
|
||||
self.all_backends : List[backend.BackendHost] = [file_source, camera_source, face_detector, face_marker, face_aligner, face_animator, face_swapper, frame_adjuster, face_merger, stream_output]
|
||||
self.all_backends : List[backend.BackendHost] = [file_source, camera_source, face_detector, face_marker, face_aligner, face_animator, face_swap_insight, face_swap_dfm, frame_adjuster, face_merger, stream_output]
|
||||
|
||||
self.q_file_source = QFileSource(self.file_source)
|
||||
self.q_camera_source = QCameraSource(self.camera_source)
|
||||
|
@ -72,7 +73,8 @@ class QLiveSwap(qtx.QXWidget):
|
|||
self.q_face_marker = QFaceMarker(self.face_marker)
|
||||
self.q_face_aligner = QFaceAligner(self.face_aligner)
|
||||
self.q_face_animator = QFaceAnimator(self.face_animator, animatables_path=animatables_path)
|
||||
self.q_face_swapper = QFaceSwapper(self.face_swapper, dfm_models_path=dfm_models_path)
|
||||
self.q_face_swap_insight = QFaceSwapInsight(self.face_swap_insight, faces_path=animatables_path)
|
||||
self.q_face_swap_dfm = QFaceSwapDFM(self.face_swap_dfm, dfm_models_path=dfm_models_path)
|
||||
self.q_frame_adjuster = QFrameAdjuster(self.frame_adjuster)
|
||||
self.q_face_merger = QFaceMerger(self.face_merger)
|
||||
self.q_stream_output = QStreamOutput(self.stream_output)
|
||||
|
@ -83,8 +85,8 @@ class QLiveSwap(qtx.QXWidget):
|
|||
self.q_ds_merged_frame_viewer = QBCMergedFrameViewer(backend_weak_heap, face_merger_bc_out)
|
||||
|
||||
q_nodes = qtx.QXWidgetHBox([ qtx.QXWidgetVBox([self.q_file_source, self.q_camera_source], spacing=5, fixed_width=256),
|
||||
qtx.QXWidgetVBox([self.q_face_detector, self.q_face_aligner,], spacing=5, fixed_width=256),
|
||||
qtx.QXWidgetVBox([self.q_face_marker, self.q_face_animator, self.q_face_swapper], spacing=5, fixed_width=256),
|
||||
qtx.QXWidgetVBox([self.q_face_detector, self.q_face_aligner, ], spacing=5, fixed_width=256),
|
||||
qtx.QXWidgetVBox([self.q_face_marker, self.q_face_animator, self.q_face_swap_insight, self.q_face_swap_dfm], spacing=5, fixed_width=256),
|
||||
qtx.QXWidgetVBox([self.q_frame_adjuster, self.q_face_merger, self.q_stream_output], spacing=5, fixed_width=256),
|
||||
], spacing=5, size_policy=('fixed', 'fixed') )
|
||||
|
||||
|
@ -112,7 +114,7 @@ class QLiveSwap(qtx.QXWidget):
|
|||
def initialize(self):
|
||||
for bcknd in self.all_backends:
|
||||
default_state = True
|
||||
if isinstance(bcknd, (backend.CameraSource, backend.FaceAnimator) ):
|
||||
if isinstance(bcknd, (backend.CameraSource, backend.FaceAnimator, backend.FaceSwapInsight) ):
|
||||
default_state = False
|
||||
bcknd.restore_on_off_state(default_state=default_state)
|
||||
|
||||
|
|
|
@ -14,13 +14,13 @@ from .BackendBase import (BackendConnection, BackendDB, BackendHost,
|
|||
BackendWorkerState)
|
||||
|
||||
|
||||
class FaceSwapper(BackendHost):
|
||||
class FaceSwapDFM(BackendHost):
|
||||
def __init__(self, weak_heap : BackendWeakHeap, reemit_frame_signal : BackendSignal, bc_in : BackendConnection, bc_out : BackendConnection, dfm_models_path : Path, backend_db : BackendDB = None,
|
||||
id : int = 0):
|
||||
self._id = id
|
||||
super().__init__(backend_db=backend_db,
|
||||
sheet_cls=Sheet,
|
||||
worker_cls=FaceSwapperWorker,
|
||||
worker_cls=FaceSwapDFMWorker,
|
||||
worker_state_cls=WorkerState,
|
||||
worker_start_args=[weak_heap, reemit_frame_signal, bc_in, bc_out, dfm_models_path])
|
||||
|
||||
|
@ -29,7 +29,7 @@ class FaceSwapper(BackendHost):
|
|||
def _get_name(self):
|
||||
return super()._get_name()# + f'{self._id}'
|
||||
|
||||
class FaceSwapperWorker(BackendWorker):
|
||||
class FaceSwapDFMWorker(BackendWorker):
|
||||
def get_state(self) -> 'WorkerState': return super().get_state()
|
||||
def get_control_sheet(self) -> 'Sheet.Worker': return super().get_control_sheet()
|
||||
|
||||
|
@ -218,7 +218,7 @@ class FaceSwapperWorker(BackendWorker):
|
|||
if events.new_status_downloading:
|
||||
self.set_busy(False)
|
||||
cs.model_dl_progress.enable()
|
||||
cs.model_dl_progress.set_config( lib_csw.Progress.Config(title='@FaceSwapper.downloading_model') )
|
||||
cs.model_dl_progress.set_config( lib_csw.Progress.Config(title='@FaceSwapDFM.downloading_model') )
|
||||
cs.model_dl_progress.set_progress(0)
|
||||
|
||||
elif events.new_status_initialized:
|
||||
|
@ -229,12 +229,12 @@ class FaceSwapperWorker(BackendWorker):
|
|||
|
||||
cs.model_info_label.enable()
|
||||
cs.model_info_label.set_config( lib_csw.InfoLabel.Config(info_icon=True,
|
||||
info_lines=[f'@FaceSwapper.model_information',
|
||||
info_lines=[f'@FaceSwapDFM.model_information',
|
||||
'',
|
||||
f'@FaceSwapper.filename',
|
||||
f'@FaceSwapDFM.filename',
|
||||
f'{self.dfm_model.get_model_path().name}',
|
||||
'',
|
||||
f'@FaceSwapper.resolution',
|
||||
f'@FaceSwapDFM.resolution',
|
||||
f'{model_width}x{model_height}']) )
|
||||
|
||||
cs.swap_all_faces.enable()
|
269
apps/DeepFaceLive/backend/FaceSwapInsight.py
Normal file
269
apps/DeepFaceLive/backend/FaceSwapInsight.py
Normal file
|
@ -0,0 +1,269 @@
|
|||
import time
|
||||
from pathlib import Path
|
||||
import cv2
|
||||
import numpy as np
|
||||
from modelhub.onnx import InsightFace2D106, InsightFaceSwap, YoloV5Face
|
||||
from xlib import cv as lib_cv2
|
||||
from xlib import os as lib_os
|
||||
from xlib import path as lib_path
|
||||
from xlib.face import ELandmarks2D, FLandmarks2D, FRect
|
||||
from xlib.image.ImageProcessor import ImageProcessor
|
||||
from xlib.mp import csw as lib_csw
|
||||
|
||||
from .BackendBase import (BackendConnection, BackendDB, BackendHost,
|
||||
BackendSignal, BackendWeakHeap, BackendWorker,
|
||||
BackendWorkerState)
|
||||
|
||||
|
||||
class FaceSwapInsight(BackendHost):
|
||||
def __init__(self, weak_heap : BackendWeakHeap, reemit_frame_signal : BackendSignal, bc_in : BackendConnection, bc_out : BackendConnection, faces_path : Path, backend_db : BackendDB = None,
|
||||
id : int = 0):
|
||||
self._id = id
|
||||
super().__init__(backend_db=backend_db,
|
||||
sheet_cls=Sheet,
|
||||
worker_cls=FaceSwapInsightWorker,
|
||||
worker_state_cls=WorkerState,
|
||||
worker_start_args=[weak_heap, reemit_frame_signal, bc_in, bc_out, faces_path])
|
||||
|
||||
def get_control_sheet(self) -> 'Sheet.Host': return super().get_control_sheet()
|
||||
|
||||
def _get_name(self):
|
||||
return super()._get_name()
|
||||
|
||||
class FaceSwapInsightWorker(BackendWorker):
|
||||
def get_state(self) -> 'WorkerState': return super().get_state()
|
||||
def get_control_sheet(self) -> 'Sheet.Worker': return super().get_control_sheet()
|
||||
|
||||
def on_start(self, weak_heap : BackendWeakHeap, reemit_frame_signal : BackendSignal, bc_in : BackendConnection, bc_out : BackendConnection, faces_path : Path):
|
||||
self.weak_heap = weak_heap
|
||||
self.reemit_frame_signal = reemit_frame_signal
|
||||
self.bc_in = bc_in
|
||||
self.bc_out = bc_out
|
||||
self.faces_path = faces_path
|
||||
|
||||
self.pending_bcd = None
|
||||
|
||||
self.swap_model : InsightFaceSwap = None
|
||||
|
||||
self.target_face_img = None
|
||||
self.face_vector = None
|
||||
|
||||
lib_os.set_timer_resolution(1)
|
||||
|
||||
state, cs = self.get_state(), self.get_control_sheet()
|
||||
|
||||
cs.device.call_on_selected(self.on_cs_device)
|
||||
cs.face.call_on_selected(self.on_cs_face)
|
||||
cs.adjust_c.call_on_number(self.on_cs_adjust_c)
|
||||
cs.adjust_x.call_on_number(self.on_cs_adjust_x)
|
||||
cs.adjust_y.call_on_number(self.on_cs_adjust_y)
|
||||
|
||||
cs.animator_face_id.call_on_number(self.on_cs_animator_face_id)
|
||||
cs.update_faces.call_on_signal(self.update_faces)
|
||||
|
||||
cs.device.enable()
|
||||
cs.device.set_choices( InsightFaceSwap.get_available_devices(), none_choice_name='@misc.menu_select')
|
||||
cs.device.select(state.device)
|
||||
|
||||
def update_faces(self):
|
||||
state, cs = self.get_state(), self.get_control_sheet()
|
||||
cs.face.set_choices([face_path.name for face_path in lib_path.get_files_paths(self.faces_path, extensions=['.jpg','.jpeg','.png'])], none_choice_name='@misc.menu_select')
|
||||
|
||||
|
||||
def on_cs_device(self, idx, device):
|
||||
state, cs = self.get_state(), self.get_control_sheet()
|
||||
if device is not None and state.device == device:
|
||||
self.swap_model = InsightFaceSwap(device)
|
||||
|
||||
self.face_detector = YoloV5Face(device)
|
||||
self.face_marker = InsightFace2D106(device)
|
||||
|
||||
cs.face.enable()
|
||||
self.update_faces()
|
||||
cs.face.select(state.face)
|
||||
|
||||
cs.adjust_c.enable()
|
||||
cs.adjust_c.set_config(lib_csw.Number.Config(min=1.0, max=2.0, step=0.01, decimals=2, allow_instant_update=True))
|
||||
adjust_c = state.adjust_c
|
||||
if adjust_c is None:
|
||||
adjust_c = 1.55
|
||||
cs.adjust_c.set_number(adjust_c)
|
||||
|
||||
cs.adjust_x.enable()
|
||||
cs.adjust_x.set_config(lib_csw.Number.Config(min=-0.5, max=0.5, step=0.01, decimals=2, allow_instant_update=True))
|
||||
adjust_x = state.adjust_x
|
||||
if adjust_x is None:
|
||||
adjust_x = 0.0
|
||||
cs.adjust_x.set_number(adjust_x)
|
||||
|
||||
cs.adjust_y.enable()
|
||||
cs.adjust_y.set_config(lib_csw.Number.Config(min=-0.5, max=0.5, step=0.01, decimals=2, allow_instant_update=True))
|
||||
adjust_y = state.adjust_y
|
||||
if adjust_y is None:
|
||||
adjust_y = -0.15
|
||||
cs.adjust_y.set_number(adjust_y)
|
||||
|
||||
cs.animator_face_id.enable()
|
||||
cs.animator_face_id.set_config(lib_csw.Number.Config(min=0, max=16, step=1, decimals=0, allow_instant_update=True))
|
||||
cs.animator_face_id.set_number(state.animator_face_id if state.animator_face_id is not None else 0)
|
||||
|
||||
cs.update_faces.enable()
|
||||
else:
|
||||
state.device = device
|
||||
self.save_state()
|
||||
self.restart()
|
||||
|
||||
def on_cs_face(self, idx, face):
|
||||
state, cs = self.get_state(), self.get_control_sheet()
|
||||
|
||||
state.face = face
|
||||
self.face_vector = None
|
||||
self.target_face_img = None
|
||||
|
||||
if face is not None:
|
||||
try:
|
||||
self.target_face_img = lib_cv2.imread(self.faces_path / face)
|
||||
|
||||
except Exception as e:
|
||||
cs.face.unselect()
|
||||
|
||||
self.save_state()
|
||||
self.reemit_frame_signal.send()
|
||||
|
||||
def on_cs_adjust_c(self, adjust_c):
|
||||
state, cs = self.get_state(), self.get_control_sheet()
|
||||
cfg = cs.adjust_c.get_config()
|
||||
adjust_c = state.adjust_c = np.clip(adjust_c, cfg.min, cfg.max)
|
||||
cs.adjust_c.set_number(adjust_c)
|
||||
|
||||
self.face_vector = None
|
||||
self.save_state()
|
||||
self.reemit_frame_signal.send()
|
||||
|
||||
def on_cs_adjust_x(self, adjust_x):
|
||||
state, cs = self.get_state(), self.get_control_sheet()
|
||||
cfg = cs.adjust_x.get_config()
|
||||
adjust_x = state.adjust_x = np.clip(adjust_x, cfg.min, cfg.max)
|
||||
cs.adjust_x.set_number(adjust_x)
|
||||
|
||||
self.face_vector = None
|
||||
self.save_state()
|
||||
self.reemit_frame_signal.send()
|
||||
|
||||
def on_cs_adjust_y(self, adjust_y):
|
||||
state, cs = self.get_state(), self.get_control_sheet()
|
||||
cfg = cs.adjust_y.get_config()
|
||||
adjust_y = state.adjust_y = np.clip(adjust_y, cfg.min, cfg.max)
|
||||
cs.adjust_y.set_number(adjust_y)
|
||||
|
||||
self.face_vector = None
|
||||
self.save_state()
|
||||
self.reemit_frame_signal.send()
|
||||
|
||||
|
||||
def on_cs_animator_face_id(self, animator_face_id):
|
||||
state, cs = self.get_state(), self.get_control_sheet()
|
||||
cfg = cs.animator_face_id.get_config()
|
||||
animator_face_id = state.animator_face_id = int(np.clip(animator_face_id, cfg.min, cfg.max))
|
||||
cs.animator_face_id.set_number(animator_face_id)
|
||||
self.save_state()
|
||||
self.reemit_frame_signal.send()
|
||||
|
||||
|
||||
def on_tick(self):
|
||||
state, cs = self.get_state(), self.get_control_sheet()
|
||||
|
||||
if self.pending_bcd is None:
|
||||
self.start_profile_timing()
|
||||
|
||||
bcd = self.bc_in.read(timeout=0.005)
|
||||
if bcd is not None:
|
||||
bcd.assign_weak_heap(self.weak_heap)
|
||||
|
||||
if self.face_vector is None and self.target_face_img is not None:
|
||||
rects = self.face_detector.extract (self.target_face_img, threshold=0.5)[0]
|
||||
if len(rects) > 0:
|
||||
_,H,W,_ = ImageProcessor(self.target_face_img).get_dims()
|
||||
|
||||
u_rects = [ FRect.from_ltrb( (l/W, t/H, r/W, b/H) ) for l,t,r,b in rects ]
|
||||
face_urect = FRect.sort_by_area_size(u_rects)[0] # sorted by largest
|
||||
|
||||
face_image, face_uni_mat = face_urect.cut(self.target_face_img, 1.6, 192)
|
||||
lmrks = self.face_marker.extract(face_image)[0]
|
||||
lmrks = lmrks[...,0:2] / (192,192)
|
||||
|
||||
face_ulmrks = FLandmarks2D.create (ELandmarks2D.L106, lmrks).transform(face_uni_mat, invert=True)
|
||||
|
||||
face_align_img, _ = face_ulmrks.cut(self.target_face_img, state.adjust_c,
|
||||
self.swap_model.get_face_vector_input_size(),
|
||||
x_offset=state.adjust_x,
|
||||
y_offset=state.adjust_y)
|
||||
self.face_vector = self.swap_model.get_face_vector(face_align_img)
|
||||
|
||||
|
||||
swap_model = self.swap_model
|
||||
if swap_model is not None and self.face_vector is not None:
|
||||
|
||||
for i, fsi in enumerate(bcd.get_face_swap_info_list()):
|
||||
if state.animator_face_id == i:
|
||||
face_align_image = bcd.get_image(fsi.face_align_image_name)
|
||||
if face_align_image is not None:
|
||||
|
||||
_,H,W,_ = ImageProcessor(face_align_image).get_dims()
|
||||
|
||||
anim_image = swap_model.generate(face_align_image, self.face_vector)
|
||||
anim_image = ImageProcessor(anim_image).resize((W,H)).get_image('HWC')
|
||||
|
||||
fsi.face_align_mask_name = f'{fsi.face_align_image_name}_mask'
|
||||
fsi.face_swap_image_name = f'{fsi.face_align_image_name}_swapped'
|
||||
fsi.face_swap_mask_name = f'{fsi.face_swap_image_name}_mask'
|
||||
bcd.set_image(fsi.face_swap_image_name, anim_image)
|
||||
|
||||
white_mask = np.full_like(anim_image, 255, dtype=np.uint8)
|
||||
bcd.set_image(fsi.face_align_mask_name, white_mask)
|
||||
bcd.set_image(fsi.face_swap_mask_name, white_mask)
|
||||
|
||||
break
|
||||
|
||||
self.stop_profile_timing()
|
||||
self.pending_bcd = bcd
|
||||
|
||||
if self.pending_bcd is not None:
|
||||
if self.bc_out.is_full_read(1):
|
||||
self.bc_out.write(self.pending_bcd)
|
||||
self.pending_bcd = None
|
||||
else:
|
||||
time.sleep(0.001)
|
||||
|
||||
class Sheet:
|
||||
class Host(lib_csw.Sheet.Host):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.device = lib_csw.DynamicSingleSwitch.Client()
|
||||
self.face = lib_csw.DynamicSingleSwitch.Client()
|
||||
self.animator_face_id = lib_csw.Number.Client()
|
||||
self.update_faces = lib_csw.Signal.Client()
|
||||
self.adjust_c = lib_csw.Number.Client()
|
||||
self.adjust_x = lib_csw.Number.Client()
|
||||
self.adjust_y = lib_csw.Number.Client()
|
||||
|
||||
|
||||
class Worker(lib_csw.Sheet.Worker):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.device = lib_csw.DynamicSingleSwitch.Host()
|
||||
self.face = lib_csw.DynamicSingleSwitch.Host()
|
||||
self.animator_face_id = lib_csw.Number.Host()
|
||||
self.update_faces = lib_csw.Signal.Host()
|
||||
self.adjust_c = lib_csw.Number.Host()
|
||||
self.adjust_x = lib_csw.Number.Host()
|
||||
self.adjust_y = lib_csw.Number.Host()
|
||||
|
||||
|
||||
class WorkerState(BackendWorkerState):
|
||||
device = None
|
||||
face : str = None
|
||||
animator_face_id : int = None
|
||||
adjust_c : float = None
|
||||
adjust_x : float = None
|
||||
adjust_y : float = None
|
|
@ -7,7 +7,8 @@ from .FaceAnimator import FaceAnimator
|
|||
from .FaceDetector import FaceDetector
|
||||
from .FaceMarker import FaceMarker
|
||||
from .FaceMerger import FaceMerger
|
||||
from .FaceSwapper import FaceSwapper
|
||||
from .FaceSwapInsight import FaceSwapInsight
|
||||
from .FaceSwapDFM import FaceSwapDFM
|
||||
from .FileSource import FileSource
|
||||
from .FrameAdjuster import FrameAdjuster
|
||||
from .StreamOutput import StreamOutput
|
||||
|
|
|
@ -4,7 +4,7 @@ from localization import L
|
|||
from resources.gfx import QXImageDB
|
||||
from xlib import qt as qtx
|
||||
|
||||
from ..backend import FaceSwapper
|
||||
from ..backend import FaceSwapDFM
|
||||
from .widgets.QBackendPanel import QBackendPanel
|
||||
from .widgets.QCheckBoxCSWFlag import QCheckBoxCSWFlag
|
||||
from .widgets.QComboBoxCSWDynamicSingleSwitch import \
|
||||
|
@ -17,8 +17,8 @@ from .widgets.QSliderCSWNumber import QSliderCSWNumber
|
|||
from .widgets.QSpinBoxCSWNumber import QSpinBoxCSWNumber
|
||||
|
||||
|
||||
class QFaceSwapper(QBackendPanel):
|
||||
def __init__(self, backend : FaceSwapper, dfm_models_path : Path):
|
||||
class QFaceSwapDFM(QBackendPanel):
|
||||
def __init__(self, backend : FaceSwapDFM, dfm_models_path : Path):
|
||||
self._dfm_models_path = dfm_models_path
|
||||
|
||||
cs = backend.get_control_sheet()
|
||||
|
@ -28,7 +28,7 @@ class QFaceSwapper(QBackendPanel):
|
|||
q_device_label = QLabelPopupInfo(label=L('@common.device'), popup_info_text=L('@common.help.device') )
|
||||
q_device = QComboBoxCSWDynamicSingleSwitch(cs.device, reflect_state_widgets=[q_device_label])
|
||||
|
||||
q_model_label = QLabelPopupInfo(label=L('@QFaceSwapper.model'), popup_info_text=L('@QFaceSwapper.help.model') )
|
||||
q_model_label = QLabelPopupInfo(label=L('@QFaceSwapDFM.model'), popup_info_text=L('@QFaceSwapDFM.help.model') )
|
||||
q_model = QComboBoxCSWDynamicSingleSwitch(cs.model, reflect_state_widgets=[q_model_label, btn_open_folder])
|
||||
|
||||
q_model_dl_error = self._q_model_dl_error = QErrorCSWError(cs.model_dl_error)
|
||||
|
@ -36,31 +36,31 @@ class QFaceSwapper(QBackendPanel):
|
|||
|
||||
q_model_info_label = self._q_model_info_label = QLabelPopupInfoCSWInfoLabel(cs.model_info_label)
|
||||
|
||||
q_swap_all_faces_label = QLabelPopupInfo(label=L('@QFaceSwapper.swap_all_faces') )
|
||||
q_swap_all_faces_label = QLabelPopupInfo(label=L('@QFaceSwapDFM.swap_all_faces') )
|
||||
q_swap_all_faces = QCheckBoxCSWFlag(cs.swap_all_faces, reflect_state_widgets=[q_swap_all_faces_label])
|
||||
|
||||
q_face_id_label = QLabelPopupInfo(label=L('@QFaceSwapper.face_id'), popup_info_text=L('@QFaceSwapper.help.face_id') )
|
||||
q_face_id_label = QLabelPopupInfo(label=L('@common.face_id'), popup_info_text=L('@QFaceSwapDFM.help.face_id') )
|
||||
q_face_id = QSpinBoxCSWNumber(cs.face_id, reflect_state_widgets=[q_face_id_label])
|
||||
|
||||
q_morph_factor_label = QLabelPopupInfo(label=L('@QFaceSwapper.morph_factor'), popup_info_text=L('@QFaceSwapper.help.morph_factor') )
|
||||
q_morph_factor_label = QLabelPopupInfo(label=L('@QFaceSwapDFM.morph_factor'), popup_info_text=L('@QFaceSwapDFM.help.morph_factor') )
|
||||
q_morph_factor = QSliderCSWNumber(cs.morph_factor, reflect_state_widgets=[q_morph_factor_label])
|
||||
|
||||
q_sharpen_amount_label = QLabelPopupInfo(label=L('@QFaceSwapper.presharpen_amount'), popup_info_text=L('@QFaceSwapper.help.presharpen_amount') )
|
||||
q_sharpen_amount_label = QLabelPopupInfo(label=L('@QFaceSwapDFM.presharpen_amount'), popup_info_text=L('@QFaceSwapDFM.help.presharpen_amount') )
|
||||
q_sharpen_amount = QSliderCSWNumber(cs.presharpen_amount, reflect_state_widgets=[q_sharpen_amount_label])
|
||||
|
||||
q_pre_gamma_label = QLabelPopupInfo(label=L('@QFaceSwapper.pregamma'), popup_info_text=L('@QFaceSwapper.help.pregamma') )
|
||||
q_pre_gamma_label = QLabelPopupInfo(label=L('@QFaceSwapDFM.pregamma'), popup_info_text=L('@QFaceSwapDFM.help.pregamma') )
|
||||
|
||||
q_pre_gamma_red = QSpinBoxCSWNumber(cs.pre_gamma_red, reflect_state_widgets=[q_pre_gamma_label])
|
||||
q_pre_gamma_green = QSpinBoxCSWNumber(cs.pre_gamma_green)
|
||||
q_pre_gamma_blue = QSpinBoxCSWNumber(cs.pre_gamma_blue)
|
||||
|
||||
q_post_gamma_label = QLabelPopupInfo(label=L('@QFaceSwapper.postgamma'))
|
||||
q_post_gamma_label = QLabelPopupInfo(label=L('@QFaceSwapDFM.postgamma'))
|
||||
|
||||
q_post_gamma_red = QSpinBoxCSWNumber(cs.post_gamma_red, reflect_state_widgets=[q_post_gamma_label])
|
||||
q_post_gamma_green = QSpinBoxCSWNumber(cs.post_gamma_green)
|
||||
q_post_gamma_blue = QSpinBoxCSWNumber(cs.post_gamma_blue)
|
||||
|
||||
q_two_pass_label = QLabelPopupInfo(label=L('@QFaceSwapper.two_pass'), popup_info_text=L('@QFaceSwapper.help.two_pass') )
|
||||
q_two_pass_label = QLabelPopupInfo(label=L('@QFaceSwapDFM.two_pass'), popup_info_text=L('@QFaceSwapDFM.help.two_pass') )
|
||||
q_two_pass = QCheckBoxCSWFlag(cs.two_pass, reflect_state_widgets=[q_two_pass_label])
|
||||
|
||||
grid_l = qtx.QXGridLayout( spacing=5)
|
||||
|
@ -94,7 +94,7 @@ class QFaceSwapper(QBackendPanel):
|
|||
grid_l.addWidget(q_two_pass, row, 1)
|
||||
row += 1
|
||||
|
||||
super().__init__(backend, L('@QFaceSwapper.module_title'),
|
||||
super().__init__(backend, L('@QFaceSwapDFM.module_title'),
|
||||
layout=qtx.QXVBoxLayout([grid_l]) )
|
||||
|
||||
|
71
apps/DeepFaceLive/ui/QFaceSwapInsight.py
Normal file
71
apps/DeepFaceLive/ui/QFaceSwapInsight.py
Normal file
|
@ -0,0 +1,71 @@
|
|||
from pathlib import Path
|
||||
|
||||
from localization import L
|
||||
from resources.gfx import QXImageDB
|
||||
from xlib import qt as qtx
|
||||
|
||||
from ..backend import FaceSwapInsight
|
||||
from .widgets.QBackendPanel import QBackendPanel
|
||||
from .widgets.QComboBoxCSWDynamicSingleSwitch import \
|
||||
QComboBoxCSWDynamicSingleSwitch
|
||||
from .widgets.QLabelPopupInfo import QLabelPopupInfo
|
||||
from .widgets.QSliderCSWNumber import QSliderCSWNumber
|
||||
from .widgets.QSpinBoxCSWNumber import QSpinBoxCSWNumber
|
||||
from .widgets.QXPushButtonCSWSignal import QXPushButtonCSWSignal
|
||||
|
||||
|
||||
class QFaceSwapInsight(QBackendPanel):
|
||||
def __init__(self, backend : FaceSwapInsight, faces_path : Path):
|
||||
self._faces_path = faces_path
|
||||
|
||||
cs = backend.get_control_sheet()
|
||||
|
||||
btn_open_folder = self.btn_open_folder = qtx.QXPushButton(image = QXImageDB.eye_outline('light gray'), tooltip_text='Reveal in Explorer', released=self._btn_open_folder_released, fixed_size=(24,22) )
|
||||
|
||||
q_device_label = QLabelPopupInfo(label=L('@common.device'), popup_info_text=L('@common.help.device') )
|
||||
q_device = QComboBoxCSWDynamicSingleSwitch(cs.device, reflect_state_widgets=[q_device_label])
|
||||
|
||||
q_face_label = QLabelPopupInfo(label=L('@QFaceSwapInsight.face') )
|
||||
q_face = QComboBoxCSWDynamicSingleSwitch(cs.face, reflect_state_widgets=[q_face_label, btn_open_folder])
|
||||
|
||||
q_adjust_c_label = QLabelPopupInfo(label='C')
|
||||
q_adjust_c = QSliderCSWNumber(cs.adjust_c, reflect_state_widgets=[q_adjust_c_label])
|
||||
|
||||
q_adjust_x_label = QLabelPopupInfo(label='X')
|
||||
q_adjust_x = QSliderCSWNumber(cs.adjust_x, reflect_state_widgets=[q_adjust_x_label])
|
||||
|
||||
q_adjust_y_label = QLabelPopupInfo(label='Y')
|
||||
q_adjust_y = QSliderCSWNumber(cs.adjust_y, reflect_state_widgets=[q_adjust_y_label])
|
||||
|
||||
q_animator_face_id_label = QLabelPopupInfo(label=L('@common.face_id') )
|
||||
q_animator_face_id = QSpinBoxCSWNumber(cs.animator_face_id, reflect_state_widgets=[q_animator_face_id_label])
|
||||
|
||||
q_update_faces = QXPushButtonCSWSignal(cs.update_faces, image=QXImageDB.reload_outline('light gray'), button_size=(24,22) )
|
||||
|
||||
grid_l = qtx.QXGridLayout( spacing=5)
|
||||
row = 0
|
||||
grid_l.addWidget(q_device_label, row, 0, alignment=qtx.AlignRight | qtx.AlignVCenter )
|
||||
grid_l.addWidget(q_device, row, 1, alignment=qtx.AlignLeft )
|
||||
row += 1
|
||||
grid_l.addWidget(q_face_label, row, 0, alignment=qtx.AlignRight | qtx.AlignVCenter )
|
||||
grid_l.addLayout(qtx.QXHBoxLayout([q_face, 2, btn_open_folder, 2, q_update_faces]), row, 1 )
|
||||
row += 1
|
||||
grid_l.addWidget(q_adjust_c_label, row, 0, alignment=qtx.AlignRight | qtx.AlignVCenter )
|
||||
grid_l.addWidget(q_adjust_c, row, 1 )
|
||||
row += 1
|
||||
grid_l.addWidget(q_adjust_x_label, row, 0, alignment=qtx.AlignRight | qtx.AlignVCenter )
|
||||
grid_l.addWidget(q_adjust_x, row, 1 )
|
||||
row += 1
|
||||
grid_l.addWidget(q_adjust_y_label, row, 0, alignment=qtx.AlignRight | qtx.AlignVCenter )
|
||||
grid_l.addWidget(q_adjust_y, row, 1 )
|
||||
row += 1
|
||||
grid_l.addWidget(q_animator_face_id_label, row, 0, alignment=qtx.AlignRight | qtx.AlignVCenter )
|
||||
grid_l.addWidget(q_animator_face_id, row, 1, alignment=qtx.AlignLeft )
|
||||
|
||||
row += 1
|
||||
|
||||
super().__init__(backend, L('@QFaceSwapInsight.module_title'),
|
||||
layout=qtx.QXVBoxLayout([grid_l]) )
|
||||
|
||||
def _btn_open_folder_released(self):
|
||||
qtx.QDesktopServices.openUrl(qtx.QUrl.fromLocalFile( str(self._faces_path) ))
|
Loading…
Add table
Add a link
Reference in a new issue