RetinaFace开源模型实战:基于关键点的瘦脸/大眼/美白等基础美颜算法接入教程
RetinaFace开源模型实战:基于关键点的瘦脸/大眼/美白等基础美颜算法接入教程
你有没有想过,那些手机App里一键就能完成的瘦脸、大眼、美白效果,背后其实并不神秘?它们大多依赖一个共同的基础——精准的人脸关键点定位。而RetinaFace,就是目前开源社区中人脸检测与关键点识别最稳、最准、最容易上手的模型之一。
这篇文章不讲论文、不堆参数,只带你从零开始,把RetinaFace跑起来,再用它输出的5个关键点(双眼中心、鼻尖、左右嘴角),真正动手实现几个实用的美颜小功能:让眼睛变大一点、让脸型更立体、让肤色更均匀。整个过程不需要训练模型,不用配环境,镜像已预装好所有依赖,10分钟内你就能看到自己照片被“智能调整”后的效果。
1. 为什么是RetinaFace?它到底能给你什么
很多人一听到“人脸关键点”,第一反应是“我只需要检测出人脸框就够了”。但真实场景中,光有框远远不够。比如你想做瘦脸,框只能告诉你“这张脸在哪”,却没法告诉你“颧骨在哪、下颌线在哪、眼睛该往哪拉”。这时候,关键点就是桥梁——它把一张模糊的脸,变成了可计算、可变形、可编辑的坐标集合。
RetinaFace之所以被广泛选用,不是因为它最炫酷,而是因为它足够“靠谱”:
- 它能稳定输出5个高精度关键点:左眼中心、右眼中心、鼻尖、左嘴角、右嘴角。这5个点虽然不多,但恰好覆盖了面部最核心的形变区域;
- 对小脸、侧脸、部分遮挡(比如戴口罩、头发遮挡)的鲁棒性极强,不像一些轻量模型在合影里经常漏检;
- 推理速度快,ResNet50版本在单张RTX 4090上平均耗时不到80ms,完全满足本地实时处理需求;
- 关键点坐标是浮点数,精度到像素级小数,为后续几何变换(比如仿射缩放、三角形网格变形)提供了扎实基础。
换句话说,RetinaFace不是终点,而是你搭建个性化美颜能力的第一块稳固地砖。它不负责“变美”,但它确保你每次操作,都精准落在该落的地方。
2. 镜像环境准备:3步启动,无需安装任何东西
本教程基于CSDN星图提供的 RetinaFace人脸检测与关键点绘制镜像,已为你预装全部依赖并优化推理流程。你不需要配置CUDA、不用pip install一堆包、也不用下载模型权重——所有这些,镜像启动即就绪。
2.1 环境配置一览
这个镜像不是简单打包,而是针对实际工程使用做了针对性优化:
| 组件 | 版本 | 说明 |
|---|---|---|
| Python | 3.11 | 兼容新特性,同时保持生态稳定 |
| PyTorch | 2.5.0+cu124 | 适配CUDA 12.4,GPU加速开箱即用 |
| CUDA / cuDNN | 12.4 / 9.x | 与主流显卡(RTX 30/40系)完美匹配 |
| ModelScope | 默认 | 自动加载官方模型,免手动下载 |
| 代码位置 | /root/RetinaFace |
所有脚本、示例、工具集中在此目录 |
注意:所有路径和命令均以镜像内默认环境为准,无需额外修改。如果你用的是Docker或云平台一键部署,启动后直接SSH进入即可。
2.2 快速验证:先看一眼关键点长什么样
别急着写代码,我们先确认环境真的跑通了。
打开终端,执行以下三步:
cd /root/RetinaFace
conda activate torch25
python inference_retinaface.py
几秒钟后,你会在当前目录下看到一个新文件夹 face_results,里面有一张名为 retinaface_result.jpg 的图片。打开它——你将看到一张带绿色检测框和5个醒目的红色圆点的图像。这5个红点,就是RetinaFace为你找到的左眼、右眼、鼻尖、左嘴角、右嘴角。
成功标志:红点清晰、位置合理、无明显偏移(比如点在眉毛上或嘴外)。如果出现错位,大概率是输入图过暗或角度过大,稍后我们会讲如何提升稳定性。
3. 提取关键点坐标:从“画点”到“拿数据”
上面的脚本只是可视化,真正驱动美颜的是坐标数值。我们需要把那5个红点变成Python里可运算的 (x, y) 列表。
3.1 修改推理脚本,导出关键点数据
原脚本 inference_retinaface.py 只负责绘图,我们要让它也“吐出”坐标。打开该文件,找到绘图逻辑附近(通常在 for b in boxes: 循环内),添加如下代码:
# 在绘制每个关键点前,添加这一行(约第120行左右)
landmarks = dets[i, 5:15].reshape(5, 2) # Reshape to (5, 2)
print("Detected landmarks (x, y):")
for idx, (x, y) in enumerate(landmarks):
print(f" Point {idx+1}: ({x:.1f}, {y:.1f})")
保存后再次运行:
python inference_retinaface.py --input ./my_test.jpg
你会看到类似这样的输出:
Detected landmarks (x, y):
Point 1: (124.3, 187.6) # 左眼中心
Point 2: (178.9, 186.2) # 右眼中心
Point 3: (152.1, 224.8) # 鼻尖
Point 4: (132.5, 256.4) # 左嘴角
Point 5: (171.7, 255.9) # 右嘴角
小贴士:这5个点的顺序是固定的(ModelScope官方模型约定),无需记忆,直接按索引使用即可:
landmarks[0]是左眼,landmarks[1]是右眼,以此类推。
3.2 封装成函数:一键获取关键点
为了后续复用,我们把它封装成一个干净的函数。新建文件 face_utils.py:
# face_utils.py
import cv2
import numpy as np
from models.retinaface import RetinaFace
def get_face_landmarks(image_path, threshold=0.5):
"""
输入图片路径,返回检测到的首个人脸的5个关键点坐标
返回: list of tuples [(x1,y1), (x2,y2), ..., (x5,y5)] or None
"""
detector = RetinaFace(model_path='/root/RetinaFace/models/Resnet50_Final.pth')
img = cv2.imread(image_path)
if img is None:
print(f"Error: cannot load image {image_path}")
return None
# 检测
dets = detector.detect_faces(img, threshold=threshold)
if len(dets) == 0:
print("No face detected.")
return None
# 取置信度最高的一张脸
best_det = max(dets, key=lambda x: x['score'])
landmarks = best_det['landmarks'] # ModelScope接口已结构化,直接取
return [
(int(landmarks['left_eye'][0]), int(landmarks['left_eye'][1])),
(int(landmarks['right_eye'][0]), int(landmarks['right_eye'][1])),
(int(landmarks['nose'][0]), int(landmarks['nose'][1])),
(int(landmarks['left_mouth'][0]), int(landmarks['left_mouth'][1])),
(int(landmarks['right_mouth'][0]), int(landmarks['right_mouth'][1]))
]
# 测试
if __name__ == "__main__":
pts = get_face_landmarks("./my_test.jpg")
print("Key points:", pts)
现在,只要调用 get_face_landmarks("xxx.jpg"),你就能拿到一个包含5个 (x, y) 元组的列表,美颜算法的“原材料”就齐了。
4. 动手实现三大基础美颜:瘦脸、大眼、美白
有了关键点,接下来就是发挥创意的时候。我们不追求工业级效果,而是用最直观、最易理解的方式,让你亲眼看到坐标变化如何改变一张脸。
4.1 瘦脸:用三角形网格做局部缩放
瘦脸的本质,是向内收缩脸颊区域。我们不用复杂算法,而是用一个经典技巧:以双眼和鼻尖构成一个三角形,再以嘴角为锚点,沿该三角形中线方向压缩。
# 在 face_utils.py 中追加
def apply_face_shrink(image, landmarks, shrink_ratio=0.15):
"""
基于关键点的简易瘦脸
shrink_ratio: 压缩强度 (0.0 ~ 0.3 合理)
"""
img = image.copy()
h, w = img.shape[:2]
# 计算脸部中心线(鼻尖到两眼中心连线的中点)
left_eye, right_eye, nose, left_mouth, right_mouth = landmarks
eye_center_x = (left_eye[0] + right_eye[0]) // 2
eye_center_y = (left_eye[1] + right_eye[1]) // 2
# 脸部宽度参考:两嘴角距离
mouth_width = right_mouth[0] - left_mouth[0]
# 构造变形网格:只对脸颊区域做水平压缩
# 这里简化为:以鼻尖为基准,向左右各取 mouth_width * 0.4 区域进行缩放
delta_x = int(mouth_width * shrink_ratio)
# 创建映射表(仅示意,生产环境建议用cv2.remap)
map_x = np.zeros((h, w), dtype=np.float32)
map_y = np.zeros((h, w), dtype=np.float32)
for y in range(h):
for x in range(w):
# 如果在左脸颊区域(鼻尖x左侧一定范围)
if x < nose[0] and abs(x - nose[0]) < mouth_width * 0.4:
map_x[y, x] = x + (nose[0] - x) * shrink_ratio
# 如果在右脸颊区域(鼻尖x右侧一定范围)
elif x > nose[0] and abs(x - nose[0]) < mouth_width * 0.4:
map_x[y, x] = x - (x - nose[0]) * shrink_ratio
else:
map_x[y, x] = x
map_y[y, x] = y
return cv2.remap(img, map_x, map_y, cv2.INTER_LINEAR)
# 使用示例
img = cv2.imread("./my_test.jpg")
pts = get_face_landmarks("./my_test.jpg")
if pts:
shrunk_img = apply_face_shrink(img, pts, shrink_ratio=0.18)
cv2.imwrite("./shrink_result.jpg", shrunk_img)
效果:脸部轮廓更紧致,下颌线更清晰,但不会失真——因为变形严格限制在关键点定义的区域内。
4.2 大眼:以眼中心为圆心,局部放大
大眼不是简单地把整张图放大,而是以眼球中心为原点,对周围小区域做平滑放大。我们用OpenCV的 cv2.resize + cv2.getRotationMatrix2D 组合实现:
def apply_enlarge_eyes(image, landmarks, scale_factor=1.25, radius=30):
"""
局部放大双眼区域
scale_factor: 放大倍数 (1.1 ~ 1.4)
radius: 影响半径(像素)
"""
img = image.copy()
left_eye, right_eye, *_ = landmarks
for eye_center in [left_eye, right_eye]:
x, y = eye_center
# 截取眼部ROI
roi_x1 = max(0, x - radius)
roi_y1 = max(0, y - radius)
roi_x2 = min(img.shape[1], x + radius)
roi_y2 = min(img.shape[0], y + radius)
roi = img[roi_y1:roi_y2, roi_x1:roi_x2].copy()
# 放大ROI
h, w = roi.shape[:2]
new_h, new_w = int(h * scale_factor), int(w * scale_factor)
enlarged = cv2.resize(roi, (new_w, new_h), interpolation=cv2.INTER_CUBIC)
# 计算居中粘贴位置
paste_x = x - new_w // 2
paste_y = y - new_h // 2
paste_x1 = max(0, paste_x)
paste_y1 = max(0, paste_y)
paste_x2 = min(img.shape[1], paste_x + new_w)
paste_y2 = min(img.shape[0], paste_y + new_h)
# 粘贴回原图(带alpha混合更自然,此处简化)
h_paste = paste_y2 - paste_y1
w_paste = paste_x2 - paste_x1
if h_paste > 0 and w_paste > 0:
enlarged_cropped = enlarged[:h_paste, :w_paste]
img[paste_y1:paste_y2, paste_x1:paste_x2] = enlarged_cropped
return img
# 使用
enlarged_img = apply_enlarge_eyes(img, pts, scale_factor=1.3)
cv2.imwrite("./enlarge_eyes.jpg", enlarged_img)
效果:眼睛看起来更大、更有神,但边缘过渡自然,没有“贴图感”。
4.3 美白:基于关键点划定肤色区域,定向提亮
美白的关键是只提亮皮肤,不提亮头发、衣服、背景。我们利用关键点围成的“面部区域”作为掩膜(mask),再对HSV空间的V通道做温和提升:
def apply_skin_whiten(image, landmarks, strength=0.12):
"""
基于面部关键点的区域美白
strength: 提亮强度 (0.05 ~ 0.2)
"""
img = image.copy()
h, w = img.shape[:2]
# 构建面部多边形掩膜(五点连成面)
pts = np.array(landmarks, dtype=np.int32)
# 补充下巴点(估算:两嘴角中点向下延伸)
chin_x = (landmarks[3][0] + landmarks[4][0]) // 2
chin_y = landmarks[3][1] + (landmarks[3][1] - landmarks[2][1]) * 2
pts = np.append(pts, [[chin_x, chin_y]], axis=0)
mask = np.zeros((h, w), dtype=np.uint8)
cv2.fillConvexPoly(mask, pts, 255)
# 转HSV,只调V通道
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(hsv)
# 对掩膜内区域提亮V值
v_masked = cv2.bitwise_and(v, v, mask=mask)
v_masked = np.clip(v_masked.astype(np.float32) * (1 + strength), 0, 255).astype(np.uint8)
# 合并回HSV并转BGR
hsv_whitened = cv2.merge([h, s, v_masked])
return cv2.cvtColor(hsv_whitened, cv2.COLOR_HSV2BGR)
# 使用
whitened_img = apply_skin_whiten(img, pts, strength=0.15)
cv2.imwrite("./whitened.jpg", whitened_img)
效果:肤色更均匀、透亮,但嘴唇、瞳孔、发色等非皮肤区域完全不受影响。
5. 整合与进阶:从单功能到流水线
上面三个函数是独立的,但在实际使用中,你往往希望“一键美颜”:输入一张图,自动完成检测→瘦脸→大眼→美白→保存。
5.1 构建美颜流水线
新建 beautify_pipeline.py:
import cv2
from face_utils import get_face_landmarks, apply_face_shrink, apply_enlarge_eyes, apply_skin_whiten
def full_beautify(input_path, output_path,
shrink_ratio=0.15,
eye_scale=1.28,
whiten_strength=0.14):
img = cv2.imread(input_path)
if img is None:
print("Failed to load image")
return
pts = get_face_landmarks(input_path)
if not pts:
print("No face detected, skipping beautify")
cv2.imwrite(output_path, img)
return
# 顺序执行(注意:顺序影响最终效果,建议先瘦脸,再大眼,最后美白)
result = apply_face_shrink(img, pts, shrink_ratio)
result = apply_enlarge_eyes(result, pts, eye_scale)
result = apply_skin_whiten(result, pts, whiten_strength)
cv2.imwrite(output_path, result)
print(f"Beautified image saved to {output_path}")
if __name__ == "__main__":
full_beautify("./my_test.jpg", "./beautified_result.jpg")
运行它,一张融合了三项基础美颜效果的图片就生成了。
5.2 实用建议与避坑指南
- 关键点质量决定上限:如果RetinaFace本身关键点偏移超过5像素,后续所有美颜都会失真。建议对低质量输入(如暗光、侧脸)先做直方图均衡化或简单锐化;
- 参数要微调,不要硬套:
shrink_ratio=0.15是通用值,但对圆脸可能需0.18,对窄脸可能0.12,建议准备一组测试图反复调试; - 避免过度处理:大眼超过1.4倍、美白超过0.2,容易产生塑料感。真实美颜App通常默认值都偏保守;
- 性能提示:上述算法都是CPU实现,单图处理约300~500ms。如需实时(>25fps),建议将核心变形逻辑改用CUDA或TensorRT加速。
6. 总结:你已经掌握了美颜的底层钥匙
回顾一下,我们完成了什么:
- 用一行命令启动了预装RetinaFace的镜像,跳过了所有环境配置;
- 修改脚本,把“画红点”变成了“输出坐标”,拿到了可编程的关键点数据;
- 动手实现了瘦脸、大眼、美白三个最常用的基础美颜功能,每一步都基于关键点坐标,逻辑清晰、代码简短;
- 将它们组装成一条可复用的流水线,输入一张图,输出一张美化后的图。
这远不止是一篇“教程”。它是一把钥匙——打开了从“调用API”到“理解原理”再到“自主定制”的大门。你不再需要依赖某个App的固定滤镜,而是可以根据自己的审美,调整参数、增删功能、甚至替换为更先进的关键点模型(比如106点、230点)。
美颜的本质,从来不是掩盖,而是增强;不是千人一面,而是让每个人的特点,被更精准地表达出来。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)