mirror of
https://github.com/iperov/DeepFaceLive
synced 2025-07-07 05:22:08 -07:00
refactoring, FaceSwapper now can swap all faces
This commit is contained in:
parent
c0efaa1900
commit
6311a12c63
6 changed files with 119 additions and 84 deletions
|
@ -23,7 +23,7 @@ from .ui.QFrameAdjuster import QFrameAdjuster
|
||||||
from .ui.QStreamOutput import QStreamOutput
|
from .ui.QStreamOutput import QStreamOutput
|
||||||
from .ui.widgets.QBCFaceAlignViewer import QBCFaceAlignViewer
|
from .ui.widgets.QBCFaceAlignViewer import QBCFaceAlignViewer
|
||||||
from .ui.widgets.QBCFaceSwapViewer import QBCFaceSwapViewer
|
from .ui.widgets.QBCFaceSwapViewer import QBCFaceSwapViewer
|
||||||
from .ui.widgets.QBCFinalFrameViewer import QBCFinalFrameViewer
|
from .ui.widgets.QBCMergedFrameViewer import QBCMergedFrameViewer
|
||||||
from .ui.widgets.QBCFrameViewer import QBCFrameViewer
|
from .ui.widgets.QBCFrameViewer import QBCFrameViewer
|
||||||
|
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ class QLiveSwap(lib_qt.QXWidget):
|
||||||
self.q_ds_frame_viewer = QBCFrameViewer(backed_weak_heap, multi_sources_bc_out)
|
self.q_ds_frame_viewer = QBCFrameViewer(backed_weak_heap, multi_sources_bc_out)
|
||||||
self.q_ds_fa_viewer = QBCFaceAlignViewer(backed_weak_heap, face_aligner_bc_out, preview_width=256)
|
self.q_ds_fa_viewer = QBCFaceAlignViewer(backed_weak_heap, face_aligner_bc_out, preview_width=256)
|
||||||
self.q_ds_fc_viewer = QBCFaceSwapViewer(backed_weak_heap, face_swapper_bc_out, preview_width=256)
|
self.q_ds_fc_viewer = QBCFaceSwapViewer(backed_weak_heap, face_swapper_bc_out, preview_width=256)
|
||||||
self.q_ds_merged_frame_viewer = QBCFinalFrameViewer(backed_weak_heap, face_merger_bc_out)
|
self.q_ds_merged_frame_viewer = QBCMergedFrameViewer(backed_weak_heap, face_merger_bc_out)
|
||||||
|
|
||||||
q_nodes = lib_qt.QXWidget(size_policy=(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed),
|
q_nodes = lib_qt.QXWidget(size_policy=(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed),
|
||||||
layout=lib_qt.QXHBoxLayout([
|
layout=lib_qt.QXHBoxLayout([
|
||||||
|
|
|
@ -208,7 +208,7 @@ class FaceMergerWorker(BackendWorker):
|
||||||
_cpu_interp = {'bilinear' : ImageProcessor.Interpolation.LINEAR,
|
_cpu_interp = {'bilinear' : ImageProcessor.Interpolation.LINEAR,
|
||||||
'bicubic' : ImageProcessor.Interpolation.CUBIC,
|
'bicubic' : ImageProcessor.Interpolation.CUBIC,
|
||||||
'lanczos4' : ImageProcessor.Interpolation.LANCZOS4}
|
'lanczos4' : ImageProcessor.Interpolation.LANCZOS4}
|
||||||
def _merge_on_cpu(self, out_merged_frame, frame_image, face_resolution, face_align_img, face_align_mask_img, face_align_lmrks_mask_img, face_swap_img, face_swap_mask_img, aligned_to_source_uni_mat, frame_width, frame_height ):
|
def _merge_on_cpu(self, frame_image, face_resolution, face_align_img, face_align_mask_img, face_align_lmrks_mask_img, face_swap_img, face_swap_mask_img, aligned_to_source_uni_mat, frame_width, frame_height, do_color_compression ):
|
||||||
state = self.get_state()
|
state = self.get_state()
|
||||||
|
|
||||||
interpolation = self._cpu_interp[state.interpolation]
|
interpolation = self._cpu_interp[state.interpolation]
|
||||||
|
@ -247,11 +247,11 @@ class FaceMergerWorker(BackendWorker):
|
||||||
opacity = np.float32(state.face_opacity)
|
opacity = np.float32(state.face_opacity)
|
||||||
one_f = np.float32(1.0)
|
one_f = np.float32(1.0)
|
||||||
if opacity == 1.0:
|
if opacity == 1.0:
|
||||||
ne.evaluate('frame_image*(one_f-frame_face_mask) + frame_face_swap_img*frame_face_mask', out=out_merged_frame)
|
out_merged_frame = ne.evaluate('frame_image*(one_f-frame_face_mask) + frame_face_swap_img*frame_face_mask')
|
||||||
else:
|
else:
|
||||||
ne.evaluate('frame_image*(one_f-frame_face_mask) + frame_image*frame_face_mask*(one_f-opacity) + frame_face_swap_img*frame_face_mask*opacity', out=out_merged_frame)
|
out_merged_frame = ne.evaluate('frame_image*(one_f-frame_face_mask) + frame_image*frame_face_mask*(one_f-opacity) + frame_face_swap_img*frame_face_mask*opacity')
|
||||||
|
|
||||||
if state.color_compression != 0:
|
if do_color_compression and state.color_compression != 0:
|
||||||
color_compression = max(4, (127.0 - state.color_compression) )
|
color_compression = max(4, (127.0 - state.color_compression) )
|
||||||
out_merged_frame *= color_compression
|
out_merged_frame *= color_compression
|
||||||
np.floor(out_merged_frame, out=out_merged_frame)
|
np.floor(out_merged_frame, out=out_merged_frame)
|
||||||
|
@ -266,7 +266,7 @@ class FaceMergerWorker(BackendWorker):
|
||||||
|
|
||||||
_n_mask_multiply_op_text = [ f"float X = {'*'.join([f'(((float)I{i}) / 255.0)' for i in range(n)])}; O = (X <= 0.5 ? 0 : 1);" for n in range(5) ]
|
_n_mask_multiply_op_text = [ f"float X = {'*'.join([f'(((float)I{i}) / 255.0)' for i in range(n)])}; O = (X <= 0.5 ? 0 : 1);" for n in range(5) ]
|
||||||
|
|
||||||
def _merge_on_gpu(self, out_merged_frame, frame_image, face_resolution, face_align_img, face_align_mask_img, face_align_lmrks_mask_img, face_swap_img, face_swap_mask_img, aligned_to_source_uni_mat, frame_width, frame_height ):
|
def _merge_on_gpu(self, frame_image, face_resolution, face_align_img, face_align_mask_img, face_align_lmrks_mask_img, face_swap_img, face_swap_mask_img, aligned_to_source_uni_mat, frame_width, frame_height, do_color_compression ):
|
||||||
state = self.get_state()
|
state = self.get_state()
|
||||||
interpolation = self._gpu_interp[state.interpolation]
|
interpolation = self._gpu_interp[state.interpolation]
|
||||||
|
|
||||||
|
@ -294,21 +294,20 @@ class FaceMergerWorker(BackendWorker):
|
||||||
frame_face_mask_t = lib_cl.remap_np_affine(face_mask_t, aligned_to_source_uni_mat, interpolation=lib_cl.EInterpolation.LINEAR, output_size=(frame_height, frame_width), post_op_text='O = (O <= (1.0/255.0) ? 0.0 : O > 1.0 ? 1.0 : O);' )
|
frame_face_mask_t = lib_cl.remap_np_affine(face_mask_t, aligned_to_source_uni_mat, interpolation=lib_cl.EInterpolation.LINEAR, output_size=(frame_height, frame_width), post_op_text='O = (O <= (1.0/255.0) ? 0.0 : O > 1.0 ? 1.0 : O);' )
|
||||||
frame_face_swap_img_t = lib_cl.remap_np_affine(face_swap_img_t, aligned_to_source_uni_mat, interpolation=interpolation, output_size=(frame_height, frame_width), post_op_text='O = clamp(O, 0.0, 1.0);' )
|
frame_face_swap_img_t = lib_cl.remap_np_affine(face_swap_img_t, aligned_to_source_uni_mat, interpolation=interpolation, output_size=(frame_height, frame_width), post_op_text='O = clamp(O, 0.0, 1.0);' )
|
||||||
|
|
||||||
frame_image_t = lib_cl.Tensor.from_value(frame_image).transpose( (2,0,1) )
|
frame_image_t = lib_cl.Tensor.from_value(frame_image).transpose( (2,0,1), op_text='O = ((float)I) / 255.0;' if frame_image.dtype == np.uint8 else None,
|
||||||
|
dtype=np.float32 if frame_image.dtype == np.uint8 else None)
|
||||||
|
|
||||||
opacity = state.face_opacity
|
opacity = state.face_opacity
|
||||||
if opacity == 1.0:
|
if opacity == 1.0:
|
||||||
frame_final_t = lib_cl.any_wise('float I0f = (((float)I0) / 255.0); O = I0f*(1.0-I1) + I2*I1', frame_image_t, frame_face_mask_t, frame_face_swap_img_t, dtype=np.float32)
|
frame_final_t = lib_cl.any_wise('O = I0*(1.0-I1) + I2*I1', frame_image_t, frame_face_mask_t, frame_face_swap_img_t, dtype=np.float32)
|
||||||
else:
|
else:
|
||||||
frame_final_t = lib_cl.any_wise('float I0f = (((float)I0) / 255.0); O = I0f*(1.0-I1) + I0f*I1*(1.0-I3) + I2*I1*I3', frame_image_t, frame_face_mask_t, frame_face_swap_img_t, np.float32(opacity), dtype=np.float32)
|
frame_final_t = lib_cl.any_wise('O = I0*(1.0-I1) + I0*I1*(1.0-I3) + I2*I1*I3', frame_image_t, frame_face_mask_t, frame_face_swap_img_t, np.float32(opacity), dtype=np.float32)
|
||||||
|
|
||||||
color_compression = state.color_compression
|
if do_color_compression and state.color_compression != 0:
|
||||||
if color_compression != 0:
|
color_compression = max(4, (127.0 - state.color_compression) )
|
||||||
color_compression = max(4, (127.0 - color_compression) )
|
|
||||||
frame_final_t = lib_cl.any_wise('O = ( floor(I0 * I1) / I1 ) + (2.0 / I1);', frame_final_t, np.float32(color_compression))
|
frame_final_t = lib_cl.any_wise('O = ( floor(I0 * I1) / I1 ) + (2.0 / I1);', frame_final_t, np.float32(color_compression))
|
||||||
|
|
||||||
frame_final_t.transpose( (1,2,0) ).np(out=out_merged_frame)
|
return frame_final_t.transpose( (1,2,0) ).np()
|
||||||
return out_merged_frame
|
|
||||||
|
|
||||||
def on_tick(self):
|
def on_tick(self):
|
||||||
state, cs = self.get_state(), self.get_control_sheet()
|
state, cs = self.get_state(), self.get_control_sheet()
|
||||||
|
@ -321,41 +320,42 @@ class FaceMergerWorker(BackendWorker):
|
||||||
bcd.assign_weak_heap(self.weak_heap)
|
bcd.assign_weak_heap(self.weak_heap)
|
||||||
|
|
||||||
frame_image_name = bcd.get_frame_image_name()
|
frame_image_name = bcd.get_frame_image_name()
|
||||||
frame_image = bcd.get_image(frame_image_name)
|
merged_frame = bcd.get_image(frame_image_name)
|
||||||
|
|
||||||
if frame_image is not None:
|
if merged_frame is not None:
|
||||||
for fsi in bcd.get_face_swap_info_list():
|
fsi_list = bcd.get_face_swap_info_list()
|
||||||
face_align_img = bcd.get_image(fsi.face_align_image_name)
|
fsi_list_len = len(fsi_list)
|
||||||
face_align_lmrks_mask_img = bcd.get_image(fsi.face_align_lmrks_mask_name)
|
has_merged_faces = False
|
||||||
face_align_mask_img = bcd.get_image(fsi.face_align_mask_name)
|
for fsi_id, fsi in enumerate(fsi_list):
|
||||||
face_swap_img = bcd.get_image(fsi.face_swap_image_name)
|
|
||||||
face_swap_mask_img = bcd.get_image(fsi.face_swap_mask_name)
|
|
||||||
image_to_align_uni_mat = fsi.image_to_align_uni_mat
|
image_to_align_uni_mat = fsi.image_to_align_uni_mat
|
||||||
|
face_resolution = fsi.face_resolution
|
||||||
|
|
||||||
face_resolution = fsi.face_resolution
|
face_align_img = bcd.get_image(fsi.face_align_image_name)
|
||||||
|
face_align_lmrks_mask_img = bcd.get_image(fsi.face_align_lmrks_mask_name)
|
||||||
|
face_align_mask_img = bcd.get_image(fsi.face_align_mask_name)
|
||||||
|
face_swap_img = bcd.get_image(fsi.face_swap_image_name)
|
||||||
|
face_swap_mask_img = bcd.get_image(fsi.face_swap_mask_name)
|
||||||
|
|
||||||
if all_is_not_None(face_resolution, face_align_img, face_align_mask_img, face_swap_img, face_swap_mask_img, image_to_align_uni_mat):
|
if all_is_not_None(face_resolution, face_align_img, face_align_mask_img, face_swap_img, face_swap_mask_img, image_to_align_uni_mat):
|
||||||
|
has_merged_faces = True
|
||||||
face_height, face_width = face_align_img.shape[:2]
|
face_height, face_width = face_align_img.shape[:2]
|
||||||
frame_height, frame_width = frame_image.shape[:2]
|
frame_height, frame_width = merged_frame.shape[:2]
|
||||||
aligned_to_source_uni_mat = image_to_align_uni_mat.invert()
|
aligned_to_source_uni_mat = image_to_align_uni_mat.invert()
|
||||||
aligned_to_source_uni_mat = aligned_to_source_uni_mat.source_translated(-state.face_x_offset, -state.face_y_offset)
|
aligned_to_source_uni_mat = aligned_to_source_uni_mat.source_translated(-state.face_x_offset, -state.face_y_offset)
|
||||||
aligned_to_source_uni_mat = aligned_to_source_uni_mat.source_scaled_around_center(state.face_scale,state.face_scale)
|
aligned_to_source_uni_mat = aligned_to_source_uni_mat.source_scaled_around_center(state.face_scale,state.face_scale)
|
||||||
aligned_to_source_uni_mat = aligned_to_source_uni_mat.to_exact_mat (face_width, face_height, frame_width, frame_height)
|
aligned_to_source_uni_mat = aligned_to_source_uni_mat.to_exact_mat (face_width, face_height, frame_width, frame_height)
|
||||||
|
|
||||||
out_merged_frame = self.out_merged_frame
|
do_color_compression = fsi_id == fsi_list_len-1
|
||||||
if out_merged_frame is None or out_merged_frame.shape[:2] != (frame_height, frame_width):
|
|
||||||
out_merged_frame = self.out_merged_frame = np.empty_like(frame_image, np.float32)
|
|
||||||
|
|
||||||
if state.device == 'CPU':
|
if state.device == 'CPU':
|
||||||
merged_frame = self._merge_on_cpu(out_merged_frame, frame_image, face_resolution, face_align_img, face_align_mask_img, face_align_lmrks_mask_img, face_swap_img, face_swap_mask_img, aligned_to_source_uni_mat, frame_width, frame_height )
|
merged_frame = self._merge_on_cpu(merged_frame, face_resolution, face_align_img, face_align_mask_img, face_align_lmrks_mask_img, face_swap_img, face_swap_mask_img, aligned_to_source_uni_mat, frame_width, frame_height, do_color_compression=do_color_compression )
|
||||||
else:
|
else:
|
||||||
merged_frame = self._merge_on_gpu(out_merged_frame, frame_image, face_resolution, face_align_img, face_align_mask_img, face_align_lmrks_mask_img, face_swap_img, face_swap_mask_img, aligned_to_source_uni_mat, frame_width, frame_height )
|
merged_frame = self._merge_on_gpu(merged_frame, face_resolution, face_align_img, face_align_mask_img, face_align_lmrks_mask_img, face_swap_img, face_swap_mask_img, aligned_to_source_uni_mat, frame_width, frame_height, do_color_compression=do_color_compression )
|
||||||
|
|
||||||
# keep image in float32 in order not to extra load FaceMerger
|
if has_merged_faces:
|
||||||
merged_image_name = f'{frame_image_name}_merged'
|
# keep image in float32 in order not to extra load FaceMerger
|
||||||
bcd.set_merged_image_name(merged_image_name)
|
merged_image_name = f'{frame_image_name}_merged'
|
||||||
bcd.set_image(merged_image_name, merged_frame)
|
bcd.set_merged_image_name(merged_image_name)
|
||||||
break
|
bcd.set_image(merged_image_name, merged_frame)
|
||||||
|
|
||||||
self.stop_profile_timing()
|
self.stop_profile_timing()
|
||||||
self.pending_bcd = bcd
|
self.pending_bcd = bcd
|
||||||
|
@ -425,3 +425,7 @@ class WorkerState(BackendWorkerState):
|
||||||
interpolation = None
|
interpolation = None
|
||||||
color_compression : int = None
|
color_compression : int = None
|
||||||
face_opacity : float = None
|
face_opacity : float = None
|
||||||
|
|
||||||
|
# out_merged_frame = self.out_merged_frame
|
||||||
|
# if out_merged_frame is None or out_merged_frame.shape[:2] != (frame_height, frame_width):
|
||||||
|
# out_merged_frame = self.out_merged_frame = np.empty_like(frame_image, np.float32)
|
||||||
|
|
|
@ -14,7 +14,9 @@ from .BackendBase import (BackendConnection, BackendDB, BackendHost,
|
||||||
|
|
||||||
|
|
||||||
class FaceSwapper(BackendHost):
|
class FaceSwapper(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):
|
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,
|
super().__init__(backend_db=backend_db,
|
||||||
sheet_cls=Sheet,
|
sheet_cls=Sheet,
|
||||||
worker_cls=FaceSwapperWorker,
|
worker_cls=FaceSwapperWorker,
|
||||||
|
@ -23,6 +25,8 @@ class FaceSwapper(BackendHost):
|
||||||
|
|
||||||
def get_control_sheet(self) -> 'Sheet.Host': return super().get_control_sheet()
|
def get_control_sheet(self) -> 'Sheet.Host': return super().get_control_sheet()
|
||||||
|
|
||||||
|
def _get_name(self):
|
||||||
|
return super()._get_name()# + f'{self._id}'
|
||||||
|
|
||||||
class FaceSwapperWorker(BackendWorker):
|
class FaceSwapperWorker(BackendWorker):
|
||||||
def get_state(self) -> 'WorkerState': return super().get_state()
|
def get_state(self) -> 'WorkerState': return super().get_state()
|
||||||
|
@ -46,6 +50,7 @@ class FaceSwapperWorker(BackendWorker):
|
||||||
|
|
||||||
cs.model.call_on_selected(self.on_cs_model_info)
|
cs.model.call_on_selected(self.on_cs_model_info)
|
||||||
cs.device.call_on_selected(self.on_cs_device)
|
cs.device.call_on_selected(self.on_cs_device)
|
||||||
|
cs.swap_all_faces.call_on_flag(self.on_cs_swap_all_faces)
|
||||||
cs.face_id.call_on_number(self.on_cs_face_id)
|
cs.face_id.call_on_number(self.on_cs_face_id)
|
||||||
cs.morph_factor.call_on_number(self.on_cs_morph_factor)
|
cs.morph_factor.call_on_number(self.on_cs_morph_factor)
|
||||||
cs.presharpen_amount.call_on_number(self.on_cs_presharpen_amount)
|
cs.presharpen_amount.call_on_number(self.on_cs_presharpen_amount)
|
||||||
|
@ -83,11 +88,28 @@ class FaceSwapperWorker(BackendWorker):
|
||||||
self.save_state()
|
self.save_state()
|
||||||
self.restart()
|
self.restart()
|
||||||
|
|
||||||
|
def on_cs_swap_all_faces(self, swap_all_faces):
|
||||||
|
state, cs = self.get_state(), self.get_control_sheet()
|
||||||
|
model_state = state.model_state
|
||||||
|
if model_state is not None:
|
||||||
|
model_state.swap_all_faces = swap_all_faces
|
||||||
|
|
||||||
|
if not swap_all_faces:
|
||||||
|
cs.face_id.enable()
|
||||||
|
cs.face_id.set_config(lib_csw.Number.Config(min=0, max=999, step=1, decimals=0, allow_instant_update=True))
|
||||||
|
cs.face_id.set_number(state.model_state.face_id if state.model_state.face_id is not None else 0)
|
||||||
|
else:
|
||||||
|
cs.face_id.disable()
|
||||||
|
|
||||||
|
self.save_state()
|
||||||
|
self.reemit_frame_signal.send()
|
||||||
|
|
||||||
|
|
||||||
def on_cs_face_id(self, face_id):
|
def on_cs_face_id(self, face_id):
|
||||||
state, cs = self.get_state(), self.get_control_sheet()
|
state, cs = self.get_state(), self.get_control_sheet()
|
||||||
model_state = state.model_state
|
model_state = state.model_state
|
||||||
cfg = cs.face_id.get_config()
|
|
||||||
if model_state is not None:
|
if model_state is not None:
|
||||||
|
cfg = cs.face_id.get_config()
|
||||||
face_id = model_state.face_id = int(np.clip(face_id, cfg.min, cfg.max))
|
face_id = model_state.face_id = int(np.clip(face_id, cfg.min, cfg.max))
|
||||||
cs.face_id.set_number(face_id)
|
cs.face_id.set_number(face_id)
|
||||||
self.save_state()
|
self.save_state()
|
||||||
|
@ -96,8 +118,8 @@ class FaceSwapperWorker(BackendWorker):
|
||||||
def on_cs_presharpen_amount(self, presharpen_amount):
|
def on_cs_presharpen_amount(self, presharpen_amount):
|
||||||
state, cs = self.get_state(), self.get_control_sheet()
|
state, cs = self.get_state(), self.get_control_sheet()
|
||||||
model_state = state.model_state
|
model_state = state.model_state
|
||||||
cfg = cs.presharpen_amount.get_config()
|
|
||||||
if model_state is not None:
|
if model_state is not None:
|
||||||
|
cfg = cs.presharpen_amount.get_config()
|
||||||
presharpen_amount = model_state.presharpen_amount = float(np.clip(presharpen_amount, cfg.min, cfg.max))
|
presharpen_amount = model_state.presharpen_amount = float(np.clip(presharpen_amount, cfg.min, cfg.max))
|
||||||
cs.presharpen_amount.set_number(presharpen_amount)
|
cs.presharpen_amount.set_number(presharpen_amount)
|
||||||
self.save_state()
|
self.save_state()
|
||||||
|
@ -106,8 +128,8 @@ class FaceSwapperWorker(BackendWorker):
|
||||||
def on_cs_morph_factor(self, morph_factor):
|
def on_cs_morph_factor(self, morph_factor):
|
||||||
state, cs = self.get_state(), self.get_control_sheet()
|
state, cs = self.get_state(), self.get_control_sheet()
|
||||||
model_state = state.model_state
|
model_state = state.model_state
|
||||||
cfg = cs.morph_factor.get_config()
|
|
||||||
if model_state is not None:
|
if model_state is not None:
|
||||||
|
cfg = cs.morph_factor.get_config()
|
||||||
morph_factor = model_state.morph_factor = float(np.clip(morph_factor, cfg.min, cfg.max))
|
morph_factor = model_state.morph_factor = float(np.clip(morph_factor, cfg.min, cfg.max))
|
||||||
cs.morph_factor.set_number(morph_factor)
|
cs.morph_factor.set_number(morph_factor)
|
||||||
self.save_state()
|
self.save_state()
|
||||||
|
@ -116,8 +138,8 @@ class FaceSwapperWorker(BackendWorker):
|
||||||
def on_cs_gamma_red(self, pre_gamma_red):
|
def on_cs_gamma_red(self, pre_gamma_red):
|
||||||
state, cs = self.get_state(), self.get_control_sheet()
|
state, cs = self.get_state(), self.get_control_sheet()
|
||||||
model_state = state.model_state
|
model_state = state.model_state
|
||||||
cfg = cs.pre_gamma_red.get_config()
|
|
||||||
if model_state is not None:
|
if model_state is not None:
|
||||||
|
cfg = cs.pre_gamma_red.get_config()
|
||||||
pre_gamma_red = model_state.pre_gamma_red = float(np.clip(pre_gamma_red, cfg.min, cfg.max))
|
pre_gamma_red = model_state.pre_gamma_red = float(np.clip(pre_gamma_red, cfg.min, cfg.max))
|
||||||
cs.pre_gamma_red.set_number(pre_gamma_red)
|
cs.pre_gamma_red.set_number(pre_gamma_red)
|
||||||
self.save_state()
|
self.save_state()
|
||||||
|
@ -126,8 +148,8 @@ class FaceSwapperWorker(BackendWorker):
|
||||||
def on_cs_pre_gamma_green(self, pre_gamma_green):
|
def on_cs_pre_gamma_green(self, pre_gamma_green):
|
||||||
state, cs = self.get_state(), self.get_control_sheet()
|
state, cs = self.get_state(), self.get_control_sheet()
|
||||||
model_state = state.model_state
|
model_state = state.model_state
|
||||||
cfg = cs.pre_gamma_green.get_config()
|
|
||||||
if model_state is not None:
|
if model_state is not None:
|
||||||
|
cfg = cs.pre_gamma_green.get_config()
|
||||||
pre_gamma_green = model_state.pre_gamma_green = float(np.clip(pre_gamma_green, cfg.min, cfg.max))
|
pre_gamma_green = model_state.pre_gamma_green = float(np.clip(pre_gamma_green, cfg.min, cfg.max))
|
||||||
cs.pre_gamma_green.set_number(pre_gamma_green)
|
cs.pre_gamma_green.set_number(pre_gamma_green)
|
||||||
self.save_state()
|
self.save_state()
|
||||||
|
@ -136,8 +158,8 @@ class FaceSwapperWorker(BackendWorker):
|
||||||
def on_cs_pre_gamma_blue(self, pre_gamma_blue):
|
def on_cs_pre_gamma_blue(self, pre_gamma_blue):
|
||||||
state, cs = self.get_state(), self.get_control_sheet()
|
state, cs = self.get_state(), self.get_control_sheet()
|
||||||
model_state = state.model_state
|
model_state = state.model_state
|
||||||
cfg = cs.pre_gamma_blue.get_config()
|
|
||||||
if model_state is not None:
|
if model_state is not None:
|
||||||
|
cfg = cs.pre_gamma_blue.get_config()
|
||||||
pre_gamma_blue = model_state.pre_gamma_blue = float(np.clip(pre_gamma_blue, cfg.min, cfg.max))
|
pre_gamma_blue = model_state.pre_gamma_blue = float(np.clip(pre_gamma_blue, cfg.min, cfg.max))
|
||||||
cs.pre_gamma_blue.set_number(pre_gamma_blue)
|
cs.pre_gamma_blue.set_number(pre_gamma_blue)
|
||||||
self.save_state()
|
self.save_state()
|
||||||
|
@ -186,9 +208,9 @@ class FaceSwapperWorker(BackendWorker):
|
||||||
'',
|
'',
|
||||||
f'@FaceSwapper.resolution',
|
f'@FaceSwapper.resolution',
|
||||||
f'{model_width}x{model_height}']) )
|
f'{model_width}x{model_height}']) )
|
||||||
cs.face_id.enable()
|
|
||||||
cs.face_id.set_config(lib_csw.Number.Config(min=0, max=16, step=1, decimals=0, allow_instant_update=True))
|
cs.swap_all_faces.enable()
|
||||||
cs.face_id.set_number(state.model_state.face_id if state.model_state.face_id is not None else 0)
|
cs.swap_all_faces.set_flag( state.model_state.swap_all_faces if state.model_state.swap_all_faces is not None else False)
|
||||||
|
|
||||||
if self.dfm_model.has_morph_value():
|
if self.dfm_model.has_morph_value():
|
||||||
cs.morph_factor.enable()
|
cs.morph_factor.enable()
|
||||||
|
@ -225,7 +247,6 @@ class FaceSwapperWorker(BackendWorker):
|
||||||
if events.download_progress is not None:
|
if events.download_progress is not None:
|
||||||
cs.model_dl_progress.set_progress(events.download_progress)
|
cs.model_dl_progress.set_progress(events.download_progress)
|
||||||
|
|
||||||
|
|
||||||
if self.pending_bcd is None:
|
if self.pending_bcd is None:
|
||||||
self.start_profile_timing()
|
self.start_profile_timing()
|
||||||
|
|
||||||
|
@ -236,41 +257,40 @@ class FaceSwapperWorker(BackendWorker):
|
||||||
model_state = state.model_state
|
model_state = state.model_state
|
||||||
dfm_model = self.dfm_model
|
dfm_model = self.dfm_model
|
||||||
if all_is_not_None(dfm_model, model_state):
|
if all_is_not_None(dfm_model, model_state):
|
||||||
face_id = model_state.face_id
|
|
||||||
if face_id is not None:
|
|
||||||
for i, fsi in enumerate(bcd.get_face_swap_info_list()):
|
|
||||||
if face_id != i:
|
|
||||||
continue
|
|
||||||
|
|
||||||
face_align_image = bcd.get_image(fsi.face_align_image_name)
|
for i, fsi in enumerate(bcd.get_face_swap_info_list()):
|
||||||
if face_align_image is not None:
|
if not model_state.swap_all_faces and model_state.face_id != i:
|
||||||
|
continue
|
||||||
|
|
||||||
pre_gamma_red = model_state.pre_gamma_red
|
face_align_image = bcd.get_image(fsi.face_align_image_name)
|
||||||
pre_gamma_green = model_state.pre_gamma_green
|
if face_align_image is not None:
|
||||||
pre_gamma_blue = model_state.pre_gamma_blue
|
|
||||||
|
|
||||||
fai_ip = ImageProcessor(face_align_image)
|
pre_gamma_red = model_state.pre_gamma_red
|
||||||
if model_state.presharpen_amount != 0:
|
pre_gamma_green = model_state.pre_gamma_green
|
||||||
fai_ip.gaussian_sharpen(sigma=1.0, power=model_state.presharpen_amount)
|
pre_gamma_blue = model_state.pre_gamma_blue
|
||||||
|
|
||||||
if pre_gamma_red != 1.0 or pre_gamma_green != 1.0 or pre_gamma_blue != 1.0:
|
fai_ip = ImageProcessor(face_align_image)
|
||||||
fai_ip.gamma(pre_gamma_red, pre_gamma_green, pre_gamma_blue)
|
if model_state.presharpen_amount != 0:
|
||||||
face_align_image = fai_ip.get_image('HWC')
|
fai_ip.gaussian_sharpen(sigma=1.0, power=model_state.presharpen_amount)
|
||||||
|
|
||||||
celeb_face, celeb_face_mask_img, face_align_mask_img = dfm_model.convert(face_align_image, morph_factor=model_state.morph_factor)
|
if pre_gamma_red != 1.0 or pre_gamma_green != 1.0 or pre_gamma_blue != 1.0:
|
||||||
celeb_face, celeb_face_mask_img, face_align_mask_img = celeb_face[0], celeb_face_mask_img[0], face_align_mask_img[0]
|
fai_ip.gamma(pre_gamma_red, pre_gamma_green, pre_gamma_blue)
|
||||||
|
face_align_image = fai_ip.get_image('HWC')
|
||||||
|
|
||||||
if model_state.two_pass:
|
celeb_face, celeb_face_mask_img, face_align_mask_img = dfm_model.convert(face_align_image, morph_factor=model_state.morph_factor)
|
||||||
celeb_face, celeb_face_mask_img, _ = dfm_model.convert(celeb_face, morph_factor=model_state.morph_factor)
|
celeb_face, celeb_face_mask_img, face_align_mask_img = celeb_face[0], celeb_face_mask_img[0], face_align_mask_img[0]
|
||||||
celeb_face, celeb_face_mask_img = celeb_face[0], celeb_face_mask_img[0]
|
|
||||||
|
|
||||||
fsi.face_align_mask_name = f'{fsi.face_align_image_name}_mask'
|
if model_state.two_pass:
|
||||||
fsi.face_swap_image_name = f'{fsi.face_align_image_name}_swapped'
|
celeb_face, celeb_face_mask_img, _ = dfm_model.convert(celeb_face, morph_factor=model_state.morph_factor)
|
||||||
fsi.face_swap_mask_name = f'{fsi.face_swap_image_name}_mask'
|
celeb_face, celeb_face_mask_img = celeb_face[0], celeb_face_mask_img[0]
|
||||||
|
|
||||||
bcd.set_image(fsi.face_align_mask_name, face_align_mask_img)
|
fsi.face_align_mask_name = f'{fsi.face_align_image_name}_mask'
|
||||||
bcd.set_image(fsi.face_swap_image_name, celeb_face)
|
fsi.face_swap_image_name = f'{fsi.face_align_image_name}_swapped'
|
||||||
bcd.set_image(fsi.face_swap_mask_name, celeb_face_mask_img)
|
fsi.face_swap_mask_name = f'{fsi.face_swap_image_name}_mask'
|
||||||
|
|
||||||
|
bcd.set_image(fsi.face_align_mask_name, face_align_mask_img)
|
||||||
|
bcd.set_image(fsi.face_swap_image_name, celeb_face)
|
||||||
|
bcd.set_image(fsi.face_swap_mask_name, celeb_face_mask_img)
|
||||||
|
|
||||||
self.stop_profile_timing()
|
self.stop_profile_timing()
|
||||||
self.pending_bcd = bcd
|
self.pending_bcd = bcd
|
||||||
|
@ -291,6 +311,7 @@ class Sheet:
|
||||||
self.model_dl_progress = lib_csw.Progress.Client()
|
self.model_dl_progress = lib_csw.Progress.Client()
|
||||||
self.model_dl_error = lib_csw.Error.Client()
|
self.model_dl_error = lib_csw.Error.Client()
|
||||||
self.device = lib_csw.DynamicSingleSwitch.Client()
|
self.device = lib_csw.DynamicSingleSwitch.Client()
|
||||||
|
self.swap_all_faces = lib_csw.Flag.Client()
|
||||||
self.face_id = lib_csw.Number.Client()
|
self.face_id = lib_csw.Number.Client()
|
||||||
self.morph_factor = lib_csw.Number.Client()
|
self.morph_factor = lib_csw.Number.Client()
|
||||||
self.presharpen_amount = lib_csw.Number.Client()
|
self.presharpen_amount = lib_csw.Number.Client()
|
||||||
|
@ -307,6 +328,7 @@ class Sheet:
|
||||||
self.model_dl_progress = lib_csw.Progress.Host()
|
self.model_dl_progress = lib_csw.Progress.Host()
|
||||||
self.model_dl_error = lib_csw.Error.Host()
|
self.model_dl_error = lib_csw.Error.Host()
|
||||||
self.device = lib_csw.DynamicSingleSwitch.Host()
|
self.device = lib_csw.DynamicSingleSwitch.Host()
|
||||||
|
self.swap_all_faces = lib_csw.Flag.Host()
|
||||||
self.face_id = lib_csw.Number.Host()
|
self.face_id = lib_csw.Number.Host()
|
||||||
self.morph_factor = lib_csw.Number.Host()
|
self.morph_factor = lib_csw.Number.Host()
|
||||||
self.presharpen_amount = lib_csw.Number.Host()
|
self.presharpen_amount = lib_csw.Number.Host()
|
||||||
|
@ -317,6 +339,7 @@ class Sheet:
|
||||||
|
|
||||||
class ModelState(BackendWorkerState):
|
class ModelState(BackendWorkerState):
|
||||||
device = None
|
device = None
|
||||||
|
swap_all_faces : bool = None
|
||||||
face_id : int = None
|
face_id : int = None
|
||||||
morph_factor : float = None
|
morph_factor : float = None
|
||||||
presharpen_amount : float = None
|
presharpen_amount : float = None
|
||||||
|
|
|
@ -39,6 +39,9 @@ class QFaceSwapper(QBackendPanel):
|
||||||
q_device_label = QLabelPopupInfo(label=L('@QFaceSwapper.device'), popup_info_text=L('@QFaceSwapper.help.device') )
|
q_device_label = QLabelPopupInfo(label=L('@QFaceSwapper.device'), popup_info_text=L('@QFaceSwapper.help.device') )
|
||||||
q_device = QComboBoxCSWDynamicSingleSwitch(cs.device, reflect_state_widgets=[q_device_label])
|
q_device = QComboBoxCSWDynamicSingleSwitch(cs.device, reflect_state_widgets=[q_device_label])
|
||||||
|
|
||||||
|
q_swap_all_faces_label = QLabelPopupInfo(label=L('@QFaceSwapper.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('@QFaceSwapper.face_id'), popup_info_text=L('@QFaceSwapper.help.face_id') )
|
||||||
q_face_id = QSpinBoxCSWNumber(cs.face_id, reflect_state_widgets=[q_face_id_label])
|
q_face_id = QSpinBoxCSWNumber(cs.face_id, reflect_state_widgets=[q_face_id_label])
|
||||||
|
|
||||||
|
@ -69,8 +72,8 @@ class QFaceSwapper(QBackendPanel):
|
||||||
grid_l.addWidget(q_device_label, row, 0, alignment=Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter )
|
grid_l.addWidget(q_device_label, row, 0, alignment=Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter )
|
||||||
grid_l.addWidget(q_device, row, 1, alignment=Qt.AlignmentFlag.AlignLeft )
|
grid_l.addWidget(q_device, row, 1, alignment=Qt.AlignmentFlag.AlignLeft )
|
||||||
row += 1
|
row += 1
|
||||||
grid_l.addWidget(q_face_id_label, row, 0, alignment=Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter )
|
grid_l.addWidget( q_swap_all_faces_label, row, 0, alignment=Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter )
|
||||||
grid_l.addWidget(q_face_id, row, 1, alignment=Qt.AlignmentFlag.AlignLeft )
|
grid_l.addLayout( lib_qt.QXHBoxLayout([q_swap_all_faces, 4, q_face_id_label, 4, q_face_id ]), row, 1, alignment=Qt.AlignmentFlag.AlignLeft )
|
||||||
row += 1
|
row += 1
|
||||||
grid_l.addWidget(q_morph_factor_label, row, 0, alignment=Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter )
|
grid_l.addWidget(q_morph_factor_label, row, 0, alignment=Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter )
|
||||||
grid_l.addWidget(q_morph_factor, row, 1)
|
grid_l.addWidget(q_morph_factor, row, 1)
|
||||||
|
|
|
@ -10,7 +10,7 @@ from xlib import qt as lib_qt
|
||||||
from ... import backend
|
from ... import backend
|
||||||
|
|
||||||
|
|
||||||
class QBCFinalFrameViewer(lib_qt.QXCollapsibleSection):
|
class QBCMergedFrameViewer(lib_qt.QXCollapsibleSection):
|
||||||
def __init__(self, backed_weak_heap : backend.BackendWeakHeap,
|
def __init__(self, backed_weak_heap : backend.BackendWeakHeap,
|
||||||
bc : backend.BackendConnection,
|
bc : backend.BackendConnection,
|
||||||
preview_width=256):
|
preview_width=256):
|
||||||
|
@ -27,7 +27,7 @@ class QBCFinalFrameViewer(lib_qt.QXCollapsibleSection):
|
||||||
main_l = lib_qt.QXVBoxLayout([ (layered_images, Qt.AlignmentFlag.AlignCenter),
|
main_l = lib_qt.QXVBoxLayout([ (layered_images, Qt.AlignmentFlag.AlignCenter),
|
||||||
(info_label, Qt.AlignmentFlag.AlignCenter),
|
(info_label, Qt.AlignmentFlag.AlignCenter),
|
||||||
], spacing=0)
|
], spacing=0)
|
||||||
super().__init__(title=L('@QBCFinalFrameViewer.title'), content_layout=main_l)
|
super().__init__(title=L('@QBCMergedFrameViewer.title'), content_layout=main_l)
|
||||||
|
|
||||||
def _on_timer_16ms(self):
|
def _on_timer_16ms(self):
|
||||||
top_qx = self.get_top_QXWindow()
|
top_qx = self.get_top_QXWindow()
|
|
@ -427,6 +427,11 @@ class Localization:
|
||||||
'ru-RU' : 'Настройте комбинации устройств модулей для достижения высоких кадр/сек либо снижения нагрузки на процессор.',
|
'ru-RU' : 'Настройте комбинации устройств модулей для достижения высоких кадр/сек либо снижения нагрузки на процессор.',
|
||||||
'zh-CN' : '调整模块设备的组合以实现更高的fps或更低的CPU使用率'},
|
'zh-CN' : '调整模块设备的组合以实现更高的fps或更低的CPU使用率'},
|
||||||
|
|
||||||
|
'QFaceSwapper.swap_all_faces':{
|
||||||
|
'en-US' : 'Swap all faces',
|
||||||
|
'ru-RU' : 'Заменить все лица',
|
||||||
|
'zh-CN' : '改变所有面孔'},
|
||||||
|
|
||||||
'QFaceSwapper.face_id':{
|
'QFaceSwapper.face_id':{
|
||||||
'en-US' : 'Face ID',
|
'en-US' : 'Face ID',
|
||||||
'ru-RU' : 'Номер лица',
|
'ru-RU' : 'Номер лица',
|
||||||
|
@ -652,10 +657,10 @@ class Localization:
|
||||||
'ru-RU' : 'Заменённое лицо',
|
'ru-RU' : 'Заменённое лицо',
|
||||||
'zh-CN' : '换后的脸'},
|
'zh-CN' : '换后的脸'},
|
||||||
|
|
||||||
'QBCFinalFrameViewer.title':{
|
'QBCMergedFrameViewer.title':{
|
||||||
'en-US' : 'Final frame',
|
'en-US' : 'Merged frame',
|
||||||
'ru-RU' : 'Финальный кадр',
|
'ru-RU' : 'Склеенный кадр',
|
||||||
'zh-CN' : '结果'},
|
'zh-CN' : '合成后的画面'},
|
||||||
|
|
||||||
'FileSource.image_folder':{
|
'FileSource.image_folder':{
|
||||||
'en-US' : 'Image folder',
|
'en-US' : 'Image folder',
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue