From 0e97e474e4c1fa3037a349055b1cb5b5dd8b647c Mon Sep 17 00:00:00 2001 From: Kenneth Estanislao Date: Mon, 18 May 2026 01:40:01 +0800 Subject: [PATCH] better swapping --- modules/processors/frame/face_swapper.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/modules/processors/frame/face_swapper.py b/modules/processors/frame/face_swapper.py index b664fde..2d09e17 100644 --- a/modules/processors/frame/face_swapper.py +++ b/modules/processors/frame/face_swapper.py @@ -316,11 +316,16 @@ def _get_soft_alpha(size: int) -> np.ndarray: the feather radius scales naturally with the affine transform. """ if _paste_cache['alpha_size'] != size: - k_erode = max(size // 10, 3) - k_blur = max(size // 20, 3) - mask = np.full((size, size), 255, dtype=np.uint8) - mask = cv2.erode(mask, np.ones((k_erode, k_erode), np.uint8), iterations=1) - mask = cv2.GaussianBlur(mask, (2 * k_blur + 1, 2 * k_blur + 1), 0) + # Elliptical (not square) template — matches the gumroad edition's + # _create_elliptical_mask. A full/eroded square leaves the aligned + # crop's corners near-opaque, so the swapped square's straight edges + # show as a visible box on the face. An ellipse (axes 0.44*size) zeroes + # the corners and the heavy blur feathers smoothly into the original. + center = (size // 2, size // 2) + axes = (int(size * 0.44), int(size * 0.44)) + mask = np.zeros((size, size), dtype=np.uint8) + cv2.ellipse(mask, center, axes, 0, 0, 360, 255, -1) + mask = cv2.GaussianBlur(mask, (31, 31), 12) _paste_cache['soft_alpha'] = mask # uint8 [0, 255] — blended via cv2 SIMD ops _paste_cache['alpha_size'] = size return _paste_cache['soft_alpha']