Python人脸识别实战——基于Dlib和OpenCV的人脸识别与关键点检测(附完整代码和结果图)

Python人脸识别实战——基于Dlib和OpenCV的人脸识别与关键点检测(附完整代码和结果图)


关于作者


作者:小白熊

作者简介:精通python、matlab、c#语言,擅长机器学习,深度学习,机器视觉,目标检测,图像分类,姿态识别,语义分割,路径规划,智能优化算法,数据分析,各类创新融合等等。

联系邮箱:xbx3144@163.com

科研辅导、知识付费答疑、个性化定制以及其他合作需求请联系作者~



1 引言


  在这篇博文中,博主将展示如何使用Python中的Dlib库对人脸进行关键点检测,并利用OpenCV绘制关键点。人脸关键点检测是计算机视觉领域的一项重要任务。我们可以通过检测人脸上的特定位置(如眼睛、鼻子、嘴唇等)来分析面部特征。在这篇文章中,我们将基于Dlib库的预训练模型shape_predictor_68_face_landmarks.dat,结合OpenCV进行人脸关键点的绘制。



2 模型理论

2.1 人脸识别

  人脸识别是定位图像或视频中的人脸的过程。经典的HOG(Histogram of Oriented Gradients,方向梯度直方图)特征提取方法是Dlib中的核心方法之一。

  • HOG特征:HOG是一种用于对象检测的图像描述方法,它通过统计图像中局部区域的梯度方向来提取物体的形状特征。
  • SVM分类器:Dlib使用支持向量机(SVM)分类器来检测面部,HOG特征被送入SVM分类器进行人脸与非人脸的分类。

  Dlib的get_frontal_face_detector()方法基于HOG特征和SVM分类器,能够快速准确地检测出人脸的边界框。


2.2 关键点检测

  关键点检测属于回归任务,它根据输入的图像预测人脸上各个特定部位的坐标。Dlib使用的是经典的**回归树(Regression Tree)*算法,具体为*基于局部二值模式(Local Binary Features)特征的回归树模型

  • 回归树模型:这种模型在初始人脸检测的基础上,通过多次迭代逐步逼近真实的关键点位置。
  • 68关键点模型:Dlib提供了一个68个点的模型(shape_predictor_68_face_landmarks.dat),它能够精确定位包括脸部轮廓、眉毛、眼睛、鼻子、嘴唇等部位的68个点。

2.3 工作流程

  1. 输入图像:提供一张待检测的图像。
  2. 人脸检测:使用HOG特征提取与SVM分类器检测人脸的边界框。
  3. 关键点预测:基于回归树模型,对人脸区域内的68个关键点进行预测。
  4. 关键点绘制:使用OpenCV对检测到的关键点进行绘制。



3 依赖库

我们需要以下库来实现这一功能:

  • dlib:用于人脸检测和关键点识别
  • opencv-python:用于加载图像并绘制关键点
  • numpy:用于处理数组和矩阵
  • warnings:用于忽略不必要的警告

可以通过以下命令安装这些库:

pip install opencv-python dlib numpy



4 代码讲解

4.1 导入所需模块

pythonCopy codeimport os
import cv2
import dlib
import numpy as np
import warnings

warnings.filterwarnings("ignore")  # 忽略警告

首先需要导入上述模块,并且为了保持输出的清晰性,我们使用warnings.filterwarnings("ignore")来忽略警告信息。


4.2 定义关键点类型及其颜色

pred_types = {
    'face': ((0, 17), (0.682, 0.780, 0.909, 0.5)),
    'eyebrow1': ((17, 22), (1.0, 0.498, 0.055, 0.4)),
    'eyebrow2': ((22, 27), (1.0, 0.498, 0.055, 0.4)),
    'nose': ((27, 31), (0.345, 0.239, 0.443, 0.4)),
    'nostril': ((31, 36), (0.345, 0.239, 0.443, 0.4)),
    'eye1': ((36, 42), (0.596, 0.875, 0.541, 0.3)),
    'eye2': ((42, 48), (0.596, 0.875, 0.541, 0.3)),
    'lips': ((48, 60), (0.596, 0.875, 0.541, 0.3)),
    'teeth': ((60, 68), (0.596, 0.875, 0.541, 0.4))
}

这个字典定义了各部分关键点的范围以及对应的颜色,用于后续绘制。


4.3 绘制关键点和连线的函数

