女生妆容效果数字预览系统
一、实际应用场景描述
在美妆行业蓬勃发展的今天,数字艺术与化妆技术的结合为女性消费者带来了全新的体验。本系统主要应用于以下场景:
- 美妆品牌专柜:顾客可现场通过AR试妆,快速找到适合的口红、眼影颜色
- 线上购物平台:用户上传照片即可虚拟试色,减少因色差导致的退货
- 美妆教学机构:学员可模拟不同妆容效果,提高学习效率
- 个人日常使用:用户可尝试各种流行妆容,找到最适合自己的风格
二、引入痛点
传统试妆方式存在以下问题:
- 时间成本高:实体试妆需逐层涂抹,反复修改
- 卫生隐患:多人共用化妆品易引发皮肤问题
- 色差困扰:不同光线、肤色下试色效果差异大
- 不可逆性:不满意需完全卸妆,损伤皮肤屏障
- 选择困难:面对众多产品难以快速决策
三、核心逻辑讲解
本系统采用"图像识别+数字叠加+色彩融合"的技术路线:
- 面部检测:使用dlib/face_recognition库定位面部关键点
- 区域划分:根据68个特征点确定眼、唇、脸颊等妆容区域
- 颜色叠加:将预设妆容素材与用户照片进行alpha混合
- 边缘融合:使用高斯模糊处理边缘,实现自然过渡
- 实时渲染:支持摄像头视频流实时试妆
四、项目结构
makeup_preview_system/ ├── main.py # 主程序入口 ├── config/ │ └── settings.py # 配置文件 ├── core/ │ ├── face_detector.py # 人脸检测模块 │ ├── makeup_engine.py # 妆容引擎核心 │ └── image_processor.py # 图像处理工具 ├── data/ │ ├── makeup_templates/ # 妆容模板素材 │ └── user_photos/ # 用户照片存储 ├── ui/ │ └── gui.py # 图形界面 ├── utils/ │ └── helpers.py # 辅助函数 ├── requirements.txt # 依赖包 └── README.md # 项目说明
五、核心代码实现
- 主程序入口 (main.py)
""" 女生妆容效果数字预览系统 - 主程序入口 功能:整合各模块,提供完整的试妆体验 作者:全栈开发工程师 版本:1.0.0 """
import sys import os from pathlib import Path
添加项目根目录到系统路径
sys.path.append(str(Path(file).parent))
from config.settings import Config from core.makeup_engine import MakeupEngine from ui.gui import MakeupGUI
def main(): """ 主函数:初始化配置,启动GUI界面
执行流程:
1. 加载系统配置
2. 初始化妆容引擎
3. 启动图形界面
4. 处理用户交互
"""
print("=" * 50)
print(" 女生妆容效果数字预览系统 v1.0.0")
print(" 数字艺术与美妆的完美融合")
print("=" * 50)
try:
# 1. 加载配置
config = Config()
print(f"[INFO] 配置加载成功,工作目录: {config.WORK_DIR}")
# 2. 初始化妆容引擎
engine = MakeupEngine(config)
print("[INFO] 妆容引擎初始化完成")
# 3. 启动GUI界面
app = MakeupGUI(engine, config)
print("[INFO] GUI界面启动成功")
# 4. 运行主循环
app.run()
except Exception as e:
print(f"[ERROR] 程序启动失败: {str(e)}")
sys.exit(1)
if name == "main": main()
- 配置文件 (config/settings.py)
""" 系统配置文件 包含所有可调参数和路径设置 """
from dataclasses import dataclass from typing import Dict, List import os
@dataclass class Config: """系统配置数据类"""
# ==================== 路径配置 ====================
WORK_DIR: str = os.path.dirname(os.path.abspath(__file__))
DATA_DIR: str = os.path.join(WORK_DIR, "data")
MAKEUP_TEMPLATES_DIR: str = os.path.join(DATA_DIR, "makeup_templates")
USER_PHOTOS_DIR: str = os.path.join(DATA_DIR, "user_photos")
# ==================== 人脸检测配置 ====================
FACE_DETECTION_MODEL: str = "hog" # 'hog' 或 'cnn'
MIN_FACE_SIZE: int = 100 # 最小检测人脸尺寸
UPSAMPLE_TIMES: int = 1 # 图像放大倍数,提高小脸检测率
# ==================== 妆容参数配置 ====================
# 口红参数
LIPSTICK_OPACITY: float = 0.7 # 不透明度 0-1
LIPSTICK_BLUR_RADIUS: int = 5 # 边缘模糊半径
LIPSTICK_COLORS: Dict[str, tuple] = {
"经典红": (180, 30, 60),
"玫瑰粉": (220, 80, 120),
"珊瑚橘": (255, 120, 80),
"豆沙色": (150, 80, 90),
"姨妈红": (130, 20, 40),
"西柚色": (255, 140, 100)
}
# 眼影参数
EYE_SHADOW_OPACITY: float = 0.6
EYE_SHADOW_BLUR_RADIUS: int = 8
EYE_SHADOW_COLORS: Dict[str, tuple] = {
"大地棕": (139, 90, 43),
"烟熏灰": (100, 100, 110),
"桃花粉": (255, 182, 193),
"香槟金": (255, 223, 128),
"孔雀蓝": (0, 128, 128),
"酒红色": (128, 0, 32)
}
# 腮红参数
BLUSH_OPACITY: float = 0.5
BLUSH_BLUR_RADIUS: int = 15
BLUSH_COLORS: Dict[str, tuple] = {
"蜜桃粉": (255, 182, 193),
"珊瑚橙": (255, 127, 80),
"玫瑰红": (255, 105, 180),
"杏色裸": (255, 228, 181),
"砖红色": (205, 92, 92)
}
# 睫毛参数
MASCARA_OPACITY: float = 0.8
MASCARA_THICKNESS: int = 2
# ==================== 图像处理配置 ====================
OUTPUT_IMAGE_QUALITY: int = 95 # JPEG质量
SUPPORTED_FORMATS: List[str] = [".jpg", ".jpeg", ".png", ".bmp"]
# ==================== GUI配置 ====================
WINDOW_TITLE: str = "女生妆容数字预览系统"
WINDOW_WIDTH: int = 1200
WINDOW_HEIGHT: int = 800
THUMBNAIL_SIZE: int = 100
def __post_init__(self):
"""初始化后处理:创建必要的目录"""
for dir_path in [
self.DATA_DIR,
self.MAKEUP_TEMPLATES_DIR,
self.USER_PHOTOS_DIR
]:
os.makedirs(dir_path, exist_ok=True)
预设妆容方案
PRESET_MAKEUPS = { "日常通勤妆": { "lipstick": ("玫瑰粉", 0.6), "eye_shadow": ("大地棕", 0.5), "blush": ("杏色裸", 0.4), "mascara": True }, "约会甜美妆": { "lipstick": ("西柚色", 0.7), "eye_shadow": ("桃花粉", 0.6), "blush": ("蜜桃粉", 0.5), "mascara": True }, "晚宴派对妆": { "lipstick": ("经典红", 0.8), "eye_shadow": ("酒红色", 0.7), "blush": ("玫瑰红", 0.5), "mascara": True }, "韩系清新妆": { "lipstick": ("珊瑚橘", 0.65), "eye_shadow": ("香槟金", 0.55), "blush": ("珊瑚橙", 0.45), "mascara": False }, "欧美酷感妆": { "lipstick": ("姨妈红", 0.85), "eye_shadow": ("烟熏灰", 0.75), "blush": ("砖红色", 0.55), "mascara": True } }
- 人脸检测模块 (core/face_detector.py)
""" 人脸检测模块 使用dlib库实现高精度人脸定位和关键点检测 """
import cv2 import numpy as np import dlib from typing import Tuple, List, Optional from dataclasses import dataclass
@dataclass class FaceLandmarks: """人脸关键点数据结构""" landmarks: np.ndarray # 68个关键点的坐标数组 bounding_box: Tuple[int, int, int, int] # (x, y, w, h) confidence: float # 检测置信度
class FaceDetector: """ 人脸检测器类
功能:
1. 检测图像中的人脸位置
2. 提取68个面部关键点
3. 判断面部朝向(正面/侧面)
"""
def __init__(self, config):
"""
初始化人脸检测器
Args:
config: 系统配置对象
"""
self.config = config
self.detector = None
self.predictor = None
self._initialize_models()
def _initialize_models(self):
"""
初始化检测模型
使用HOG+SVM作为默认检测器(速度快)
可选CNN检测器(精度高但速度慢)
"""
print("[INFO] 正在加载人脸检测模型...")
# 人脸检测器
if self.config.FACE_DETECTION_MODEL == "cnn":
# CNN模型精度更高,适合复杂场景
model_path = "shape_predictor_68_face_landmarks.dat"
self.detector = dlib.cnn_face_detection_model_v1(model_path)
else:
# HOG+SVM模型,速度快,适合实时应用
self.detector = dlib.get_frontal_face_detector()
# 关键点预测器(68点模型)
predictor_path = "shape_predictor_68_face_landmarks.dat"
self.predictor = dlib.shape_predictor(predictor_path)
print("[INFO] 人脸检测模型加载完成")
def detect(self, image: np.ndarray) -> List[FaceLandmarks]:
"""
检测图像中的所有人脸及其关键点
Args:
image: BGR格式的OpenCV图像数组
Returns:
检测到的人脸列表,每个元素包含关键点和边界框
"""
# 转换为灰度图以提高检测效率
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 人脸检测
if self.config.FACE_DETECTION_MODEL == "cnn":
faces = self.detector(gray, self.config.UPSAMPLE_TIMES)
faces = [(face.rect, face.confidence) for face in faces]
else:
faces = self.detector(
gray,
self.config.UPSAMPLE_TIMES
)
faces = [(face, 1.0) for face in faces]
landmarks_list = []
for face_rect, confidence in faces:
# 提取68个关键点
shape = self.predictor(gray, face_rect)
landmarks = np.array([
[shape.part(i).x, shape.part(i).y]
for i in range(68)
])
# 获取边界框
x = face_rect.left()
y = face_rect.top()
w = face_rect.width()
h = face_rect.height()
landmarks_list.append(FaceLandmarks(
landmarks=landmarks,
bounding_box=(x, y, w, h),
confidence=confidence
))
return landmarks_list
def get_face_regions(self, landmarks: np.ndarray) -> dict:
"""
根据68个关键点划分面部区域
关键点索引说明:
0-16: 下巴轮廓
17-21: 左眉毛
22-26: 右眉毛
27-35: 鼻子
36-41: 左眼
42-47: 右眼
48-67: 嘴巴
Args:
landmarks: 68个关键点坐标数组
Returns:
各面部区域的掩码和轮廓信息
"""
regions = {}
# 1. 嘴唇区域(内唇和外唇)
# 外唇: 48-59, 内唇: 60-67
lip_outer = landmarks[48:60]
lip_inner = landmarks[60:68]
regions['lips'] = {
'contour': lip_outer,
'inner': lip_inner
}
# 2. 左眼区域
left_eye = landmarks[36:42]
regions['left_eye'] = {'contour': left_eye}
# 3. 右眼区域
right_eye = landmarks[42:48]
regions['right_eye'] = {'contour': right_eye}
# 4. 眉毛区域
left_eyebrow = landmarks[17:22]
right_eyebrow = landmarks[22:27]
regions['left_eyebrow'] = {'contour': left_eyebrow}
regions['right_eyebrow'] = {'contour': right_eyebrow}
# 5. 脸颊区域(用于腮红)
# 计算颧骨位置
cheek_left = landmarks[[1, 2, 3, 31, 41, 40]]
cheek_right = landmarks[[15, 14, 13, 35, 46, 47]]
regions['cheeks'] = {
'left': cheek_left,
'right': cheek_right
}
# 6. 鼻子区域
nose = landmarks[27:36]
regions['nose'] = {'contour': nose}
return regions
def is_front_facing(self, landmarks: np.ndarray) -> bool:
"""
判断是否为正面人脸
通过计算左右眼、嘴角的对称性来判断
Args:
landmarks: 68个关键点坐标数组
Returns:
True表示正面,False表示侧面
"""
# 计算眼睛中心距离比
left_eye_center = landmarks[36:42].mean(axis=0)
right_eye_center = landmarks[42:48].mean(axis=0)
eye_distance = np.linalg.norm(left_eye_center - right_eye_center)
# 计算嘴角距离比
mouth_left = landmarks[48]
mouth_right = landmarks[54]
mouth_distance = np.linalg.norm(mouth_left - mouth_right)
# 简单判断:眼距和嘴距比例合理则为正面
ratio = mouth_distance / eye_distance
return 1.5 < ratio < 2.5
4. 妆容引擎核心 (core/makeup_engine.py)
""" 妆容引擎核心模块 负责所有妆容效果的渲染和处理 """
import cv2 import numpy as np from typing import Dict, Tuple, Optional from PIL import Image, ImageDraw, ImageFilter import colorsys
class MakeupEngine: """ 妆容引擎类
核心功能:
1. 口红效果渲染
2. 眼影效果渲染
3. 腮红效果渲染
4. 睫毛效果增强
5. 多妆容组合应用
"""
def __init__(self, config):
"""
初始化妆容引擎
Args:
config: 系统配置对象
"""
self.config = config
self.face_detector = FaceDetector(config)
self.current_makeup = None
def apply_lipstick(
self,
image: np.ndarray,
color: Tuple[int, int, int],
opacity: float = None,
blur_radius: int = None
) -> np.ndarray:
"""
应用口红效果
算法流程:
1. 检测人脸和嘴唇区域
2. 创建嘴唇形状的掩码
3. 将颜色应用到掩码区域
4. 使用高斯模糊平滑边缘
5. Alpha混合到原图
Args:
image: 原始BGR图像
color: RGB颜色元组
opacity: 不透明度(默认使用配置值)
blur_radius: 模糊半径(默认使用配置值)
Returns:
添加口红效果的图像
"""
if opacity is None:
opacity = self.config.LIPSTICK_OPACITY
if blur_radius is None:
blur_radius = self.config.LIPSTICK_BLUR_RADIUS
# 复制图像避免修改原图
result = image.copy()
h, w = result.shape[:2]
# 检测人脸
faces = self.face_detector.detect(result)
if not faces:
print("[WARNING] 未检测到人脸,无法应用口红")
return result
for face in faces:
landmarks = face.landmarks
# 获取嘴唇轮廓
lip_contour = landmarks[48:60]
lip_inner = landmarks[60:68]
# 创建嘴唇掩码
mask = self._create_lip_mask(h, w, lip_contour, lip_inner)
# 应用颜色
colored_layer = self._apply_color_to_mask(
result,
mask,
color,
opacity
)
# 边缘模糊处理
blurred_layer = cv2.GaussianBlur(
colored_layer,
(blur_radius * 2 + 1, blur_radius * 2 + 1),
0
)
# Alpha混合
result = cv2.addWeighted(
result, 1 - opacity * 0.5,
blurred_layer, opacity * 0.5,
0
)
return result
def apply_eye_shadow(
self,
image: np.ndarray,
color: Tuple[int, int, int],
opacity: float = None,
blur_radius: int = None
) -> np.ndarray:
"""
应用眼影效果
算法流程:
1. 检测人脸和眼部区域
2. 分别处理上下眼皮
3. 多层渐变着色模拟阴影层次
4. 边缘羽化处理
Args:
image: 原始BGR图像
color: RGB颜色元组
opacity: 不透明度
blur_radius: 模糊半径
Returns:
添加眼影效果的图像
"""
if opacity is None:
opacity = self.config.EYE_SHADOW_OPACITY
if blur_radius is None:
blur_radius = self.config.EYE_SHADOW_BLUR_RADIUS
result = image.copy()
h, w = result.shape[:2]
faces = self.face_detector.detect(result)
if not faces:
print("[WARNING] 未检测到人脸,无法应用眼影")
return result
for face in faces:
landmarks = face.landmarks
# 处理左眼
left_eye_mask = self._create_eye_shadow_mask(
h, w, landmarks[36:42], side='left'
)
result = self._blend_eye_region(
result, left_eye_mask, color, opacity, blur_radius
)
# 处理右眼
right_eye_mask = self._create_eye_shadow_mask(
h, w, landmarks[42:48], side='right'
)
result = self._blend_eye_region(
result, right_eye_mask, color, opacity, blur_radius
)
return result
def apply_blush(
self,
image: np.ndarray,
color: Tuple[int, int, int],
opacity: float = None,
blur_radius: int = None
) -> np.ndarray:
"""
应用腮红效果
算法流程:
1. 检测人脸和颧骨位置
2. 创建椭圆形腮红区域
3. 从中心向外渐变透明
4. 柔化处理实现自然效果
Args:
image: 原始BGR图像
color: RGB颜色元组
opacity: 不透明度
blur_radius: 模糊半径
Returns:
添加腮红效果的图像
"""
if opacity is None:
opacity = self.config.BLUSH_OPACITY
if blur_radius is None:
blur_radius = self.config.BLUSH_BLUR_RADIUS
result = image.copy()
h, w = result.shape[:2]
faces = self.face_detector.detect(result)
if not faces:
print("[WARNING] 未检测到人脸,无法应用腮红")
return result
for face in faces:
landmarks = face.landmarks
# 获取颧骨参考点
cheek_points = landmarks[[1, 15]] # 下巴两侧点
nose_bottom = landmarks[33] # 鼻底中点
# 创建双侧腮红掩码
left_cheek_mask = self._create_blush_mask(
h, w, cheek_points[0], nose_bottom, side='left'
)
right_cheek_mask = self._create_blush_mask(
h, w, cheek_points[1], nose_bottom, side='right'
)
# 应用左侧腮红
result = self._blend_with_mask(
result, left_cheek_mask, color, opacity, blur_radius
)
# 应用右侧腮红
result = self._blend_with_mask(
result, right_cheek_mask, color, opacity, blur_radius
)
return result
def apply_mascara(
self,
image: np.ndarray,
thickness: int = None
) -> np.ndarray:
"""
应用睫毛效果(增强眼部轮廓)
通过增强眼部边缘线条模拟睫毛效果
Args:
image: 原始BGR图像
thickness: 线条粗细
Returns:
添加睫毛效果的图像
"""
if thickness is None:
thickness = self.config.MASCARA_THICKNESS
result = image.copy()
h, w = result.shape[:2]
faces = self.face_detector.detect(result)
if not faces:
return result
for face in faces:
landmarks = face.landmarks
# 左眼轮廓
left_eye = landmarks[36:42]
# 右眼轮廓
right_eye = landmarks[42:48]
# 绘制睫毛线条(黑色细线)
cv2.polylines(result, [left_eye.astype(int)], True,
(30, 30, 30), thickness)
cv2.polylines(result, [right_eye.astype(int)], True,
(30, 30, 30), thickness)
return result
def apply_full_makeup(
self,
image: np.ndarray,
makeup_config: Dict
) -> np.ndarray:
"""
应用完整妆容
按正确顺序叠加各妆容效果:
1. 底妆/腮红(最先,作为基础)
2. 眼影
3. 睫毛
4. 口红(最后,避免被其他效果覆盖)
Args:
image: 原始BGR图像
makeup_config: 妆容配置字典
Returns:
完整妆容效果图
"""
result = image.copy()
# 解析妆容配置
lipstick_color = makeup_config.get('lipstick', {})
eye_shadow_color = makeup_config.get('eye_shadow', {})
blush_color = makeup_config.get('blush', {})
mascara = makeup_config.get('mascara', False)
# 1. 应用腮红
if blush_color and blush_color[0]:
result = self.apply_blush(
result,
blush_color[0],
blush_color[1] if len(blush_color) > 1 else None
)
# 2. 应用眼影
if eye_shadow_color and eye_shadow_color[0]:
result = self.apply_eye_shadow(
result,
eye_shadow_color[0],
eye_shadow_color[1] if len(eye_shadow_color) > 1 else None
)
# 3. 应用睫毛
if mascara:
result = self.apply_mascara(result)
# 4. 应用口红
if lipstick_color and lipstick_color[0]:
result = self.apply_lipstick(
result,
lipstick_color[0],
lipstick_color[1] if len(lipstick_color) > 1 else None
)
return result
def apply_preset_makeup(
self,
image: np.ndarray,
preset_name: str
) -> np.ndarray:
"""
应用预设妆容方案
Args:
image: 原始BGR图像
preset_name: 预设名称
Returns:
应用预设妆容后的图像
"""
if preset_name not in self.config.PRESET_MAKEUPS:
print(f"[WARNING] 未找到预设妆容: {preset_name}")
return image
makeup_config = self.config.PRESET_MAKEUPS[preset_name]
return self.apply_full_makeup(image, makeup_config)
# ==================== 私有辅助方法 ====================
def _create_lip_mask(
self,
h: int,
w: int,
outer_contour: np.ndarray,
inner_contour: np.ndarray
) -> np.ndarray:
"""
创建嘴唇区域的掩码
使用多边形填充创建精确的嘴唇形状
Args:
h, w: 图像尺寸
outer_contour: 外唇轮廓点
inner_contour: 内唇轮廓点
Re
利用AI解决实际问题,如果你觉得这个工具好用,欢迎关注长安牧笛!