女生妆容效果数字预览,试妆不用卸妆。

1 阅读11分钟

女生妆容效果数字预览系统

一、实际应用场景描述

在美妆行业蓬勃发展的今天,数字艺术与化妆技术的结合为女性消费者带来了全新的体验。本系统主要应用于以下场景:

  1. 美妆品牌专柜:顾客可现场通过AR试妆,快速找到适合的口红、眼影颜色
  2. 线上购物平台:用户上传照片即可虚拟试色,减少因色差导致的退货
  3. 美妆教学机构:学员可模拟不同妆容效果,提高学习效率
  4. 个人日常使用:用户可尝试各种流行妆容,找到最适合自己的风格

二、引入痛点

传统试妆方式存在以下问题:

  • 时间成本高:实体试妆需逐层涂抹,反复修改
  • 卫生隐患:多人共用化妆品易引发皮肤问题
  • 色差困扰:不同光线、肤色下试色效果差异大
  • 不可逆性:不满意需完全卸妆,损伤皮肤屏障
  • 选择困难:面对众多产品难以快速决策

三、核心逻辑讲解

本系统采用"图像识别+数字叠加+色彩融合"的技术路线:

  1. 面部检测:使用dlib/face_recognition库定位面部关键点
  2. 区域划分:根据68个特征点确定眼、唇、脸颊等妆容区域
  3. 颜色叠加:将预设妆容素材与用户照片进行alpha混合
  4. 边缘融合:使用高斯模糊处理边缘,实现自然过渡
  5. 实时渲染:支持摄像头视频流实时试妆

四、项目结构

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 # 项目说明

五、核心代码实现

  1. 主程序入口 (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()

  1. 配置文件 (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 } }

  1. 人脸检测模块 (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解决实际问题,如果你觉得这个工具好用,欢迎关注长安牧笛!