Разработка AI-системы виртуальной примерки макияжа
Virtual makeup try-on позволяет пользователям «примерять» косметику в реальном времени через камеру или на загруженном фото. Используется в приложениях бьюти-брендов, маркетплейсах косметики, AR-фильтрах.
Подходы к реализации
Подход 1: Landmark-based (быстрый, для real-time)
- Детекция 468 ключевых точек лица (MediaPipe Face Mesh)
- Рендеринг косметики через mesh overlay
- < 5 мс, работает в браузере через WebGL
Подход 2: AI-генеративный (высокое качество, офлайн)
- Stable Diffusion inpainting с маской области нанесения
- Реалистичная текстура и отражения
- 5–15 сек, требует GPU
MediaPipe подход (real-time)
import mediapipe as mp
import cv2
import numpy as np
from PIL import Image
class RealTimeMakeupAR:
def __init__(self):
self.face_mesh = mp.solutions.face_mesh.FaceMesh(
static_image_mode=False,
max_num_faces=1,
min_detection_confidence=0.5,
min_tracking_confidence=0.5
)
# Индексы точек MediaPipe для частей лица
LIPS_INDICES = [61, 185, 40, 39, 37, 0, 267, 269, 270, 409, 291, 375, 321, 405, 314, 17, 84, 181, 91, 146]
UPPER_LID_L = [362, 382, 381, 380, 374, 373, 390, 249, 263, 466, 388, 387, 386, 385, 384, 398]
CHEEKS_L = [36, 31, 228, 229, 230, 231, 232, 233, 244, 245, 188, 174, 177, 215, 213, 192]
def apply_lipstick(
self,
frame: np.ndarray,
color: tuple, # (R, G, B)
opacity: float = 0.6
) -> np.ndarray:
rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
results = self.face_mesh.process(rgb)
if not results.multi_face_landmarks:
return frame
landmarks = results.multi_face_landmarks[0]
h, w = frame.shape[:2]
# Координаты губ
lip_points = np.array([
[int(landmarks.landmark[i].x * w),
int(landmarks.landmark[i].y * h)]
for i in self.LIPS_INDICES
], dtype=np.int32)
# Рендерим помаду
overlay = frame.copy()
cv2.fillPoly(overlay, [lip_points], color[::-1]) # BGR
result = cv2.addWeighted(frame, 1 - opacity, overlay, opacity, 0)
return result
def apply_eyeshadow(
self,
frame: np.ndarray,
color: tuple,
opacity: float = 0.5
) -> np.ndarray:
# Аналогично для верхних век
rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
results = self.face_mesh.process(rgb)
if not results.multi_face_landmarks:
return frame
landmarks = results.multi_face_landmarks[0]
h, w = frame.shape[:2]
for indices in [self.UPPER_LID_L]:
points = np.array([
[int(landmarks.landmark[i].x * w), int(landmarks.landmark[i].y * h)]
for i in indices
], dtype=np.int32)
overlay = frame.copy()
cv2.fillPoly(overlay, [points], color[::-1])
frame = cv2.addWeighted(frame, 1 - opacity, overlay, opacity, 0)
return frame
AI-генеративный подход (высокое качество)
from diffusers import StableDiffusionXLInpaintPipeline
import torch
class AIPhotoMakeupTryOn:
def __init__(self):
self.pipe = StableDiffusionXLInpaintPipeline.from_pretrained(
"diffusers/stable-diffusion-xl-1.0-inpainting-0.1",
torch_dtype=torch.float16
).to("cuda")
self.face_parser = FaceParser() # Bisenet / SCHP
def apply_makeup_ai(
self,
photo: bytes,
makeup_style: str, # "natural glow", "smoky eye", "bold red lip"
intensity: float = 0.7
) -> bytes:
img = Image.open(io.BytesIO(photo)).convert("RGB")
# Маска для зон нанесения макияжа
face_mask = self.face_parser.get_makeup_zone_mask(img)
result = self.pipe(
prompt=f"beautiful makeup, {makeup_style}, natural skin texture, professional beauty photography",
negative_prompt="unnatural, heavy, clown, overdone, smeared",
image=img,
mask_image=face_mask,
strength=intensity,
num_inference_steps=30,
guidance_scale=8.0
).images[0]
buf = io.BytesIO()
result.save(buf, format="PNG")
return buf.getvalue()
Браузерная real-time реализация
// TensorFlow.js + MediaPipe WASM — работает без сервера
import * as faceMesh from '@mediapipe/face_mesh';
import * as drawingUtils from '@mediapipe/drawing_utils';
const faceMeshInstance = new faceMesh.FaceMesh({locateFile: (file) => {
return `https://cdn.jsdelivr.net/npm/@mediapipe/face_mesh/${file}`;
}});
faceMeshInstance.setOptions({
maxNumFaces: 1,
minDetectionConfidence: 0.5,
minTrackingConfidence: 0.5
});
// Рендерим макияж на canvas поверх видео
function renderLipstick(ctx, landmarks, color, opacity) {
const lipIndices = [61, 185, 40, 39, 37, 0, 267, 269, 270, 409, 291, 375];
ctx.globalAlpha = opacity;
ctx.fillStyle = color;
ctx.beginPath();
lipIndices.forEach((idx, i) => {
const lm = landmarks[idx];
if (i === 0) ctx.moveTo(lm.x * canvas.width, lm.y * canvas.height);
else ctx.lineTo(lm.x * canvas.width, lm.y * canvas.height);
});
ctx.closePath();
ctx.fill();
ctx.globalAlpha = 1.0;
}
Архитектура продукта
Веб/мобильное приложение
├── Camera/Photo mode
│ ├── Real-time: MediaPipe WASM + WebGL (< 5мс)
│ └── Photo: AI inpainting API (10–15 сек)
├── Product catalog (оттенки помады, теней)
├── Shade picker + color mixer
└── Share / Download result
Сроки: браузерный real-time AR макияж (MediaPipe) — 3–4 недели. AI фото-примерка с API — 1–2 недели. Полное мобильное приложение с каталогом — 3–4 месяца.







