refactoring, FaceSwapper now can swap all faces

This commit is contained in:
iperov 2021-11-18 18:41:28 +04:00
parent c0efaa1900
commit 6311a12c63
6 changed files with 119 additions and 84 deletions

View file

@ -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([

View file

@ -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)

View file

@ -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,
@ -22,7 +24,9 @@ class FaceSwapper(BackendHost):
worker_start_args=[weak_heap, reemit_frame_signal, bc_in, bc_out, dfm_models_path]) worker_start_args=[weak_heap, reemit_frame_signal, bc_in, bc_out, dfm_models_path])
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

View file

@ -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)

View file

@ -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()

View file

@ -426,7 +426,12 @@ class Localization:
'en-US' : 'Adjust the combination of module devices to achieve higher fps or lower CPU usage.', 'en-US' : 'Adjust the combination of module devices to achieve higher fps or lower CPU usage.',
'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',