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

View file

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

View file

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

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

View file

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

View file

@ -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',