diff --git a/facefusion/face_masker.py b/facefusion/face_masker.py index 6ebcdab..400838d 100755 --- a/facefusion/face_masker.py +++ b/facefusion/face_masker.py @@ -3,7 +3,6 @@ from typing import List, Tuple import cv2 import numpy -from cv2.typing import Size import facefusion.choices from facefusion import inference_manager, state_manager @@ -156,8 +155,8 @@ def pre_check() -> bool: return conditional_download_hashes(model_hash_set) and conditional_download_sources(model_source_set) -@lru_cache(maxsize = None) -def create_static_box_mask(crop_size : Size, face_mask_blur : float, face_mask_padding : Padding) -> Mask: +def create_box_mask(crop_vision_frame : VisionFrame, face_mask_blur : float, face_mask_padding : Padding) -> Mask: + crop_size = crop_vision_frame.shape[:2][::-1] blur_amount = int(crop_size[0] * 0.5 * face_mask_blur) blur_area = max(blur_amount // 2, 1) box_mask : Mask = numpy.ones(crop_size).astype(numpy.float32) @@ -165,6 +164,7 @@ def create_static_box_mask(crop_size : Size, face_mask_blur : float, face_mask_p box_mask[-max(blur_area, int(crop_size[1] * face_mask_padding[2] / 100)):, :] = 0 box_mask[:, :max(blur_area, int(crop_size[0] * face_mask_padding[3] / 100))] = 0 box_mask[:, -max(blur_area, int(crop_size[0] * face_mask_padding[1] / 100)):] = 0 + if blur_amount > 0: box_mask = cv2.GaussianBlur(box_mask, (0, 0), blur_amount * 0.25) return box_mask @@ -183,7 +183,8 @@ def create_occlusion_mask(crop_vision_frame : VisionFrame) -> Mask: return occlusion_mask -def create_area_mask(face_landmark_68 : FaceLandmark68, face_mask_areas : List[FaceMaskArea]) -> Mask: +def create_area_mask(crop_vision_frame : VisionFrame, face_landmark_68 : FaceLandmark68, face_mask_areas : List[FaceMaskArea]) -> Mask: + crop_size = crop_vision_frame.shape[:2][::-1] landmark_points = [] for face_mask_area in face_mask_areas: @@ -191,7 +192,7 @@ def create_area_mask(face_landmark_68 : FaceLandmark68, face_mask_areas : List[F landmark_points.extend(facefusion.choices.face_mask_area_set.get(face_mask_area)) convex_hull = cv2.convexHull(face_landmark_68[landmark_points].astype(numpy.int32)) - area_mask = numpy.zeros((512, 512)).astype(numpy.float32) + area_mask = numpy.zeros(crop_size).astype(numpy.float32) cv2.fillConvexPoly(area_mask, convex_hull, 1.0) # type: ignore[call-overload] area_mask = (cv2.GaussianBlur(area_mask.clip(0, 1), (0, 0), 5).clip(0.5, 1) - 0.5) * 2 return area_mask diff --git a/facefusion/processors/modules/age_modifier.py b/facefusion/processors/modules/age_modifier.py index 4719744..0ed6725 100755 --- a/facefusion/processors/modules/age_modifier.py +++ b/facefusion/processors/modules/age_modifier.py @@ -15,7 +15,7 @@ from facefusion.download import conditional_download_hashes, conditional_downloa from facefusion.execution import has_execution_provider from facefusion.face_analyser import get_many_faces, get_one_face from facefusion.face_helper import merge_matrix, paste_back, scale_face_landmark_5, warp_face_by_face_landmark_5 -from facefusion.face_masker import create_occlusion_mask, create_static_box_mask +from facefusion.face_masker import create_box_mask, create_occlusion_mask from facefusion.face_selector import find_similar_faces, sort_and_filter_faces from facefusion.face_store import get_reference_faces from facefusion.filesystem import in_directory, is_image, is_video, resolve_relative_path, same_file_extension @@ -135,7 +135,7 @@ def modify_age(target_face : Face, temp_vision_frame : VisionFrame) -> VisionFra extend_face_landmark_5 = scale_face_landmark_5(face_landmark_5, 0.875) extend_vision_frame, extend_affine_matrix = warp_face_by_face_landmark_5(temp_vision_frame, extend_face_landmark_5, model_templates.get('target_with_background'), model_sizes.get('target_with_background')) extend_vision_frame_raw = extend_vision_frame.copy() - box_mask = create_static_box_mask(model_sizes.get('target_with_background'), state_manager.get_item('face_mask_blur'), (0, 0, 0, 0)) + box_mask = create_box_mask(extend_vision_frame, state_manager.get_item('face_mask_blur'), (0, 0, 0, 0)) crop_masks =\ [ box_mask diff --git a/facefusion/processors/modules/deep_swapper.py b/facefusion/processors/modules/deep_swapper.py index 54438c7..1b1b35e 100755 --- a/facefusion/processors/modules/deep_swapper.py +++ b/facefusion/processors/modules/deep_swapper.py @@ -14,7 +14,7 @@ from facefusion.common_helper import create_int_metavar from facefusion.download import conditional_download_hashes, conditional_download_sources, resolve_download_url_by_provider from facefusion.face_analyser import get_many_faces, get_one_face from facefusion.face_helper import paste_back, warp_face_by_face_landmark_5 -from facefusion.face_masker import create_occlusion_mask, create_region_mask, create_static_box_mask +from facefusion.face_masker import create_area_mask, create_box_mask, create_occlusion_mask, create_region_mask from facefusion.face_selector import find_similar_faces, sort_and_filter_faces from facefusion.face_store import get_reference_faces from facefusion.filesystem import get_file_name, in_directory, is_image, is_video, resolve_file_paths, resolve_relative_path, same_file_extension @@ -328,7 +328,7 @@ def swap_face(target_face : Face, temp_vision_frame : VisionFrame) -> VisionFram model_size = get_model_size() crop_vision_frame, affine_matrix = warp_face_by_face_landmark_5(temp_vision_frame, target_face.landmark_set.get('5/68'), model_template, model_size) crop_vision_frame_raw = crop_vision_frame.copy() - box_mask = create_static_box_mask(crop_vision_frame.shape[:2][::-1], state_manager.get_item('face_mask_blur'), state_manager.get_item('face_mask_padding')) + box_mask = create_box_mask(crop_vision_frame, state_manager.get_item('face_mask_blur'), state_manager.get_item('face_mask_padding')) crop_masks =\ [ box_mask @@ -345,6 +345,11 @@ def swap_face(target_face : Face, temp_vision_frame : VisionFrame) -> VisionFram crop_vision_frame = conditional_match_frame_color(crop_vision_frame_raw, crop_vision_frame) crop_masks.append(prepare_crop_mask(crop_source_mask, crop_target_mask)) + if 'area' in state_manager.get_item('face_mask_types'): + face_landmark_68 = cv2.transform(target_face.landmark_set.get('68').reshape(1, -1, 2), affine_matrix).reshape(-1, 2) + area_mask = create_area_mask(crop_vision_frame, face_landmark_68, state_manager.get_item('face_mask_areas')) + crop_masks.append(area_mask) + if 'region' in state_manager.get_item('face_mask_types'): region_mask = create_region_mask(crop_vision_frame, state_manager.get_item('face_mask_regions')) crop_masks.append(region_mask) diff --git a/facefusion/processors/modules/expression_restorer.py b/facefusion/processors/modules/expression_restorer.py index 0e307dd..12ebc87 100755 --- a/facefusion/processors/modules/expression_restorer.py +++ b/facefusion/processors/modules/expression_restorer.py @@ -13,7 +13,7 @@ from facefusion.common_helper import create_int_metavar from facefusion.download import conditional_download_hashes, conditional_download_sources, resolve_download_url from facefusion.face_analyser import get_many_faces, get_one_face from facefusion.face_helper import paste_back, warp_face_by_face_landmark_5 -from facefusion.face_masker import create_occlusion_mask, create_static_box_mask +from facefusion.face_masker import create_box_mask, create_occlusion_mask from facefusion.face_selector import find_similar_faces, sort_and_filter_faces from facefusion.face_store import get_reference_faces from facefusion.filesystem import in_directory, is_image, is_video, resolve_relative_path, same_file_extension @@ -148,7 +148,7 @@ def restore_expression(source_vision_frame : VisionFrame, target_face : Face, te source_vision_frame = cv2.resize(source_vision_frame, temp_vision_frame.shape[:2][::-1]) source_crop_vision_frame, _ = warp_face_by_face_landmark_5(source_vision_frame, target_face.landmark_set.get('5/68'), model_template, model_size) target_crop_vision_frame, affine_matrix = warp_face_by_face_landmark_5(temp_vision_frame, target_face.landmark_set.get('5/68'), model_template, model_size) - box_mask = create_static_box_mask(target_crop_vision_frame.shape[:2][::-1], state_manager.get_item('face_mask_blur'), (0, 0, 0, 0)) + box_mask = create_box_mask(target_crop_vision_frame, state_manager.get_item('face_mask_blur'), (0, 0, 0, 0)) crop_masks =\ [ box_mask diff --git a/facefusion/processors/modules/face_debugger.py b/facefusion/processors/modules/face_debugger.py index 5f9df93..2402182 100755 --- a/facefusion/processors/modules/face_debugger.py +++ b/facefusion/processors/modules/face_debugger.py @@ -10,7 +10,7 @@ import facefusion.processors.core as processors from facefusion import config, content_analyser, face_classifier, face_detector, face_landmarker, face_masker, face_recognizer, logger, process_manager, state_manager, video_manager, wording from facefusion.face_analyser import get_many_faces, get_one_face from facefusion.face_helper import warp_face_by_face_landmark_5 -from facefusion.face_masker import create_area_mask, create_occlusion_mask, create_region_mask, create_static_box_mask +from facefusion.face_masker import create_area_mask, create_box_mask, create_occlusion_mask, create_region_mask from facefusion.face_selector import find_similar_faces, sort_and_filter_faces from facefusion.face_store import get_reference_faces from facefusion.filesystem import in_directory, same_file_extension @@ -97,7 +97,7 @@ def debug_face(target_face : Face, temp_vision_frame : VisionFrame) -> VisionFra crop_masks = [] if 'box' in state_manager.get_item('face_mask_types'): - box_mask = create_static_box_mask(crop_vision_frame.shape[:2][::-1], 0, state_manager.get_item('face_mask_padding')) + box_mask = create_box_mask(crop_vision_frame, 0, state_manager.get_item('face_mask_padding')) crop_masks.append(box_mask) if 'occlusion' in state_manager.get_item('face_mask_types'): @@ -105,8 +105,8 @@ def debug_face(target_face : Face, temp_vision_frame : VisionFrame) -> VisionFra crop_masks.append(occlusion_mask) if 'area' in state_manager.get_item('face_mask_types'): - landmarks_68 = cv2.transform(target_face.landmark_set.get('68').reshape(1, -1, 2), affine_matrix).reshape(-1, 2) - area_mask = create_area_mask(landmarks_68, state_manager.get_item('face_mask_areas')) + face_landmark_68 = cv2.transform(target_face.landmark_set.get('68').reshape(1, -1, 2), affine_matrix).reshape(-1, 2) + area_mask = create_area_mask(crop_vision_frame, face_landmark_68, state_manager.get_item('face_mask_areas')) crop_masks.append(area_mask) if 'region' in state_manager.get_item('face_mask_types'): diff --git a/facefusion/processors/modules/face_editor.py b/facefusion/processors/modules/face_editor.py index 2414d14..f567b87 100755 --- a/facefusion/processors/modules/face_editor.py +++ b/facefusion/processors/modules/face_editor.py @@ -13,7 +13,7 @@ from facefusion.common_helper import create_float_metavar from facefusion.download import conditional_download_hashes, conditional_download_sources, resolve_download_url from facefusion.face_analyser import get_many_faces, get_one_face from facefusion.face_helper import paste_back, scale_face_landmark_5, warp_face_by_face_landmark_5 -from facefusion.face_masker import create_static_box_mask +from facefusion.face_masker import create_box_mask from facefusion.face_selector import find_similar_faces, sort_and_filter_faces from facefusion.face_store import get_reference_faces from facefusion.filesystem import in_directory, is_image, is_video, resolve_relative_path, same_file_extension @@ -199,7 +199,7 @@ def edit_face(target_face : Face, temp_vision_frame : VisionFrame) -> VisionFram model_size = get_model_options().get('size') face_landmark_5 = scale_face_landmark_5(target_face.landmark_set.get('5/68'), 1.5) crop_vision_frame, affine_matrix = warp_face_by_face_landmark_5(temp_vision_frame, face_landmark_5, model_template, model_size) - box_mask = create_static_box_mask(crop_vision_frame.shape[:2][::-1], state_manager.get_item('face_mask_blur'), (0, 0, 0, 0)) + box_mask = create_box_mask(crop_vision_frame, state_manager.get_item('face_mask_blur'), (0, 0, 0, 0)) crop_vision_frame = prepare_crop_frame(crop_vision_frame) crop_vision_frame = apply_edit(crop_vision_frame, target_face.landmark_set.get('68')) crop_vision_frame = normalize_crop_frame(crop_vision_frame) diff --git a/facefusion/processors/modules/face_enhancer.py b/facefusion/processors/modules/face_enhancer.py index ad1b0a5..dce358e 100755 --- a/facefusion/processors/modules/face_enhancer.py +++ b/facefusion/processors/modules/face_enhancer.py @@ -13,7 +13,7 @@ from facefusion.common_helper import create_float_metavar, create_int_metavar from facefusion.download import conditional_download_hashes, conditional_download_sources, resolve_download_url from facefusion.face_analyser import get_many_faces, get_one_face from facefusion.face_helper import paste_back, warp_face_by_face_landmark_5 -from facefusion.face_masker import create_occlusion_mask, create_static_box_mask +from facefusion.face_masker import create_box_mask, create_occlusion_mask from facefusion.face_selector import find_similar_faces, sort_and_filter_faces from facefusion.face_store import get_reference_faces from facefusion.filesystem import in_directory, is_image, is_video, resolve_relative_path, same_file_extension @@ -291,7 +291,7 @@ def enhance_face(target_face : Face, temp_vision_frame : VisionFrame) -> VisionF model_template = get_model_options().get('template') model_size = get_model_options().get('size') crop_vision_frame, affine_matrix = warp_face_by_face_landmark_5(temp_vision_frame, target_face.landmark_set.get('5/68'), model_template, model_size) - box_mask = create_static_box_mask(crop_vision_frame.shape[:2][::-1], state_manager.get_item('face_mask_blur'), (0, 0, 0, 0)) + box_mask = create_box_mask(crop_vision_frame, state_manager.get_item('face_mask_blur'), (0, 0, 0, 0)) crop_masks =\ [ box_mask diff --git a/facefusion/processors/modules/face_swapper.py b/facefusion/processors/modules/face_swapper.py index 859d1b6..ed27cef 100755 --- a/facefusion/processors/modules/face_swapper.py +++ b/facefusion/processors/modules/face_swapper.py @@ -2,6 +2,7 @@ from argparse import ArgumentParser from functools import lru_cache from typing import List, Tuple +import cv2 import numpy import facefusion.choices @@ -14,7 +15,7 @@ from facefusion.download import conditional_download_hashes, conditional_downloa from facefusion.execution import has_execution_provider from facefusion.face_analyser import get_average_face, get_many_faces, get_one_face from facefusion.face_helper import paste_back, warp_face_by_face_landmark_5 -from facefusion.face_masker import create_occlusion_mask, create_region_mask, create_static_box_mask +from facefusion.face_masker import create_area_mask, create_box_mask, create_occlusion_mask, create_region_mask from facefusion.face_selector import find_similar_faces, sort_and_filter_faces, sort_faces_by_order from facefusion.face_store import get_reference_faces from facefusion.filesystem import filter_image_paths, has_image, in_directory, is_image, is_video, resolve_relative_path, same_file_extension @@ -429,7 +430,7 @@ def swap_face(source_face : Face, target_face : Face, temp_vision_frame : Vision crop_masks = [] if 'box' in state_manager.get_item('face_mask_types'): - box_mask = create_static_box_mask(crop_vision_frame.shape[:2][::-1], state_manager.get_item('face_mask_blur'), state_manager.get_item('face_mask_padding')) + box_mask = create_box_mask(crop_vision_frame, state_manager.get_item('face_mask_blur'), state_manager.get_item('face_mask_padding')) crop_masks.append(box_mask) if 'occlusion' in state_manager.get_item('face_mask_types'): @@ -444,6 +445,11 @@ def swap_face(source_face : Face, target_face : Face, temp_vision_frame : Vision temp_vision_frames.append(pixel_boost_vision_frame) crop_vision_frame = explode_pixel_boost(temp_vision_frames, pixel_boost_total, model_size, pixel_boost_size) + if 'area' in state_manager.get_item('face_mask_types'): + face_landmark_68 = cv2.transform(target_face.landmark_set.get('68').reshape(1, -1, 2), affine_matrix).reshape(-1, 2) + area_mask = create_area_mask(crop_vision_frame, face_landmark_68, state_manager.get_item('face_mask_areas')) + crop_masks.append(area_mask) + if 'region' in state_manager.get_item('face_mask_types'): region_mask = create_region_mask(crop_vision_frame, state_manager.get_item('face_mask_regions')) crop_masks.append(region_mask) diff --git a/facefusion/processors/modules/lip_syncer.py b/facefusion/processors/modules/lip_syncer.py index 274f0f3..27559e2 100755 --- a/facefusion/processors/modules/lip_syncer.py +++ b/facefusion/processors/modules/lip_syncer.py @@ -15,7 +15,7 @@ from facefusion.common_helper import get_first from facefusion.download import conditional_download_hashes, conditional_download_sources, resolve_download_url from facefusion.face_analyser import get_many_faces, get_one_face from facefusion.face_helper import create_bounding_box, paste_back, warp_face_by_bounding_box, warp_face_by_face_landmark_5 -from facefusion.face_masker import create_area_mask, create_occlusion_mask, create_static_box_mask +from facefusion.face_masker import create_area_mask, create_box_mask, create_occlusion_mask from facefusion.face_selector import find_similar_faces, sort_and_filter_faces from facefusion.face_store import get_reference_faces from facefusion.filesystem import filter_audio_paths, has_audio, in_directory, is_image, is_video, resolve_relative_path, same_file_extension @@ -179,14 +179,14 @@ def sync_lip(target_face : Face, temp_audio_frame : AudioFrame, temp_vision_fram if model_name == 'edtalk_256': lip_syncer_weight = numpy.array([ state_manager.get_item('lip_syncer_weight') ]).astype(numpy.float32) * 1.25 - box_mask = create_static_box_mask(crop_vision_frame.shape[:2][::-1], state_manager.get_item('face_mask_blur'), state_manager.get_item('face_mask_padding')) + box_mask = create_box_mask(crop_vision_frame, state_manager.get_item('face_mask_blur'), state_manager.get_item('face_mask_padding')) crop_masks.append(box_mask) crop_vision_frame = prepare_crop_frame(crop_vision_frame) crop_vision_frame = forward_edtalk(temp_audio_frame, crop_vision_frame, lip_syncer_weight) crop_vision_frame = normalize_crop_frame(crop_vision_frame) if model_name.startswith('wav2lip'): face_landmark_68 = cv2.transform(target_face.landmark_set.get('68').reshape(1, -1, 2), affine_matrix).reshape(-1, 2) - area_mask = create_area_mask(face_landmark_68, [ 'lower-face' ]) + area_mask = create_area_mask(crop_vision_frame, face_landmark_68, [ 'lower-face' ]) crop_masks.append(area_mask) bounding_box = create_bounding_box(face_landmark_68) bounding_box = resize_bounding_box(bounding_box, 1 / 8)