MakeUp_Blush / app.py
ukzada's picture
Update app.py
8a57534 verified
Raw
History Blame Contribute Delete
11.6 kB
#!/usr/bin/env python3
"""
Blush Virtual Makeup App
Dedicated app for applying blush with customizable placement and styles
Features: Multiple styles (Powder/Cream/Tint), Intensity control, Placement adjustment
"""
import cv2
import numpy as np
import gradio as gr
from PIL import Image
import os
from landmarks import detect_landmarks, normalize_landmarks
# Blush color presets
BLUSH_COLORS = {
"Coral Pink": (66, 135, 245),
"Rose Pink": (192, 135, 220),
"Peach": (152, 165, 255),
"Mauve Rose": (100, 70, 200),
"Berry": (140, 50, 150),
"Apricot": (140, 140, 230),
"Dusty Rose": (150, 120, 200),
"Terracotta": (80, 100, 180),
"Plum": (120, 60, 160),
"Natural Pink": (180, 150, 230),
}
# Landmark indices for cheeks
CHEEKS = [425, 205] # Left and right cheek centers
# Placement presets (offset adjustments from cheek center)
PLACEMENT_STYLES = {
"Classic (Apple of Cheek)": {"x_offset": 0, "y_offset": 0, "radius_mult": 1.0},
"High Cheekbone": {"x_offset": 0, "y_offset": -15, "radius_mult": 0.9},
"Contour (Lower Cheek)": {"x_offset": -10, "y_offset": 10, "radius_mult": 1.1},
"Lifted (Temple)": {"x_offset": -20, "y_offset": -20, "radius_mult": 0.85},
"Soft Drape": {"x_offset": -5, "y_offset": 5, "radius_mult": 1.2},
}
# Blush style characteristics
BLUSH_STYLES = {
"Powder": {
"opacity": 0.35,
"blur_amount": 0.4,
"gradient_sharpness": 1.0,
"description": "Matte, buildable finish"
},
"Cream": {
"opacity": 0.45,
"blur_amount": 0.5,
"gradient_sharpness": 0.7,
"description": "Dewy, blended finish"
},
"Tint": {
"opacity": 0.25,
"blur_amount": 0.6,
"gradient_sharpness": 0.5,
"description": "Sheer, natural flush"
},
}
def apply_blush_advanced(image, color_rgb, landmarks, intensity=50, radius=40,
style="Powder", placement="Classic (Apple of Cheek)"):
"""
Apply blush with advanced controls.
Args:
image: Input image (BGR format)
color_rgb: RGB color tuple for blush
landmarks: Facial landmarks
intensity: Intensity percentage (0-100)
radius: Base radius for blush application
style: Blush style (Powder/Cream/Tint)
placement: Placement style
Returns:
Image with blush applied
"""
if landmarks is None:
return image
h, w = image.shape[:2]
mask = np.zeros_like(image, dtype=np.float32)
# Get cheek points
cheek_points = normalize_landmarks(landmarks, h, w, CHEEKS)
# Get placement adjustments
placement_info = PLACEMENT_STYLES.get(placement, PLACEMENT_STYLES["Classic (Apple of Cheek)"])
x_offset = placement_info["x_offset"]
y_offset = placement_info["y_offset"]
radius_mult = placement_info["radius_mult"]
# Get style characteristics
style_info = BLUSH_STYLES.get(style, BLUSH_STYLES["Powder"])
base_opacity = style_info["opacity"]
blur_amount = style_info["blur_amount"]
gradient_sharp = style_info["gradient_sharpness"]
# Adjust radius based on placement and intensity
effective_radius = int(radius * radius_mult)
# Convert intensity to multiplier
intensity_mult = intensity / 100.0
for point in cheek_points:
x, y = int(point[0]) + x_offset, int(point[1]) + y_offset
# Ensure within bounds
x = max(effective_radius, min(w - effective_radius, x))
y = max(effective_radius, min(h - effective_radius, y))
# Create circular blush with gradient
y_min = max(0, y - effective_radius)
y_max = min(h, y + effective_radius + 1)
x_min = max(0, x - effective_radius)
x_max = min(w, x + effective_radius + 1)
yy, xx = np.ogrid[y_min:y_max, x_min:x_max]
dist = np.sqrt((yy - y) ** 2 + (xx - x) ** 2)
# Create gradient based on style
gradient = np.zeros_like(dist, dtype=np.float32)
valid = dist <= effective_radius
# Different gradient functions for different styles
if style == "Powder":
# Sharper gradient for powder
gradient[valid] = (1.0 - (dist[valid] / effective_radius)) ** gradient_sharp
elif style == "Cream":
# Smoother gradient for cream
gradient[valid] = (1.0 + np.cos(np.pi * dist[valid] / effective_radius)) / 2.0
else: # Tint
# Very soft gradient for tint
gradient[valid] = np.exp(-2 * (dist[valid] / effective_radius) ** 2)
# Apply color with gradient
for c in range(3):
color_val = color_rgb[c]
mask[y_min:y_max, x_min:x_max, c] = np.maximum(
mask[y_min:y_max, x_min:x_max, c],
color_val * gradient
)
# Apply blur based on style
blur_radius = int(effective_radius * blur_amount)
if blur_radius % 2 == 0:
blur_radius += 1
blur_radius = max(3, blur_radius)
mask = cv2.GaussianBlur(mask, (blur_radius, blur_radius), blur_radius // 3)
# Convert to uint8
mask = mask.astype(np.uint8)
# Apply with intensity and style-specific opacity
alpha = base_opacity * intensity_mult
output = cv2.addWeighted(image, 1.0, mask, alpha, 0)
return output
def process_blush(image, color_name, style, placement, intensity, radius):
"""
Process image to apply blush.
Args:
image: Input image
color_name: Name of blush color
style: Blush style (Powder/Cream/Tint)
placement: Placement style
intensity: Intensity percentage
radius: Application radius
Returns:
Tuple of (processed_image, status_message)
"""
if image is None:
return None, "No image provided"
# Convert PIL to OpenCV format
if isinstance(image, Image.Image):
img = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
else:
img = image.copy()
# Detect landmarks
landmarks = detect_landmarks(img)
if landmarks is None:
return cv2.cvtColor(img, cv2.COLOR_BGR2RGB), "No face detected"
# Get color
color = BLUSH_COLORS.get(color_name, BLUSH_COLORS["Rose Pink"])
# Apply blush
output = apply_blush_advanced(
img, color, landmarks,
intensity=intensity,
radius=radius,
style=style,
placement=placement
)
# Convert back to RGB
output_rgb = cv2.cvtColor(output, cv2.COLOR_BGR2RGB)
style_info = BLUSH_STYLES.get(style, BLUSH_STYLES["Powder"])
status = (f"Applied {color_name} blush in {style} style "
f"({style_info['description']}) at {intensity}% intensity "
f"with {placement} placement")
return output_rgb, status
# Create Gradio interface
with gr.Blocks(title="Blush Virtual Makeup", theme=gr.themes.Soft()) as demo:
gr.Markdown("# 🌸 Blush Virtual Makeup App")
gr.Markdown("Apply professional blush with customizable placement, intensity, and finish styles")
with gr.Row():
with gr.Column(scale=1):
# Image upload
image_input = gr.Image(label="Upload Your Photo", type="pil")
# Color selection
gr.Markdown("### 🎨 Choose Your Color")
color_dropdown = gr.Dropdown(
choices=list(BLUSH_COLORS.keys()),
value="Rose Pink",
label="Blush Color",
interactive=True
)
# Style selection
gr.Markdown("### πŸ’„ Select Style")
style_radio = gr.Radio(
choices=list(BLUSH_STYLES.keys()),
value="Powder",
label="Blush Type",
interactive=True
)
style_desc = gr.Markdown(
f"*{BLUSH_STYLES['Powder']['description']}*",
visible=True
)
# Placement selection
gr.Markdown("### πŸ“ Placement")
placement_dropdown = gr.Dropdown(
choices=list(PLACEMENT_STYLES.keys()),
value="Classic (Apple of Cheek)",
label="Placement Style",
interactive=True
)
# Intensity control
gr.Markdown("### 🎚️ Intensity")
intensity_slider = gr.Slider(
minimum=0,
maximum=100,
value=50,
step=5,
label="Intensity (%)",
interactive=True
)
# Radius control
gr.Markdown("### πŸ“ Size")
radius_slider = gr.Slider(
minimum=20,
maximum=80,
value=45,
step=5,
label="Blush Size (radius in pixels)",
interactive=True
)
# Apply button
apply_btn = gr.Button("🌸 Apply Blush", variant="primary", size="lg")
with gr.Column(scale=1):
# Output image
image_output = gr.Image(label="Result", type="pil")
# Status message
status_text = gr.Textbox(
label="Status",
interactive=False,
lines=3
)
# Info guide
gr.Markdown("""
### πŸ“– Style Guide
**Powder Blush**
- Matte finish
- Buildable coverage
- Long-lasting
- Best for oily skin
**Cream Blush**
- Dewy finish
- Blended look
- Natural glow
- Best for dry skin
**Tint Blush**
- Sheer coverage
- Natural flush
- Very subtle
- Best for minimal makeup
### πŸ’‘ Placement Tips
- **Classic**: Smile and apply to apple of cheek
- **High Cheekbone**: For lifted, sculpted look
- **Contour**: Add warmth and definition
- **Lifted**: Temple placement for face-lifting effect
- **Soft Drape**: Modern, soft-focus look
""")
# Update style description when style changes
def update_style_desc(style):
desc = BLUSH_STYLES.get(style, BLUSH_STYLES["Powder"])["description"]
return f"*{desc}*"
style_radio.change(
fn=update_style_desc,
inputs=[style_radio],
outputs=[style_desc]
)
# Apply blush
apply_btn.click(
fn=process_blush,
inputs=[image_input, color_dropdown, style_radio, placement_dropdown,
intensity_slider, radius_slider],
outputs=[image_output, status_text]
)
# Example gallery (optional - can be populated with sample results)
gr.Markdown("""
### 🎯 Quick Start
1. Upload a clear, front-facing photo
2. Choose your desired blush color
3. Select your preferred style (Powder/Cream/Tint)
4. Adjust placement to customize your look
5. Fine-tune intensity and size
6. Click "Apply Blush" to see results
""")
if __name__ == "__main__":
print("\n" + "="*60)
print("🌸 Blush Virtual Makeup App")
print("="*60 + "\n")
demo.launch()