上图是官方在项目里提供的示意图。下面我根据索引号对应又画了一版:
当使用 tuple(start, stop) 形式定义范围并通过 slice(*tuple) 创建切片时,遵循的是左闭右开区间原则。
landmarks_68_pt = { "mouth": (48,68),
"right_eyebrow": (17, 22),
"left_eyebrow": (22, 27),
"right_eye": (36, 42),
"left_eye": (42, 48),
"nose": (27, 36), # missed one point
"jaw": (0, 17) }
slice(*landmarks_68_pt["right_eyebrow"]) 实际上等同于 slice(17, 22) ,它会从 int_lmrks 数组中选择索引为17、18、19、20、21的元素,总共5个点,而不包括索引为22的点。
# 人脸对齐变换过程详解(附具体数值示例)
DeepFaceLab中的人脸对齐是一个将不同姿态、角度的人脸标准化为统一格式的关键过程。下面我将通过具体的数值例子来详细演示这个过程。
## 一、人脸对齐的基本原理
人脸对齐主要通过以下步骤实现:
1. 1.
使用面部地标点(landmarks)估计变换关系
2. 2.
计算仿射变换矩阵
3. 3.
应用变换提取对齐后的人脸图像
## 二、具体数值演示
### 步骤1:假设我们有一组检测到的面部地标点
假设在一张800x600的原始图像中,检测到了一个人脸,其关键点坐标如下(仅显示部分关键坐标):
```
# 实际检测到的面部关键点(部分)
image_landmarks = np.array([
# 眼睛、鼻子、嘴巴等关键点(示例值)
[200, 150], # 左眼左上角
[230, 150], # 左眼右上角
[215, 170], # 左眼中心
[260, 150], # 右眼左上角
[290, 150], # 右眼右上角
[275, 170], # 右眼中心
[245, 200], # 鼻尖
[235, 230], # 左嘴角
[255, 230], # 右嘴角
# ... 更多关键点
], dtype=np.float32)
```
### 步骤2:使用Umeyama算法计算相似变换
首先,系统使用 umeyma 函数将检测到的地标点与标准模板地标点进行匹配:
```
# 从LandmarksProcessor.py中,系统使用
这些特定区域的关键点
selected_landmarks = np.concatenate
([image_landmarks[17:49],
image_landmarks[54:55]])
我这里看了很久才看懂。48号点和54号点是两个嘴角的坐标
# landmarks_2D_new是预定义的标准模板
# 计算从图像关键点到标准模板的相似变换矩阵
similarity_mat = umeyama
(selected_landmarks,
landmarks_2D_new, True)
# 取前两行用于2D变换
transform_mat = similarity_mat[0:2]
``` Umeyama算法计算过程:
1. 1.
计算源点和目标点的均值:
```
src_mean = [245, 180] # 假设的源
点均值
dst_mean = [0.5, 0.5] # 目标模板
的均值
```
2. 2.
去中心化处理后计算协方差矩阵
3. 3.
通过SVD分解得到旋转和缩放分量
4. 4.
最终得到的相似变换矩阵可能类似于:
```
# 示例变换矩阵(2x3)
transform_mat = [
[120.5, 2.1, -28500.7], # 第
一行:a, b, tx
[-1.3, 119.8, -22000.5] # 第
二行:-b, a, ty
]
```
### 步骤3:计算仿射变换的三个关键点
接下来,系统使用变换矩阵计算对齐所需的三个关键点:
```
# 计算变换后的标准点在原图中的坐标
g_p = transform_points(np.float32
([(0,0),(1,0),(1,1),(0,1),(0.5,0.
5)]), transform_mat, True)
g_c = g_p[4] # 中心点
# 计算对角线向量
tb_diag_vec = (g_p[2]-g_p[0]).
astype(np.float32)
tb_diag_vec /= np.linalg.norm
(tb_diag_vec)
bt_diag_vec = (g_p[1]-g_p[3]).
astype(np.float32)
bt_diag_vec /= np.linalg.norm
(bt_diag_vec)
# 计算缩放因子(假设使用FULL类型,
padding=0.2109375)
mod = (1.0/1.0) * (np.linalg.norm
(g_p[0]-g_p[2])*(0.2109375*np.sqrt
(2.0) + 0.5))
# 计算仿射变换的三个源点
l_t = np.array([
g_c - tb_diag_vec*mod,
g_c + bt_diag_vec*mod,
g_c + tb_diag_vec*mod
])
```
假设计算结果为:
```
l_t = np.array([
[170, 120], # 左上点
[320, 130], # 右上点
[310, 290] # 右下点
])
```
### 步骤4:计算最终的仿射变换矩阵
```
# 定义目标图像中的三个对应点(假设输出大小
为512x512)
pts2 = np.float32([(0,0), (512,0),
(512,512)])
# 计算仿射变换矩阵
final_mat = cv2.getAffineTransform
(l_t, pts2)
```
最终得到的仿射变换矩阵可能如下:
```
final_mat = [
[3.25, 0.15, -550.75], # 第一
行:a, b, tx
[-0.2, 3.18, -370.6] # 第二
行:-b, a, ty
]
```
### 步骤5:应用仿射变换提取对齐的人脸
```
# 应用仿射变换
aligned_face = cv2.warpAffine
(original_image, final_mat, (512,
512), cv2.INTER_LANCZOS4)
# 同时变换关键点到新坐标系
aligned_landmarks =
LandmarksProcessor.transform_points
(image_landmarks, final_mat)
```
## 三、变换过程的关键点解释
1. 1.
相似变换(Umeyama) :
- 保持形状不变的变换,包含旋转、缩放和平移
- 用于建立检测到的人脸与标准模板之间的对应关系
2. 2.
仿射变换 :
- 允许旋转、缩放、剪切和平移
- 通过三个对应点对定义
- 在DeepFaceLab中,用于将人脸区域映射到标准大小的输出图像
3. 3.
面部类型的影响 :
- 不同的 face_type 参数(FULL、WHOLE_FACE、HEAD等)会影响:
- padding 值:决定提取区域的大小
- 中心点位置:如WHOLE_FACE会向下调整7%以包含更多额头
4. 4.
对齐的效果 :
- 无论原始人脸在图像中的位置、角度和大小如何
- 经过变换后,所有人脸都将:
- 大小统一(如512x512)
- 面部特征点位置标准化
- 方向一致(通常是正面朝向)
## 四、实际效果演示
原始图像中的人脸:
- 可能位于图像的任何位置
- 可能有旋转、倾斜
- 大小不一
对齐后的人脸:
- 总是位于输出图像的中心
- 方向标准化(眼睛水平,嘴巴水平)
- 大小统一(由image_size参数决定)
- 面部特征相对位置一致
这种对齐过程对于后续的深度学习模型训练至关重要,因为它确保了输入数据的一致性,大大提高了模型的学习效率和效果。
|