我们定义了两个函数来实现关键点的绘制:

  • draw_line():用于绘制两个连续关键点之间的直线。
  • draw_line_circle():用于绘制一圈关键点的连线,适用于嘴唇、眼睛等区域。
def draw_line(img, shape, i):
    cv2.line(img, (shape.part(i).x, shape.part(i).y), 
             (shape.part(i + 1).x, shape.part(i + 1).y),
             color=(0, 255, 0), thickness=1, lineType=cv2.LINE_AA)

def draw_line_circle(img, shape, i, start, end):
    cv2.line(img, (shape.part(i).x, shape.part(i).y), 
             (shape.part(i + 1).x, shape.part(i + 1).y),
             color=(0, 255, 0), thickness=1, lineType=cv2.LINE_AA)
    cv2.line(img, (shape.part(start).x, shape.part(start).y), 
             (shape.part(end).x, shape.part(end).y),
             color=(0, 255, 0), thickness=1, lineType=cv2.LINE_AA)

4.4 人脸识别和关键点检测

  在dlib_face_keypoint_detector()函数中,我们使用Dlib预训练模型shape_predictor_68_face_landmarks.dat来加载人脸关键点检测模型。然后,我们使用detector来检测图像中的人脸,接着使用predictor来识别人脸的68个关键点。

下载人脸关键点检测模型http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2

def dlib_face_keypoint_detector(img_path, save_result=True):
    detector = dlib.get_frontal_face_detector()
    predictor_path = './model/shape_predictor_68_face_landmarks.dat'
    predictor = dlib.shape_predictor(predictor_path)

    img = cv2.imread(img_path)
    dets = detector(img, 1)
    
    for k, d in enumerate(dets):
        shape = predictor(img, d)
        for i, point in enumerate(shape.parts()):
            x, y = point.x, point.y
            cv2.circle(img, (x, y), 1, color=(255, 0, 255), thickness=1)
            cv2.putText(img, str(i + 1), (x, y), fontFace=cv2.FONT_HERSHEY_SCRIPT_SIMPLEX,
                        fontScale=0.3, color=(255, 255, 0))
            
            # 连接关键点
            if i + 1 < 17:  # face
                draw_line(img, shape, i)
            elif 17 < i + 1 < 22:  # eyebrow1
                draw_line(img, shape, i)
            elif 22 < i + 1 < 27:  # eyebrow2
                draw_line(img, shape, i)
            elif 27 < i + 1 < 31:  # nose
                draw_line(img, shape, i)
            elif 31 < i + 1 < 36:  # nostril
                draw_line(img, shape, i)
            elif 36 < i + 1 < 42:  # eye1
                draw_line_circle(img, shape, i, 36, 42 - 1)
            elif 42 < i + 1 < 48:  # eye2
                draw_line_circle(img, shape, i, 42, 48 - 1)
            elif 48 < i + 1 < 60:  # lips
                draw_line_circle(img, shape, i, 48, 60 - 1)
            elif 60 < i + 1 < 68:  # teeth
                draw_line_circle(img, shape, i, 60, 68 - 1)

    cv2.imshow('detect keypoints', img)
    if save_result:
        save_filename = img_path.split('.')[0] + '_keypoint.' + img_path.split('.')[1]
        cv2.imwrite(save_filename, img)
    cv2.waitKey(0)

4.5 运行程序

运行主函数,img_path是待识别图片的路径。

if __name__ == '__main__':
    dlib_face_keypoint_detector('./images/test.jpg')



5 结果展示


原图:

原图



运行代码后,程序会在图像上绘制人脸的矩形框和68个关键点。每个关键点将被标注序号,并且相关部分(如眼睛、嘴巴)会被连成线:

人脸识别



6 完整代码

import os
import cv2
import dlib
import numpy as np
import warnings

warnings.filterwarnings("ignore")


pred_types = {'face': ((0, 17), (0.682, 0.780, 0.909, 0.5)),
              'eyebrow1': ((17, 22), (1.0, 0.498, 0.055, 0.4)),
              'eyebrow2': ((22, 27), (1.0, 0.498, 0.055, 0.4)),
              'nose': ((27, 31), (0.345, 0.239, 0.443, 0.4)),
              'nostril': ((31, 36), (0.345, 0.239, 0.443, 0.4)),
              'eye1': ((36, 42), (0.596, 0.875, 0.541, 0.3)),
              'eye2': ((42, 48), (0.596, 0.875, 0.541, 0.3)),
              'lips': ((48, 60), (0.596, 0.875, 0.541, 0.3)),
              'teeth': ((60, 68), (0.596, 0.875, 0.541, 0.4))
              }

