perf(face-swapper): optimize opacity handling and frame copies

Move opacity calculation before frame copy to skip the copy when
opacity is 1.0 (common case). Add early return path for full opacity.
Clear PREVIOUS_FRAME_RESULT instead of caching when interpolation
is disabled.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Lauri Gates
2026-02-22 21:12:02 +02:00
parent d5338a3eae
commit aabf41050a
+9 -15
View File
@@ -137,7 +137,9 @@ def swap_face(source_face: Face, target_face: Face, temp_frame: Frame) -> Frame:
return temp_frame return temp_frame
# Store a copy of the original frame before swapping for opacity blending # Store a copy of the original frame before swapping for opacity blending
original_frame = temp_frame.copy() opacity = getattr(modules.globals, "opacity", 1.0)
opacity = max(0.0, min(1.0, opacity))
original_frame = temp_frame if opacity >= 1.0 else temp_frame.copy()
# Pre-swap Input Check with optimization # Pre-swap Input Check with optimization
if temp_frame.dtype != np.uint8: if temp_frame.dtype != np.uint8:
@@ -240,19 +242,13 @@ def swap_face(source_face: Face, target_face: Face, temp_frame: Frame) -> Frame:
except Exception as e: except Exception as e:
print(f"Poisson blending failed: {e}") print(f"Poisson blending failed: {e}")
# Apply opacity blend between the original frame and the swapped frame # Apply opacity blend between the original frame and the swapped frame
opacity = getattr(modules.globals, "opacity", 1.0) if opacity >= 1.0:
# Ensure opacity is within valid range [0.0, 1.0] return swapped_frame.astype(np.uint8)
opacity = max(0.0, min(1.0, opacity))
# Blend the original_frame with the (potentially mouth-masked) swapped_frame # Blend the original_frame with the (potentially mouth-masked) swapped_frame
# Ensure both frames are uint8 before blending
final_swapped_frame = gpu_add_weighted(original_frame.astype(np.uint8), 1 - opacity, swapped_frame.astype(np.uint8), opacity, 0) final_swapped_frame = gpu_add_weighted(original_frame.astype(np.uint8), 1 - opacity, swapped_frame.astype(np.uint8), opacity, 0)
return final_swapped_frame.astype(np.uint8)
# Ensure final frame is uint8 after blending (addWeighted should preserve it, but belt-and-suspenders)
final_swapped_frame = final_swapped_frame.astype(np.uint8)
return final_swapped_frame
# --- START: Mac M1-M5 Optimized Face Detection --- # --- START: Mac M1-M5 Optimized Face Detection ---
@@ -363,10 +359,8 @@ def apply_post_processing(current_frame: Frame, swapped_face_bboxes: List[np.nda
pass pass
PREVIOUS_FRAME_RESULT = processed_frame.copy() PREVIOUS_FRAME_RESULT = processed_frame.copy()
else: else:
# If interpolation is off or weight is invalid, just use the current frame # Interpolation is off or weight is invalid — no need to cache
# Update state with the current (potentially sharpened) frame PREVIOUS_FRAME_RESULT = None
# Reset previous frame state if interpolation was just turned off or weight is invalid
PREVIOUS_FRAME_RESULT = processed_frame.copy()
return final_frame return final_frame