美颜是直播、相机、视频通话的绝对刚需。磨皮、美白、瘦脸、大眼,传统美颜靠肤色检测和几何变形,AI 美颜靠关键点 + 语义分割,既磨得自然又不糊五官。
1、你遇到的场景
“做相机 App,美颜强度一拉高就变成’塑料脸’——皮肤磨得像硅胶,眉毛眼睛都糊了。想用 AI 美颜,结果发现美颜不是单一算法,是磨皮、美白、瘦脸、大眼一堆算法的组合,GPU 跑起来发烫掉帧……”
端侧 AI 美颜的三座山:
- 自然度 — 磨皮太狠变塑料感,五官保护是难点
- 实时算力 — 一堆滤镜叠加,GPU 负载拉满
- 效果一致性 — 不同肤色、光照下效果要稳
2、美颜的算法矩阵
美颜不是「一个模型」,是「一组算子」的组合,各管一摊:
| 模块 | 传统做法 | AI 做法 | 作用 |
|---|---|---|---|
| 磨皮 | 高斯模糊 + 肤色 mask | 语义分割皮肤 mask + 引导滤波 | 去斑、去痘、柔化 |
| 美白 | 肤色区域提亮 | 分割 skin + 肤色映射 | 提亮肤色 |
| 瘦脸 | 关键点驱动网格变形 | 关键点 + 平滑 warp | 脸部几何调整 |
| 大眼 | 关键点局部放大 | 关键点 + 局部 warp | 眼睛放大 |
| 风格化 | — | 语义分割 + 风格迁移 | 卡通化、油画化 |
核心洞察: 美颜的关键是「分区域处理」——皮肤要磨,但五官(眉毛、眼睛、嘴唇、发丝)不能磨。所以第一步一定是语义分割:把 skin / 五官 / 头发分出来,磨皮只在 skin 区域生效,五官用 mask 保护。
AI 美颜管线:
相机帧 → 人脸检测 + 关键点 → 语义分割(皮肤/五官 mask)
↓
磨皮(仅 skin 区域) → 美白(肤色映射) → 五官保护 mask 反乘
↓
瘦脸/大眼(关键点驱动 warp) → 输出帧
3、皮肤分割 + 磨皮核
# 训练侧:皮肤语义分割(与上篇人像分割同架构,改成多类)
# face_parsing.py(Claude Code 生成)
# 输出 N 类:0背景 1皮肤 2眉毛 3眼睛 4嘴唇 5鼻子 6头发 ...
import torch
import torch.nn as nn
class FaceParsing(nn.Module):
"""输入人脸 crop (1,3,256,256),输出 (1,N,256,256) 类别 logit"""
def __init__(self, n_classes=8):
super().__init__()
from torchvision.models import mobilenet_v3_small
self.enc = mobilenet_v3_small(pretrained=True).features
self.dec = nn.Sequential(
nn.Conv2d(576, 128, 1),
nn.Upsample(scale_factor=8, mode='bilinear', align_corners=False),
nn.Conv2d(128, n_classes, 3, padding=1),
)
def forward(self, x):
return self.dec(self.enc(x))
# 磨皮核:引导滤波(保边缘平滑),传统但实用
# 对 skin 区域做引导滤波,平滑掉痘痘/斑,但保留轮廓
def skin_smooth(img,
4、端侧实时美颜
// BeautyFilter.swift (iOS)
// AI 美颜:分割 → 磨皮/美白 → 五官保护 → warp
finalclass BeautyFilter {
privatelet parsing: MLInferenceEngine
privatelet landmarks: LandmarkTracker
func process(_ frame: CVPixelBuffer, level: Float) -> CVPixelBuffer? {
// 1. 人脸检测 + 关键点 + 语义分割
let pts = landmarks.track(frame)
let logits = try! parsing.predict(tensorFrom(cropFace(frame, pts)))
let masks = softmax(logits) // (N, H, W) 各类别概率
let skin = masks[1] // 皮肤类
let facial = masks[2...7].reduce(0, +) // 五官类合并
// 2. 磨皮:只在皮肤区域,强度随 level 走
let smooth = skinSmooth(frame, skinMask: skin, radius: 4 + level * 4)
// 3. 美白:肤色区域提亮(LUT 或曲线)
let whitened = whiten(smooth, skinMask: skin, amount: level)
// 4. 五官保护:五官区域用原图,避免磨皮糊掉
let protected = whitened * (1 - facial) + frame * facial
// 5. 瘦脸/大眼:关键点驱动 warp
return warp(protected, landmarks: pts, slim: level * 0.5, eye: level)
}
}
// BeautyFilter.kt (Android)
// 美颜:RenderScript / GL 上做,比 CPU 快
class BeautyFilter(
privateval parsing: MLInferenceEngine,
privateval landmarks: LandmarkTracker
) {
fun process(frame: Bitmap, level: Float): Bitmap {
val pts = landmarks.track(frame)
val logits = parsing.predict(tensorFrom(cropFace(frame, pts)))
val masks = softmax(logits)
val skin = masks[1]
val facial = masks.sliceArray(2..7).sum()
val smooth = skinSmooth(frame, skin, 4 + level * 4)
val whitened = whiten(smooth, skin, level)
valprotected = blend(whitened, frame, facial)
return warp(protected, pts, level * 0.5f, level)
}
}
5、自然度与性能的平衡
技巧 1:磨皮强度分级 —— level 0.3 轻微磨,0.7 重磨,1.0 容易塑料感
技巧 2:五官保护 —— 分割出五官 mask,磨皮结果在五官处还原原图
技巧 3:分分辨率 —— 分割在 256x256 跑,磨皮在原分辨率做,兼顾速度与质量
技巧 4:肤色自适应 —— 根据肤色直方图调美白曲线,避免惨白
| 强度 | 磨皮半径 | 美白量 | 主观观感 |
|---|---|---|---|
| 0.3 | 3 | 轻 | 自然 |
| 0.7 | 6 | 中 | 明显但不假 |
| 1.0 | 10 | 重 | 易塑料感 |
6、踩坑记录
| # | 问题 | 现象 | 根因 | 修复 |
|---|---|---|---|---|
| 1 | 塑料脸 | 磨皮后皮肤像硅胶 | 磨皮半径太大 + 五官没保护 | 半径分级 + 五官 mask 保护 |
| 2 | 眉毛被糊 | 眉毛边缘模糊 | 分割把眉毛当皮肤 | 训练集细分眉毛类 + mask 保护 |
| 3 | 惨白 | 美白后脸色发灰 | 提亮曲线全局用 | 按肤色直方图自适应 |
| 4 | 发烫掉帧 | 美颜后帧率骤降 | 全分辨率跑分割 | 分割降分辨率 + GPU 渲染 |
| 5 | 边缘色块 | 磨皮边缘有色块 | skin mask 边缘硬 | skin mask 羽化 + 引导滤波 |
| 6 | 大眼变形 | 眼睛周围扭曲 | warp 影响区域太大 | 局部 warp,限制影响半径 |
学习和提升音视频开发技术,欢迎你加入我们的知识星球

版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。