计算机视觉:人脸关键点定位与轮廓绘制

目录

一、关键模型准备

[二、实战 1:人脸 68 个关键点定位](#二、实战 1:人脸 68 个关键点定位)

[2.1 核心原理](#2.1 核心原理)

[2.2 完整代码实现](#2.2 完整代码实现)

[2.3 结果说明](#2.3 结果说明)

[三、实战 2:基于关键点的面部轮廓绘制](#三、实战 2:基于关键点的面部轮廓绘制)

[3.1 核心原理](#3.1 核心原理)

[3.2 完整代码实现](#3.2 完整代码实现)

[3.3 运行效果](#3.3 运行效果)

四、常见问题与解决方案

1.模型路径错误

2.未检测到人脸

3.关键点绘制错位

五、技术扩展:关键点的应用场景


在计算机视觉领域,人脸关键点检测是表情识别、人脸编辑、疲劳监测等高级应用的核心基础。本文将跳过环境搭建环节,直接从核心原理出发,结合 OpenCV 与 dlib 库,详细讲解人脸 68 个关键点的定位与面部轮廓绘制的完整实现过程。


一、关键模型准备

dlib 的人脸关键点预测依赖预训练模型**shape_predictor_68_face_landmarks.dat**,该模型可精准检测人脸的 68 个关键点(涵盖眼睛、眉毛、鼻子、嘴巴、面部轮廓)。


二、实战 1:人脸 68 个关键点定位

2.1 核心原理

dlib 的关键点检测基于级联回归树算法,整体流程分为三步:

  • 人脸检测 :通过dlib.get_frontal_face_detector()识别图像中的人脸区域,输出人脸边界框;
  • 关键点预测 :利用预训练的shape_predictor模型,在人脸边界框内定位 68 个关键点的坐标;
  • 可视化展示:将关键点坐标转换为 NumPy 数组,通过 OpenCV 绘制关键点及编号,直观呈现检测结果。

2.2 完整代码实现

python 复制代码
'''
功能:检测人脸68个关键点,并绘制关键点及编号
依赖库:numpy, cv2, dlib
模型:shape_predictor_68_face_landmarks.dat(需与代码同目录)
'''
import numpy as np
import cv2
import dlib

# 1. 读取图像(替换为你的图像路径,支持png/jpg格式)
img = cv2.imread("man.png")
# 读取失败判断
if img is None:
    raise ValueError("图像读取失败,请检查文件路径是否正确!")

# 2. 初始化人脸检测器(正面人脸检测)
detector = dlib.get_frontal_face_detector()

# 3. 检测图像中的人脸(参数0:不放大图像,平衡速度与精度)
faces = detector(img, 0)
if len(faces) == 0:
    print("未检测到人脸,请更换清晰正面人脸图像重试!")
else:
    print(f"共检测到 {len(faces)} 张人脸")

# 4. 加载关键点预测模型
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")

# 5. 遍历人脸,获取并绘制关键点
for face in faces:
    # 5.1 预测当前人脸的68个关键点
    shape = predictor(img, face)  # shape包含68个关键点对象
    
    # 5.2 转换关键点为(x, y)坐标数组(便于后续处理)
    landmarks = np.array([[p.x, p.y] for p in shape.parts()])
    
    # 5.3 绘制关键点(绿色实心圆)与编号(白色文字)
    for idx, point in enumerate(landmarks):
        pos = (point[0], point[1])  # 关键点坐标
        # 绘制实心圆:图像、坐标、半径2、颜色(0,255,0)(BGR)、厚度-1(填充)
        cv2.circle(img, pos, radius=2, color=(0, 255, 0), thickness=-1)
        # 绘制编号:字体SIMPLEX、字号0.4、颜色(255,255,255)、厚度1、抗锯齿
        cv2.putText(img, str(idx), pos, cv2.FONT_HERSHEY_SIMPLEX, 
                    fontScale=0.4, color=(255, 255, 255), thickness=1, lineType=cv2.LINE_AA)

# 6. 显示结果与释放资源
cv2.imshow("Face 68 Landmarks", img)
cv2.waitKey(0)  # 按任意键关闭窗口
cv2.destroyAllWindows()

2.3 结果说明

关键点编号规则:68 个关键点按区域划分,具体对应关系如下:

  • 0-16:面部轮廓(从下巴到额头两侧)
  • 17-21:左眉,22-26:右眉
  • 27-35:鼻子(含鼻梁、鼻尖、鼻翼)
  • 36-41:右眼,42-47:左眼
  • 48-67:嘴巴(48-59 为外轮廓,60-67 为内轮廓)

可视化效果:图像中每个关键点以绿色实心圆标记,旁边标注白色编号,可清晰区分不同面部区域的关键点位置。


三、实战 2:基于关键点的面部轮廓绘制

在获取 68 个关键点后,通过凸包算法线段绘制,可进一步勾勒面部轮廓,让检测结果更直观。

3.1 核心原理

  • 凸包算法(cv2.convexHull):对于眼睛、嘴巴等闭合区域,通过关键点生成凸多边形,准确包裹区域边界,避免轮廓断裂;
  • 线段绘制(cv2.line):对于面部轮廓、眉毛、鼻子等非闭合区域,将连续关键点用线段连接,形成完整的线性轮廓。

3.2 完整代码实现

python 复制代码
'''
功能:基于68个关键点绘制面部轮廓(眉毛、眼睛、鼻子、嘴巴、面部轮廓)
依赖库:numpy, cv2, dlib
'''
import numpy as np
import dlib
import cv2

# 1. 定义轮廓绘制工具函数
def draw_line(start, end):
    '''绘制线段:连接从start到end的连续关键点(左闭右开区间)'''
    pts = shape[start:end]  # 获取关键点区间
    for i in range(1, len(pts)):
        pt_a = tuple(pts[i-1])  # 前一个关键点
        pt_b = tuple(pts[i])    # 当前关键点
        # 绘制绿色线段,厚度2
        cv2.line(image, pt_a, pt_b, color=(0, 255, 0), thickness=2)

def draw_convex_hull(start, end):
    '''绘制凸包轮廓:用于眼睛、嘴巴等闭合区域(包含end的闭区间)'''
    facial_pts = shape[start:end+1]  # 获取关键点区间
    hull = cv2.convexHull(facial_pts)  # 生成凸包
    # 绘制绿色凸包轮廓,厚度2(-1表示填充,此处用2保留轮廓线)
    cv2.drawContours(image, [hull], -1, (0, 255, 0), thickness=2)

# 2. 读取图像
image = cv2.imread("man.png")
if image is None:
    raise ValueError("图像读取失败,请检查文件路径!")

# 3. 人脸检测与关键点预测(与实战1逻辑一致)
detector = dlib.get_frontal_face_detector()
faces = detector(image, 0)
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")

if len(faces) == 0:
    print("未检测到人脸!")
else:
    for face in faces:
        # 获取关键点并转换为数组
        shape = predictor(image, face)
        shape = np.array([[p.x, p.y] for p in shape.parts()])
        
        # 4. 按区域绘制轮廓(关键:对应68个关键点的正确区间)
        draw_convex_hull(36, 41)   # 右眼轮廓(36-41号关键点)
        draw_convex_hull(42, 47)   # 左眼轮廓(42-47号关键点)
        draw_convex_hull(48, 59)   # 嘴巴外部轮廓(48-59号关键点)
        draw_convex_hull(60, 67)   # 嘴巴内部轮廓(60-67号关键点)
        draw_line(0, 17)           # 面部轮廓(0-16号,左闭右开需到17)
        draw_line(17, 22)          # 左眉轮廓(17-21号关键点)
        draw_line(22, 27)          # 右眉轮廓(22-26号关键点)
        draw_line(27, 36)          # 鼻子轮廓(27-35号关键点)

# 5. 结果展示与保存(可选)
cv2.imshow("Face Contours", image)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 保存结果图像到当前目录
cv2.imwrite("face_contours_result.png", image)
print("结果图像已保存为 face_contours_result.png")

3.3 运行效果

代码运行后,图像将呈现以下绿色轮廓:

  • 闭合轮廓:左右眼(凸包形状,完整包裹眼球区域)、嘴巴内外侧(区分嘴唇与牙齿边界);
  • 线性轮廓:面部轮廓(从下巴尖沿脸颊到额头两侧)、左右眉毛(沿眉形连接关键点)、鼻子(从鼻梁到鼻尖的中线)。

四、常见问题与解决方案

1.模型路径错误

报错信息:Unable to open shape_predictor_68_face_landmarks.dat

解决:确认模型文件与代码在同一目录,或在shape_predictor中传入完整路径(如"D:/cv_project/shape_predictor_68_face_landmarks.dat")。

2.未检测到人脸

原因:图像中无正面人脸、人脸尺寸过小(小于 80×80 像素,dlib 默认最小检测尺寸)或光线过暗。

解决:更换清晰正面人脸图像,或调整detector参数(如detector(img, 1),1 表示放大图像 1 倍后检测,提升小人脸识别率)。

3.关键点绘制错位

原因:图像读取时通道顺序错误(OpenCV 默认 BGR,若误转为 RGB 会导致坐标偏移)。

解决:确保直接使用cv2.imread()读取图像,不额外转换通道顺序(除非后续有特殊处理需求)。


五、技术扩展:关键点的应用场景

人脸 68 个关键点是计算机视觉中极具价值的基础数据,基于本文技术可进一步扩展以下应用:

表情识别:通过嘴巴关键点(48-67)的开合程度、眼睛关键点(36-47)的眯眼状态,判断微笑、愤怒、惊讶等表情;

疲劳监测:计算眼睛纵横比(如 "眼高 / 眼宽",当比值 < 0.3 时判定为闭眼),统计单位时间内闭眼次数与时长,预警疲劳状态;

人脸编辑 :结合仿射变换(cv2.warpAffine),基于关键点实现人脸对齐、换脸、妆容迁移(如将 A 的眉毛轮廓复制到 B 的脸上)。

相关推荐
爱读源码的大都督3 小时前
Spring AI Alibaba JManus底层实现剖析
java·人工智能·后端
且慢.5893 小时前
机器学习/深度学习名词理解
人工智能·深度学习·机器学习
☆cwlulu3 小时前
解码Android 系统蓝牙音频全流程
前端·人工智能·算法
嘀咕博客3 小时前
GPTEngineer:AI 驱动的Web应用开发平台
前端·人工智能·ai工具
SkyXZ~3 小时前
AWS SageMaker SDK 完整教程:从零开始云端训练你的模型
人工智能·深度学习·云计算·aws·sagemaker·boto3
黎燃3 小时前
RAG 技术合集:检索增强生成的实践指南
人工智能
nju_spy3 小时前
南京大学 LLM开发基础(二)大语言模型解析 -- 基于HF LlaMA实现的讲解
人工智能·pytorch·深度学习·大模型·多头注意力·rmsnorm·位置掩码
胡耀超3 小时前
开源生态与技术民主化 - 从LLaMA到DeepSeek的开源革命(LLaMA、DeepSeek-V3、Mistral 7B)
人工智能·python·神经网络·开源·大模型·llama·deepseek
weixin_446260854 小时前
轻松在家构建AI集群,开启智能生活
人工智能·生活