Improve eyebrow mask
parent
ab3b73631b
commit
01ef955372
|
@ -285,6 +285,65 @@ def create_eyes_mask(face: Face, frame: Frame) -> (np.ndarray, np.ndarray, tuple
|
||||||
|
|
||||||
return mask, eyes_cutout, (min_x, min_y, max_x, max_y), eyes_polygon
|
return mask, eyes_cutout, (min_x, min_y, max_x, max_y), eyes_polygon
|
||||||
|
|
||||||
|
def create_curved_eyebrow(points):
|
||||||
|
if len(points) >= 5:
|
||||||
|
# Sort points by x-coordinate
|
||||||
|
sorted_idx = np.argsort(points[:, 0])
|
||||||
|
sorted_points = points[sorted_idx]
|
||||||
|
|
||||||
|
# Calculate dimensions
|
||||||
|
x_min, y_min = np.min(sorted_points, axis=0)
|
||||||
|
x_max, y_max = np.max(sorted_points, axis=0)
|
||||||
|
width = x_max - x_min
|
||||||
|
height = y_max - y_min
|
||||||
|
|
||||||
|
# Create more points for smoother curve
|
||||||
|
num_points = 50
|
||||||
|
x = np.linspace(x_min, x_max, num_points)
|
||||||
|
|
||||||
|
# Fit quadratic curve through points for more natural arch
|
||||||
|
coeffs = np.polyfit(sorted_points[:, 0], sorted_points[:, 1], 2) # Changed to quadratic
|
||||||
|
y = np.polyval(coeffs, x)
|
||||||
|
|
||||||
|
# Create points for top and bottom curves with consistent offsets
|
||||||
|
top_offset = height * 0.3 # Simplified offset for cleaner curve
|
||||||
|
bottom_offset = height * 0.1 # Thinner bottom curve
|
||||||
|
|
||||||
|
# Create smooth curves
|
||||||
|
top_curve = y - top_offset
|
||||||
|
bottom_curve = y + bottom_offset
|
||||||
|
|
||||||
|
# Create curved endpoints with slight taper
|
||||||
|
end_points = 5
|
||||||
|
start_x = np.linspace(x[0] - width * 0.1, x[0], end_points)
|
||||||
|
end_x = np.linspace(x[-1], x[-1] + width * 0.1, end_points)
|
||||||
|
|
||||||
|
# Create tapered ends
|
||||||
|
start_curve = np.column_stack((
|
||||||
|
start_x,
|
||||||
|
np.linspace(bottom_curve[0], top_curve[0], end_points)
|
||||||
|
))
|
||||||
|
end_curve = np.column_stack((
|
||||||
|
end_x,
|
||||||
|
np.linspace(bottom_curve[-1], top_curve[-1], end_points)
|
||||||
|
))
|
||||||
|
|
||||||
|
# Combine all points to form a smooth contour
|
||||||
|
contour_points = np.vstack([
|
||||||
|
start_curve,
|
||||||
|
np.column_stack((x, top_curve)),
|
||||||
|
end_curve,
|
||||||
|
np.column_stack((x[::-1], bottom_curve[::-1]))
|
||||||
|
])
|
||||||
|
|
||||||
|
# Add slight padding for better coverage
|
||||||
|
center = np.mean(contour_points, axis=0)
|
||||||
|
vectors = contour_points - center
|
||||||
|
padded_points = center + vectors * 1.15 # 15% padding
|
||||||
|
|
||||||
|
return padded_points
|
||||||
|
return points
|
||||||
|
|
||||||
def create_eyebrows_mask(face: Face, frame: Frame) -> (np.ndarray, np.ndarray, tuple, np.ndarray):
|
def create_eyebrows_mask(face: Face, frame: Frame) -> (np.ndarray, np.ndarray, tuple, np.ndarray):
|
||||||
mask = np.zeros(frame.shape[:2], dtype=np.uint8)
|
mask = np.zeros(frame.shape[:2], dtype=np.uint8)
|
||||||
eyebrows_cutout = None
|
eyebrows_cutout = None
|
||||||
|
@ -335,33 +394,30 @@ def create_eyebrows_mask(face: Face, frame: Frame) -> (np.ndarray, np.ndarray, t
|
||||||
num_points = 50
|
num_points = 50
|
||||||
x = np.linspace(x_min, x_max, num_points)
|
x = np.linspace(x_min, x_max, num_points)
|
||||||
|
|
||||||
# Fit cubic curve through points for more natural arch
|
# Fit quadratic curve through points for more natural arch
|
||||||
coeffs = np.polyfit(sorted_points[:, 0], sorted_points[:, 1], 3)
|
coeffs = np.polyfit(sorted_points[:, 0], sorted_points[:, 1], 2) # Changed to quadratic
|
||||||
y = np.polyval(coeffs, x)
|
y = np.polyval(coeffs, x)
|
||||||
|
|
||||||
# Create points for top and bottom curves with varying offsets
|
# Create points for top and bottom curves with consistent offsets
|
||||||
top_offset = np.linspace(height * 0.4, height * 0.3, num_points) # Varying offset for more natural shape
|
top_offset = height * 0.3 # Simplified offset for cleaner curve
|
||||||
bottom_offset = np.linspace(height * 0.2, height * 0.15, num_points)
|
bottom_offset = height * 0.1 # Thinner bottom curve
|
||||||
|
|
||||||
# Add some randomness to the offsets for more natural look
|
|
||||||
top_offset += np.random.normal(0, height * 0.02, num_points)
|
|
||||||
bottom_offset += np.random.normal(0, height * 0.01, num_points)
|
|
||||||
|
|
||||||
# Smooth the offsets
|
|
||||||
top_offset = cv2.GaussianBlur(top_offset.reshape(-1, 1), (1, 3), 1).reshape(-1)
|
|
||||||
bottom_offset = cv2.GaussianBlur(bottom_offset.reshape(-1, 1), (1, 3), 1).reshape(-1)
|
|
||||||
|
|
||||||
|
# Create smooth curves
|
||||||
top_curve = y - top_offset
|
top_curve = y - top_offset
|
||||||
bottom_curve = y + bottom_offset
|
bottom_curve = y + bottom_offset
|
||||||
|
|
||||||
# Create curved endpoints
|
# Create curved endpoints with slight taper
|
||||||
end_points = 5
|
end_points = 5
|
||||||
|
start_x = np.linspace(x[0] - width * 0.1, x[0], end_points)
|
||||||
|
end_x = np.linspace(x[-1], x[-1] + width * 0.1, end_points)
|
||||||
|
|
||||||
|
# Create tapered ends
|
||||||
start_curve = np.column_stack((
|
start_curve = np.column_stack((
|
||||||
np.linspace(x[0] - width * 0.05, x[0], end_points),
|
start_x,
|
||||||
np.linspace(bottom_curve[0], top_curve[0], end_points)
|
np.linspace(bottom_curve[0], top_curve[0], end_points)
|
||||||
))
|
))
|
||||||
end_curve = np.column_stack((
|
end_curve = np.column_stack((
|
||||||
np.linspace(x[-1], x[-1] + width * 0.05, end_points),
|
end_x,
|
||||||
np.linspace(bottom_curve[-1], top_curve[-1], end_points)
|
np.linspace(bottom_curve[-1], top_curve[-1], end_points)
|
||||||
))
|
))
|
||||||
|
|
||||||
|
@ -373,13 +429,10 @@ def create_eyebrows_mask(face: Face, frame: Frame) -> (np.ndarray, np.ndarray, t
|
||||||
np.column_stack((x[::-1], bottom_curve[::-1]))
|
np.column_stack((x[::-1], bottom_curve[::-1]))
|
||||||
])
|
])
|
||||||
|
|
||||||
# Add padding and smooth the shape
|
# Add slight padding for better coverage
|
||||||
center = np.mean(contour_points, axis=0)
|
center = np.mean(contour_points, axis=0)
|
||||||
vectors = contour_points - center
|
vectors = contour_points - center
|
||||||
padded_points = center + vectors * 1.2 # 20% padding
|
padded_points = center + vectors * 1.15 # 15% padding
|
||||||
|
|
||||||
# Convert to integer coordinates and draw
|
|
||||||
cv2.fillPoly(mask_roi, [padded_points.astype(np.int32)], 255)
|
|
||||||
|
|
||||||
return padded_points
|
return padded_points
|
||||||
return points
|
return points
|
||||||
|
|
Loading…
Reference in New Issue