【实操:人脸矫正】两次定位操作解决人脸矫正问题

简介: 【实操:人脸矫正】两次定位操作解决人脸矫正问题

前言

  在实际应用中,由于各种因素的影响,采集到的人脸图像可能存在不同的问题,由于摄像机角度不同、人动作不一样,使得过滤后的人脸还是不满足我们进行特征提取的最佳状 态(训练集中大部分都是正面正脸图片),所以我们还需要对人脸进行对齐和矫正。为了解决这些问题,人脸矫正成为了人脸识别技术中不可或缺的一环。

  在本文中将着重讲解人脸识别过程中的人脸矫正步骤。通过了解人脸矫正的过程和原理,我们将能够更好地理解人脸识别系统是如何处理和利用人脸图像的。

人脸检测及五官定位

  这里可以参考本人之前写的博客:一起来学MediaPipe(一)人脸及五官定位检测 通过mediapipe 库可以轻松解决人脸的定位以及人脸内的五官定位六个部位(双耳2 + 双眼2 + 鼻子1 + 嘴心1)。


解析坐标

  在mediapipe库中,mp_face_detection.FaceDetection函数用于检测图像或视频中的人脸,并返回人脸的坐标信息。函数返回的坐标信息的讲解如下:

  1. LocationData类:mp_face_detection.FaceDetection函数返回一个列表,其中每个元素都是LocationData类的实例。LocationData类包含了表示人脸位置和边界框的属性。
  2. relative_bounding_box:表示检测到的人脸边界框的相对位置。它是一个四维浮点数的元组 (x, y, width, height),其中 (x, y) 是边界框左上角相对于整个图像宽度和高度的比例,width 和 height 是边界框相对于整个图像的宽度和高度的比例。
  3. score:表示检测到的人脸的置信度分数。该分数范围从 0 到 1,表示对检测结果的置信程度,值越高表示置信度越高。

  坐标信息解读:通过使用 relative_bounding_box 的值,可以解读人脸的位置和边界框。其中的x 和 y 表示边界框左上角相对于整个图像的位置。

  例如,如果 x = 0.2,y = 0.3,则边界框的左上角位于图像宽度的 20% 处,高度的 30% 处。width 和 height 表示边界框的宽度和高度相对于整个图像的比例。例如,如果 width = 0.4,height = 0.6,则边界框的宽度为图像宽度的 40%,高度为图像高度的 60%。可以通过将相对坐标与实际图像的宽度和高度相乘,将相对坐标转换为实际坐标。例如,如果图像的宽度为 800 像素,高度为 600 像素,则将 x 乘以 800,y 乘以 600,width 乘以 800,height 乘以 600,就可以得到实际坐标。

博客:一起来学MediaPipe(一)人脸及五官定位检测detection返回信息如下:

shell

复制代码

label_id: 0
score: 0.5956658720970154
location_data {
  format: RELATIVE_BOUNDING_BOX
  relative_bounding_box {
    xmin: 0.23118790984153748
    ymin: 0.09999196231365204
    width: 0.5988736152648926
    height: 0.7984580993652344
  }
  relative_keypoints {
    x: 0.39731642603874207
    y: 0.3905108571052551
  }
  relative_keypoints {
    x: 0.6470986008644104
    y: 0.36055833101272583
  }
  relative_keypoints {
    x: 0.5388920307159424
    y: 0.6023311018943787
  }
  relative_keypoints {
    x: 0.5485179424285889
    y: 0.740068256855011
  }
  relative_keypoints {
    x: 0.2765348255634308
    y: 0.40228205919265747
  }
  relative_keypoints {
    x: 0.7757663130760193
    y: 0.3326093554496765
  }
}

检测函数

  定义一个函数进行处理人脸并返回人脸坐标以及五官坐标,其中box_info返回的是人脸(xmin,ymin,width, height),facial返回的是五官的定位坐标信息

shell

复制代码

def get_face_info(image):
    # To improve performance, optionally mark the image as not writeable to
    # pass by reference.
    image.flags.writeable = False
    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    results = face_detection.process(image)
    # Draw the face detection annotations on the image.
    image.flags.writeable = True
    image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
    box_info, facial = None, None
    if results.detections:
        for detection in results.detections:
            box_info = detection.location_data.relative_bounding_box
            facial = detection.location_data.relative_keypoints
    return cv2.flip(image, 1), box_info, facial


