feat: smoother morph via elliptical alpha mask and EMA keypoint smoothing#1799
Open
codex12121212 wants to merge 1 commit into
Open
feat: smoother morph via elliptical alpha mask and EMA keypoint smoothing#1799codex12121212 wants to merge 1 commit into
codex12121212 wants to merge 1 commit into
Conversation
…hing Replaces the square erode+blur alpha template with an oval mask that follows the natural face silhouette, eliminating the rectangular halo artifact at ears, hair and neck. Adds temporal EMA smoothing of the 5-point face keypoints before each swap so the paste-back affine transform is stable across frames — the main source of per-frame jitter in live mode. A jump-detection threshold (>40 px shift) resets tracking automatically on new faces or fast pans. - globals.py: add `face_smooth_alpha` (default 0.5; 0=off, ~0.9=very smooth) - _get_soft_alpha: ellipse (rx=44%, ry=48%) + single GaussianBlur - _smooth_face_kps / _reset_kps_tracking: EMA helpers with lock - process_frame: call smoothing in single-face path, reset on miss - process_image / process_video: reset tracking on each new job Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Contributor
Reviewer's GuideImplements smoother, more natural face swaps by replacing the cached square soft-alpha mask with an elliptical, face-shaped mask and introducing global EMA-based smoothing of face keypoints with jump detection and lifecycle resets, then wiring smoothing into the single-face processing path. Sequence diagram for single-face processing with EMA keypoint smoothingsequenceDiagram
actor User
participant ProcessFrame as process_frame
participant FaceDetector as get_one_face
participant Smoother as _smooth_face_kps
participant Globals as modules_globals
participant Swap as swap_face
participant Tracker as _reset_kps_tracking
User->>ProcessFrame: process_frame(source_face, temp_frame, target_face)
alt target_face is None
ProcessFrame->>FaceDetector: get_one_face(processed_frame)
FaceDetector-->>ProcessFrame: target_face
end
alt target_face exists
ProcessFrame->>Smoother: _smooth_face_kps(target_face)
Smoother->>Globals: read face_smooth_alpha
alt face_smooth_alpha <= 0.0
Smoother-->>ProcessFrame: original_target_face
else face_smooth_alpha > 0.0
Smoother->>Smoother: compare kps with previous in _kps_smooth_state
alt jump_distance > 40.0
Smoother->>Smoother: reset tracking for this frame
Smoother-->>ProcessFrame: unsmoothed_kps_face
else jump_distance <= 40.0
Smoother->>Smoother: EMA blend current and previous kps
Smoother-->>ProcessFrame: smoothed_kps_face
end
end
ProcessFrame->>Swap: swap_face(source_face, returned_face, processed_frame)
Swap-->>ProcessFrame: processed_frame
ProcessFrame->>ProcessFrame: append bbox to swapped_face_bboxes
else no target_face
ProcessFrame->>Tracker: _reset_kps_tracking()
end
User-->>ProcessFrame: receive final_frame
Class diagram for new alpha mask and EMA keypoint smoothingclassDiagram
class FaceSwapperModule {
_get_soft_alpha(size: int) np.ndarray
_smooth_face_kps(face: Face) Face
_reset_kps_tracking() void
process_frame(source_face: Face, temp_frame: Frame, target_face: Face) Frame
process_image(source_path: str, target_path: str, output_path: str) void
process_video(source_path: str, temp_frame_paths: List_str) void
}
class _paste_cache {
soft_alpha: np.ndarray
alpha_size: int
}
class _kps_smooth_state {
kps: np.ndarray
}
class Globals {
face_smooth_alpha: float
map_faces: bool
many_faces: bool
}
class Face {
kps: np.ndarray
bbox: np.ndarray
copy() Face
get(key: str) any
}
class Frame {
}
class List_str {
}
FaceSwapperModule --> _paste_cache : uses_for_alpha_mask
FaceSwapperModule --> _kps_smooth_state : uses_for_kps_ema
FaceSwapperModule --> Globals : reads_config
FaceSwapperModule --> Face : processes
FaceSwapperModule --> Frame : processes
_paste_cache : cached
_kps_smooth_state : global_state
FaceSwapperModule ..> Face : single_face_path_uses_kps
FaceSwapperModule ..> Globals : face_smooth_alpha_controls_ema
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two targeted improvements to make live face swaps look smoother and more realistic.
1. Elliptical alpha mask
Replaces the square erode+blur alpha template with an oval mask that follows the natural face silhouette, eliminating the rectangular halo artifact at ears, hair, and neck.
2. Temporal EMA keypoint smoothing
Applies an Exponential Moving Average to the 5 face keypoints before each swap, making the paste-back affine transform stable across frames (the main source of per-frame jitter in live mode).
Files changed
Test plan
Summary by Sourcery
Improve visual smoothness and stability of live face swaps by refining alpha masking and adding temporal keypoint smoothing.
New Features:
Enhancements: