From 6311a12c630397c187794a9de8ac3c89aa56d67c Mon Sep 17 00:00:00 2001 From: iperov Date: Thu, 18 Nov 2021 18:41:28 +0400 Subject: [PATCH] refactoring, FaceSwapper now can swap all faces --- apps/DeepFaceLive/DeepFaceLiveApp.py | 4 +- apps/DeepFaceLive/backend/FaceMerger.py | 72 +++++++------ apps/DeepFaceLive/backend/FaceSwapper.py | 101 +++++++++++------- apps/DeepFaceLive/ui/QFaceSwapper.py | 7 +- ...FrameViewer.py => QBCMergedFrameViewer.py} | 4 +- localization/localization.py | 15 ++- 6 files changed, 119 insertions(+), 84 deletions(-) rename apps/DeepFaceLive/ui/widgets/{QBCFinalFrameViewer.py => QBCMergedFrameViewer.py} (93%) diff --git a/apps/DeepFaceLive/DeepFaceLiveApp.py b/apps/DeepFaceLive/DeepFaceLiveApp.py index 30862e0..19a43b9 100644 --- a/apps/DeepFaceLive/DeepFaceLiveApp.py +++ b/apps/DeepFaceLive/DeepFaceLiveApp.py @@ -23,7 +23,7 @@ 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.QBCFinalFrameViewer import QBCFinalFrameViewer +from .ui.widgets.QBCMergedFrameViewer import QBCMergedFrameViewer 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_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_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), layout=lib_qt.QXHBoxLayout([ diff --git a/apps/DeepFaceLive/backend/FaceMerger.py b/apps/DeepFaceLive/backend/FaceMerger.py index 7e2cb6f..4eab0f2 100644 --- a/apps/DeepFaceLive/backend/FaceMerger.py +++ b/apps/DeepFaceLive/backend/FaceMerger.py @@ -208,7 +208,7 @@ class FaceMergerWorker(BackendWorker): _cpu_interp = {'bilinear' : ImageProcessor.Interpolation.LINEAR, 'bicubic' : ImageProcessor.Interpolation.CUBIC, '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() interpolation = self._cpu_interp[state.interpolation] @@ -247,11 +247,11 @@ class FaceMergerWorker(BackendWorker): opacity = np.float32(state.face_opacity) one_f = np.float32(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: - 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) ) out_merged_frame *= color_compression 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) ] - 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() 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_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 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: - 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 color_compression != 0: - color_compression = max(4, (127.0 - color_compression) ) + if do_color_compression and state.color_compression != 0: + color_compression = max(4, (127.0 - state.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 out_merged_frame + return frame_final_t.transpose( (1,2,0) ).np() def on_tick(self): state, cs = self.get_state(), self.get_control_sheet() @@ -321,41 +320,42 @@ class FaceMergerWorker(BackendWorker): bcd.assign_weak_heap(self.weak_heap) 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: - for fsi in bcd.get_face_swap_info_list(): - 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 merged_frame is not None: + fsi_list = bcd.get_face_swap_info_list() + fsi_list_len = len(fsi_list) + has_merged_faces = False + for fsi_id, fsi in enumerate(fsi_list): 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): + has_merged_faces = True 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 = 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.to_exact_mat (face_width, face_height, frame_width, frame_height) - 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) - + do_color_compression = fsi_id == fsi_list_len-1 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: - 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 - merged_image_name = f'{frame_image_name}_merged' - bcd.set_merged_image_name(merged_image_name) - bcd.set_image(merged_image_name, merged_frame) - break + if has_merged_faces: + # keep image in float32 in order not to extra load FaceMerger + merged_image_name = f'{frame_image_name}_merged' + bcd.set_merged_image_name(merged_image_name) + bcd.set_image(merged_image_name, merged_frame) self.stop_profile_timing() self.pending_bcd = bcd @@ -425,3 +425,7 @@ class WorkerState(BackendWorkerState): interpolation = None color_compression : int = 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) diff --git a/apps/DeepFaceLive/backend/FaceSwapper.py b/apps/DeepFaceLive/backend/FaceSwapper.py index bd8fbc9..5ccde8c 100644 --- a/apps/DeepFaceLive/backend/FaceSwapper.py +++ b/apps/DeepFaceLive/backend/FaceSwapper.py @@ -14,7 +14,9 @@ from .BackendBase import (BackendConnection, BackendDB, 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, sheet_cls=Sheet, 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]) 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): 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.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.morph_factor.call_on_number(self.on_cs_morph_factor) cs.presharpen_amount.call_on_number(self.on_cs_presharpen_amount) @@ -83,11 +88,28 @@ class FaceSwapperWorker(BackendWorker): self.save_state() 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): state, cs = self.get_state(), self.get_control_sheet() model_state = state.model_state - cfg = cs.face_id.get_config() 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)) cs.face_id.set_number(face_id) self.save_state() @@ -96,8 +118,8 @@ class FaceSwapperWorker(BackendWorker): def on_cs_presharpen_amount(self, presharpen_amount): state, cs = self.get_state(), self.get_control_sheet() model_state = state.model_state - cfg = cs.presharpen_amount.get_config() 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)) cs.presharpen_amount.set_number(presharpen_amount) self.save_state() @@ -106,8 +128,8 @@ class FaceSwapperWorker(BackendWorker): def on_cs_morph_factor(self, morph_factor): state, cs = self.get_state(), self.get_control_sheet() model_state = state.model_state - cfg = cs.morph_factor.get_config() 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)) cs.morph_factor.set_number(morph_factor) self.save_state() @@ -116,8 +138,8 @@ class FaceSwapperWorker(BackendWorker): def on_cs_gamma_red(self, pre_gamma_red): state, cs = self.get_state(), self.get_control_sheet() model_state = state.model_state - cfg = cs.pre_gamma_red.get_config() 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)) cs.pre_gamma_red.set_number(pre_gamma_red) self.save_state() @@ -126,8 +148,8 @@ class FaceSwapperWorker(BackendWorker): def on_cs_pre_gamma_green(self, pre_gamma_green): state, cs = self.get_state(), self.get_control_sheet() model_state = state.model_state - cfg = cs.pre_gamma_green.get_config() 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)) cs.pre_gamma_green.set_number(pre_gamma_green) self.save_state() @@ -136,8 +158,8 @@ class FaceSwapperWorker(BackendWorker): def on_cs_pre_gamma_blue(self, pre_gamma_blue): state, cs = self.get_state(), self.get_control_sheet() model_state = state.model_state - cfg = cs.pre_gamma_blue.get_config() 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)) cs.pre_gamma_blue.set_number(pre_gamma_blue) self.save_state() @@ -186,9 +208,9 @@ class FaceSwapperWorker(BackendWorker): '', f'@FaceSwapper.resolution', 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.face_id.set_number(state.model_state.face_id if state.model_state.face_id is not None else 0) + + cs.swap_all_faces.enable() + 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(): cs.morph_factor.enable() @@ -225,7 +247,6 @@ class FaceSwapperWorker(BackendWorker): if events.download_progress is not None: cs.model_dl_progress.set_progress(events.download_progress) - if self.pending_bcd is None: self.start_profile_timing() @@ -236,41 +257,40 @@ class FaceSwapperWorker(BackendWorker): model_state = state.model_state dfm_model = self.dfm_model 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) - if face_align_image is not None: + for i, fsi in enumerate(bcd.get_face_swap_info_list()): + if not model_state.swap_all_faces and model_state.face_id != i: + continue - pre_gamma_red = model_state.pre_gamma_red - pre_gamma_green = model_state.pre_gamma_green - pre_gamma_blue = model_state.pre_gamma_blue + face_align_image = bcd.get_image(fsi.face_align_image_name) + if face_align_image is not None: - fai_ip = ImageProcessor(face_align_image) - if model_state.presharpen_amount != 0: - fai_ip.gaussian_sharpen(sigma=1.0, power=model_state.presharpen_amount) + pre_gamma_red = model_state.pre_gamma_red + pre_gamma_green = model_state.pre_gamma_green + 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.gamma(pre_gamma_red, pre_gamma_green, pre_gamma_blue) - face_align_image = fai_ip.get_image('HWC') + fai_ip = ImageProcessor(face_align_image) + if model_state.presharpen_amount != 0: + 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) - celeb_face, celeb_face_mask_img, face_align_mask_img = celeb_face[0], celeb_face_mask_img[0], face_align_mask_img[0] + if pre_gamma_red != 1.0 or pre_gamma_green != 1.0 or pre_gamma_blue != 1.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, _ = dfm_model.convert(celeb_face, morph_factor=model_state.morph_factor) - celeb_face, celeb_face_mask_img = celeb_face[0], celeb_face_mask_img[0] + 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, face_align_mask_img = celeb_face[0], celeb_face_mask_img[0], face_align_mask_img[0] - 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' + if model_state.two_pass: + celeb_face, celeb_face_mask_img, _ = dfm_model.convert(celeb_face, morph_factor=model_state.morph_factor) + 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) - bcd.set_image(fsi.face_swap_image_name, celeb_face) - bcd.set_image(fsi.face_swap_mask_name, celeb_face_mask_img) + 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_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.pending_bcd = bcd @@ -291,6 +311,7 @@ class Sheet: self.model_dl_progress = lib_csw.Progress.Client() self.model_dl_error = lib_csw.Error.Client() self.device = lib_csw.DynamicSingleSwitch.Client() + self.swap_all_faces = lib_csw.Flag.Client() self.face_id = lib_csw.Number.Client() self.morph_factor = 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_error = lib_csw.Error.Host() self.device = lib_csw.DynamicSingleSwitch.Host() + self.swap_all_faces = lib_csw.Flag.Host() self.face_id = lib_csw.Number.Host() self.morph_factor = lib_csw.Number.Host() self.presharpen_amount = lib_csw.Number.Host() @@ -317,6 +339,7 @@ class Sheet: class ModelState(BackendWorkerState): device = None + swap_all_faces : bool = None face_id : int = None morph_factor : float = None presharpen_amount : float = None diff --git a/apps/DeepFaceLive/ui/QFaceSwapper.py b/apps/DeepFaceLive/ui/QFaceSwapper.py index ea427ec..e528ac8 100644 --- a/apps/DeepFaceLive/ui/QFaceSwapper.py +++ b/apps/DeepFaceLive/ui/QFaceSwapper.py @@ -39,6 +39,9 @@ class QFaceSwapper(QBackendPanel): 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_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 = 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, row, 1, alignment=Qt.AlignmentFlag.AlignLeft ) row += 1 - grid_l.addWidget(q_face_id_label, row, 0, alignment=Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter ) - grid_l.addWidget(q_face_id, row, 1, alignment=Qt.AlignmentFlag.AlignLeft ) + grid_l.addWidget( q_swap_all_faces_label, row, 0, alignment=Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter ) + 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 grid_l.addWidget(q_morph_factor_label, row, 0, alignment=Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter ) grid_l.addWidget(q_morph_factor, row, 1) diff --git a/apps/DeepFaceLive/ui/widgets/QBCFinalFrameViewer.py b/apps/DeepFaceLive/ui/widgets/QBCMergedFrameViewer.py similarity index 93% rename from apps/DeepFaceLive/ui/widgets/QBCFinalFrameViewer.py rename to apps/DeepFaceLive/ui/widgets/QBCMergedFrameViewer.py index 0e8765d..8d385c2 100644 --- a/apps/DeepFaceLive/ui/widgets/QBCFinalFrameViewer.py +++ b/apps/DeepFaceLive/ui/widgets/QBCMergedFrameViewer.py @@ -10,7 +10,7 @@ from xlib import qt as lib_qt from ... import backend -class QBCFinalFrameViewer(lib_qt.QXCollapsibleSection): +class QBCMergedFrameViewer(lib_qt.QXCollapsibleSection): def __init__(self, backed_weak_heap : backend.BackendWeakHeap, bc : backend.BackendConnection, preview_width=256): @@ -27,7 +27,7 @@ class QBCFinalFrameViewer(lib_qt.QXCollapsibleSection): main_l = lib_qt.QXVBoxLayout([ (layered_images, Qt.AlignmentFlag.AlignCenter), (info_label, Qt.AlignmentFlag.AlignCenter), ], 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): top_qx = self.get_top_QXWindow() diff --git a/localization/localization.py b/localization/localization.py index 552dd11..5200419 100644 --- a/localization/localization.py +++ b/localization/localization.py @@ -426,7 +426,12 @@ class Localization: 'en-US' : 'Adjust the combination of module devices to achieve higher fps or lower CPU usage.', 'ru-RU' : 'Настройте комбинации устройств модулей для достижения высоких кадр/сек либо снижения нагрузки на процессор.', 'zh-CN' : '调整模块设备的组合以实现更高的fps或更低的CPU使用率'}, - + + 'QFaceSwapper.swap_all_faces':{ + 'en-US' : 'Swap all faces', + 'ru-RU' : 'Заменить все лица', + 'zh-CN' : '改变所有面孔'}, + 'QFaceSwapper.face_id':{ 'en-US' : 'Face ID', 'ru-RU' : 'Номер лица', @@ -652,10 +657,10 @@ class Localization: 'ru-RU' : 'Заменённое лицо', 'zh-CN' : '换后的脸'}, - 'QBCFinalFrameViewer.title':{ - 'en-US' : 'Final frame', - 'ru-RU' : 'Финальный кадр', - 'zh-CN' : '结果'}, + 'QBCMergedFrameViewer.title':{ + 'en-US' : 'Merged frame', + 'ru-RU' : 'Склеенный кадр', + 'zh-CN' : '合成后的画面'}, 'FileSource.image_folder':{ 'en-US' : 'Image folder',