人脸对齐矫正

  人脸对齐矫正用于将人脸图像中的关键点对齐到特定位置,以达到标准化或者更好的分析和比较效果。下面是人脸对齐矫正的基本原理:

  1. 关键点检测:首先,需要通过算法来检测人脸图像中的关键点,例如眼睛、鼻子、嘴巴等。常用的关键点检测算法包括人工标注、Haar级联分类器、深度学习模型等。
  2. 刚性变换:一旦检测到关键点,接下来的目标是将关键点对齐到一个标准的位置。这通常涉及到应用刚性变换,包括平移、旋转和缩放等操作,以使得关键点对应的人脸特征在图像中的位置和大小与标准位置相匹配。
  3. 仿射变换:在某些情况下,刚性变换可能无法完全解决对齐问题,特别是当人脸姿态发生较大变化时。这时,需要使用更灵活的仿射变换,可以通过调整关键点之间的距离、角度和比例来进一步改善对齐效果。
  4. 插值和融合:在完成对齐变换后,可能会产生一些空白区域或者重叠区域。为了消除这些问题,常常使用插值技术来填充空白区域,同时可以通过融合操作来平滑处理重叠区域。

在上述矫正的过程中有两种方案可供备选:一种是使用标准点进行矫正;另一种是采用深度学习方法进行矫正。这二者各有优缺点,在本文中我将主要就讲述第一种方法。


基于标准参考特征点进行旋转平移矫正

  基于标准参考特征点进行旋转平移矫正是一种常用的人脸对齐方法。该方法基于一组预定义的标准参考特征点,通过计算目标人脸的特征点与标准参考特征点之间的差异,来进行旋转和平移变换,以实现人脸对齐的目的。下面是详细的步骤:

image.png

  通过以上步骤,基于标准参考特征点进行旋转平移矫正可以使目标人脸图像的关键点与预定义的标准特征点对齐。这种对齐方法可以有效地纠正人脸图像中的姿态变化,使得后续的人脸分析和处理更加准确和可靠。定义下面函数通过多个关键点进行定位矫正获取矫正后的图像:

shell

复制代码

# 旋转矩阵
def transformation_from_points(points1, points2):
    points1 = points1.astype(np.float64)
    points2 = points2.astype(np.float64)
    c1 = np.mean(points1, axis=0)
    c2 = np.mean(points2, axis=0)
    points1 -= c1
    points2 -= c2
    s1 = np.std(points1)
    s2 = np.std(points2)
    points1 /= s1
    points2 /= s2
    U, S, Vt = np.linalg.svd(points1.T * points2)
    R = (U * Vt).T
    M = np.vstack([
        np.hstack(((s2 / s1) * R, c2.T - (s2 / s1) * R * c1.T)),
        np.asmatrix([0., 0., 1.])])
    return M
# 人脸对齐
def face_alignment(src_landmark6, image_numpy):
    h, w, c = image_numpy.shape
    # 5点对齐后的基准点
    dst_landmark6 = np.asmatrix([[283, 162], # 左眼
                                 [405, 165],# 右眼
                                 [345, 233],# 鼻子
                                 [341, 293], # 嘴心
                                 [212, 187], # 左耳
                                 [463, 195]]) # 右耳
    # 计算旋转矩阵
    M = transformation_from_points(src_landmark6, dst_landmark6)
    # 旋转图像
    align_image = cv2.warpAffine(image_numpy, M[:2], (w, h))
    return align_image

坐标解析函数

  在基于标准参考特征点进行旋转平移矫正函数中可以看见关键点的坐标以及数据格式,对人脸检测函数get_face_info 中获取的坐标进行解析组织,可如下所示:

shell

复制代码

def CoordinateTransformation(w, h, img_box, facial):
    xmin, ymin, width, height = int(img_box.xmin * h), \
                                int(img_box.ymin * w), \
                                int(img_box.width * h), \
                                int(img_box.height * w)
    # 左眼
    key_0_x = int(facial[0].x * h)
    key_0_y = int(img_fa[0].y * w)
    # 右眼
    key_1_x = int(facial[1].x * h)
    key_1_y = int(facial[1].y * w)
    # 鼻子
    key_2_x = int(facial[2].x * h)
    key_2_y = int(facial[2].y * w)
    # 嘴巴
    key_3_x = int(facial[3].x * h)
    key_3_y = int(facial[3].y * w)
    # 左耳
    key_4_x = int(facial[4].x * h)
    key_4_y = int(facial[4].y * w)
    # 右耳
    key_5_x = int(facial[5].x * h)
    key_5_y = int(facial[5].y * w)
 
    keys = np.asmatrix([[key_0_x, key_0_y],
                        [key_1_x, key_1_y],
                        [key_2_x, key_2_y],
                        [key_3_x, key_3_y],
                        [key_4_x, key_4_y],
                        [key_5_x, key_5_y]])
    return xmin, ymin, width, height, keys

