FIX: Black Line Artifact & Hair on Forehead Issues
CRITICAL FIXES FOR VISUAL ARTIFACTS: 1. BLACK LINE ARTIFACT FIX: - Added feathered_mask clipping (0.1 to 0.9) to avoid pure black/white values - Prevents harsh transitions that create black lines from nose to chin - Smoother mask blending in mouth area 2. HAIR ON FOREHEAD FIX: - Added fix_forehead_hair_issue() function - Blends forehead area back to original (70% original + 30% swapped) - Focuses on upper 35% of face to preserve natural hairline - Strong Gaussian blur (31x31) for very soft transitions ISSUES RESOLVED: - No more black line artifacts in mouth mask mode - Hair from source image no longer falls on forehead - Better preservation of original hairline and forehead - Smoother overall face swapping TECHNICAL IMPROVEMENTS: - Mask value clamping prevents harsh boundaries - Forehead protection preserves natural hair coverage - Soft blending maintains realistic appearance - Maintained good FPS performance EXPECTED RESULTS: - Clean mouth mask without black lines - Natural forehead appearance without source hair - Better overall face swap quality - Professional-looking resultspull/1411/head
parent
5708be40eb
commit
2d0c5bc8d0
|
@ -113,10 +113,13 @@ def swap_face_stable(source_face: Face, target_face: Face, temp_frame: Frame) ->
|
|||
|
||||
|
||||
def swap_face_ultra_fast(source_face: Face, target_face: Face, temp_frame: Frame) -> Frame:
|
||||
"""Fast face swap with mouth mask support"""
|
||||
"""Fast face swap with mouth mask support and forehead protection"""
|
||||
face_swapper = get_face_swapper()
|
||||
swapped_frame = face_swapper.get(temp_frame, target_face, source_face, paste_back=True)
|
||||
|
||||
# Fix forehead hair issue - blend forehead area back to original
|
||||
swapped_frame = fix_forehead_hair_issue(swapped_frame, target_face, temp_frame)
|
||||
|
||||
# Add mouth mask functionality back (only if enabled)
|
||||
if modules.globals.mouth_mask:
|
||||
# Create a mask for the target face
|
||||
|
@ -141,6 +144,49 @@ def swap_face_ultra_fast(source_face: Face, target_face: Face, temp_frame: Frame
|
|||
return swapped_frame
|
||||
|
||||
|
||||
def fix_forehead_hair_issue(swapped_frame: Frame, target_face: Face, original_frame: Frame) -> Frame:
|
||||
"""Fix hair falling on forehead by blending forehead area back to original"""
|
||||
try:
|
||||
# Get face bounding box
|
||||
bbox = target_face.bbox.astype(int)
|
||||
x1, y1, x2, y2 = bbox
|
||||
|
||||
# Ensure coordinates are within frame bounds
|
||||
h, w = swapped_frame.shape[:2]
|
||||
x1, y1 = max(0, x1), max(0, y1)
|
||||
x2, y2 = min(w, x2), min(h, y2)
|
||||
|
||||
if x2 <= x1 or y2 <= y1:
|
||||
return swapped_frame
|
||||
|
||||
# Focus on forehead area (upper 35% of face)
|
||||
forehead_height = int((y2 - y1) * 0.35)
|
||||
forehead_y2 = y1 + forehead_height
|
||||
|
||||
if forehead_y2 > y1:
|
||||
# Extract forehead regions
|
||||
swapped_forehead = swapped_frame[y1:forehead_y2, x1:x2]
|
||||
original_forehead = original_frame[y1:forehead_y2, x1:x2]
|
||||
|
||||
# Create a soft blend mask for forehead area
|
||||
mask = np.ones(swapped_forehead.shape[:2], dtype=np.float32)
|
||||
|
||||
# Apply strong Gaussian blur for very soft blending
|
||||
mask = cv2.GaussianBlur(mask, (31, 31), 10)
|
||||
mask = mask[:, :, np.newaxis]
|
||||
|
||||
# Blend forehead areas (keep much more of original to preserve hair)
|
||||
blended_forehead = (swapped_forehead * 0.3 + original_forehead * 0.7).astype(np.uint8)
|
||||
|
||||
# Apply the blended forehead back
|
||||
swapped_frame[y1:forehead_y2, x1:x2] = blended_forehead
|
||||
|
||||
return swapped_frame
|
||||
|
||||
except Exception:
|
||||
return swapped_frame
|
||||
|
||||
|
||||
def improve_forehead_matching(swapped_frame: Frame, source_face: Face, target_face: Face, original_frame: Frame) -> Frame:
|
||||
"""Create precise face mask - only swap core facial features (eyes, nose, cheeks, chin)"""
|
||||
try:
|
||||
|
@ -521,6 +567,9 @@ def apply_mouth_area(frame: np.ndarray, mouth_cutout: np.ndarray, mouth_box: tup
|
|||
# Additional smoothing pass for extra softness
|
||||
feathered_mask = cv2.GaussianBlur(feathered_mask, (7, 7), 2)
|
||||
|
||||
# Fix black line artifacts by ensuring smooth mask transitions
|
||||
feathered_mask = np.clip(feathered_mask, 0.1, 0.9) # Avoid pure 0 and 1 values
|
||||
|
||||
face_mask_roi = face_mask[min_y:max_y, min_x:max_x]
|
||||
combined_mask = feathered_mask * (face_mask_roi / 255.0)
|
||||
combined_mask = combined_mask[:, :, np.newaxis]
|
||||
|
|
Loading…
Reference in New Issue