def draw_line(img, shape, i):
    cv2.line(img, pt1=(shape.part(i).x, shape.part(i).y), pt2=(shape.part(i + 1).x, shape.part(i + 1).y),
             color=(0, 255, 0), thickness=1, lineType=cv2.LINE_AA)


def draw_line_circle(img, shape, i, start, end):
    cv2.line(img, pt1=(shape.part(i).x, shape.part(i).y), pt2=(shape.part(i + 1).x, shape.part(i + 1).y),
             color=(0, 255, 0), thickness=1, lineType=cv2.LINE_AA)

    cv2.line(img, pt1=(shape.part(start).x, shape.part(start).y), pt2=(shape.part(end).x, shape.part(end).y),
             color=(0, 255, 0), thickness=1, lineType=cv2.LINE_AA)

def dlib_face_keypoint_detector(img_path, save_result=True):
    # 检测人脸框
    detector = dlib.get_frontal_face_detector()
    
    predictor_path = './model/shape_predictor_68_face_landmarks.dat'

    # 检测人脸关键点
    predictor = dlib.shape_predictor(predictor_path)

    img = cv2.imread(img_path)
    print("Processing file: {}".format(img_path))
    dets = detector(img, 1)
    print("Number of faces detected: {}".format(len(dets)))
    for k, d in enumerate(dets):
        x1 = d.left()
        y1 = d.top()
        x2 = d.right()
        y2 = d.bottom()
        print("Detection {}: Left: {} Top: {} Right: {} Bottom: {}".format(k, x1, y1, x2, y2))
        cv2.rectangle(img, (x1, y1), (x2, y2), color=(0, 255, 255), thickness=1, lineType=cv2.LINE_AA)
        shape = predictor(img, d)
        print(shape.num_parts) 
        print(shape.rect)  
        print(
            shape.parts())  
        print("Part 0: {}, Part 1: {} ...".format(shape.part(0), shape.part(1)))

        landmarks = np.matrix([[p.x, p.y] for p in shape.parts()])
        # 绘制所有的关键点
        for i, point in enumerate(shape.parts()):
            x = point.x
            y = point.y
            cv2.circle(img, (x, y), 1, color=(255, 0, 255), thickness=1, lineType=cv2.LINE_AA)
            cv2.putText(img, str(i + 1), (x, y), fontFace=cv2.FONT_HERSHEY_SCRIPT_SIMPLEX,
                        fontScale=0.3, color=(255, 255, 0))

            # 连接关键点
            if i + 1 < 17:  # face
                draw_line(img, shape, i)
            elif 17 < i + 1 < 22:  # eyebrow1
                draw_line(img, shape, i)
            elif 22 < i + 1 < 27:  # eyebrow2
                draw_line(img, shape, i)
            elif 27 < i + 1 < 31:  # nose
                draw_line(img, shape, i)
            elif 31 < i + 1 < 36:  # nostril
                draw_line(img, shape, i)
            elif 36 < i + 1 < 42:  # eye1
                draw_line_circle(img, shape, i, 36, 42 - 1)
            elif 42 < i + 1 < 48:  # eye2
                draw_line_circle(img, shape, i, 42, 48 - 1)
            elif 48 < i + 1 < 60:  # lips
                draw_line_circle(img, shape, i, 48, 60 - 1)
            elif 60 < i + 1 < 68:  # teeth
                draw_line_circle(img, shape, i, 60, 68 - 1)

    cv2.imshow('detect keypoints', img)
    if save_result:
        dir, filename = os.path.split(img_path)
        save_filename = os.path.join(dir, filename.split('.')[0] + '_keypoint' + '.' + filename.split('.')[1])
        cv2.imwrite(save_filename, img)
    cv2.waitKey(0)


if __name__ == '__main__':
    dlib_face_keypoint_detector('./images/test.jpg')



7 总结

  通过这篇文章,我们展示了如何利用Dlib和OpenCV来检测和绘制人脸关键点。这项技术可以广泛应用于人脸识别、表情分析和美颜效果等领域。你可以根据自己的需求进行调整或扩展。如果你有任何问题或建议,欢迎留言讨论!


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小白熊_XBX

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值