完整流程

上面我们定义完成了所有的函数,下面我将讲述如何串联起来进行对齐矫正。大体的思路如下所述:

  1. 获取一张标准人脸头像,使用get_face_info获取五官位置并记录填写到矩阵中;
  2. 调取摄像头并获取人脸;
  3. 使用get_face_info获取五官位置并进行矫正,此时或者矫正后的图像:align_image
  4. 将矫正后的图像align_image再次使用get_face_info函数进行定位人脸区域;
  5. 获取get_face_info函数返回人脸位置信息并ROI处理

shell

复制代码

if __name__ == "__main__":
    mp_face_detection = mp.solutions.face_detection
    mp_drawing = mp.solutions.drawing_utils
    src_img = cv2.imread("wa.jpg")  # 读取原始图像
    src_img_copy = src_img.copy()
    w, h, _ = src_img.shape  # 获取原始图像尺寸
    _, box, fa = get_face_info(src_img)  # 对原始图像中获取翻转后的尺寸 、 人脸坐标集 、 五官坐标集
    xmin, ymin, width, height, keys = CoordinateTransformation(w, h, box, fa)  # 转换各种坐标集格式便于读取
    align_image, _ = face_alignment(keys, src_img)
    align_img, align_box, align_fa = get_face_info(align_image)
    align_w, align_h, _ = align_img.shape
    align_xmin, align_ymin, align_width, align_height, _ = CoordinateTransformation(align_w, align_h, align_box, align_fa)  # 转换各种坐标集格式便于读取
    face_roi = align_image[align_ymin: align_ymin + align_width, align_xmin:align_xmin + align_height]  #
    # 使用人脸坐标对人脸部分裁剪出来 
    face_roi = cv2.resize(face_roi, (150, 150))
    src_img_copy[0:150, 0:150] = face_roi
    # cv2.imwrite("T.png", src_img_copy)
    cv2.imshow('MediaPipe Face Detection', src_img_copy)
    cv2.waitKey(0)


相关文章
|
3月前
|
机器学习/深度学习 Shell 算法框架/工具
【姿态估计】实操记录:使用Dlib与mediapipe进行人脸姿态估计
【姿态估计】实操记录:使用Dlib与mediapipe进行人脸姿态估计
200 0
|
3月前
|
机器学习/深度学习 算法 计算机视觉
yolov8人脸识别-脸部关键点检测(代码+原理)
yolov8人脸识别-脸部关键点检测(代码+原理)
263 0
|
8月前
|
机器学习/深度学习 传感器 算法
【交互式阈值二进制图像】采用彩色或单色图像通过交互/手动方式阈值单色图像或彩色图像的单个色带研究(Matlab代码实现)
【交互式阈值二进制图像】采用彩色或单色图像通过交互/手动方式阈值单色图像或彩色图像的单个色带研究(Matlab代码实现)
|
10月前
|
算法 云计算 图形学
基于双目人脸图像ORB特征提取匹配的人脸三维点云提取和建模的matlab仿真
基于双目人脸图像ORB特征提取匹配的人脸三维点云提取和建模的matlab仿真
|
1天前
|
存储 算法 数据可视化
LabVIEW利用矢量量化直方图开发人脸识别
LabVIEW利用矢量量化直方图开发人脸识别
|
25天前
|
文字识别 算法 计算机视觉
图像倾斜校正算法的MATLAB实现:图像倾斜角检测及校正
图像倾斜校正算法的MATLAB实现:图像倾斜角检测及校正
|
2月前
|
机器学习/深度学习 人工智能 算法
使用纹理对比度检测检测AI生成的图像
在本篇文章中我们将介绍如何开发一个深度学习模型来检测人工智能生成的图像
20 0
|
11月前
|
计算机视觉 C++
【影像配准】遥感影像配准精度评价—特征点检测精度评价(附有完整代码)
【影像配准】遥感影像配准精度评价—特征点检测精度评价(附有完整代码)
|
11月前
|
机器学习/深度学习
识别手绘数字图像
识别手绘数字图像
61 0
|
12月前
|
自然语言处理 搜索推荐 算法
人脸神经辐射场的掩码编辑方法NeRFFaceEditing,不会三维建模也能编辑立体人脸
人脸神经辐射场的掩码编辑方法NeRFFaceEditing,不会三维建模也能编辑立体人脸
126 0