人脸对齐:Procrustes analysis 普氏分析

概述

在人脸相关应用中,获得的人脸图像常常形状各异,这时就需要对人脸形状进行归一化处理。人脸对齐就是将两个不同的形状进行归一化的过程,将一个形状尽可能地贴近另一个形状。

值得注意的是,在英语文献中,Face Alignment和Facial Landmark Detection常常混用,在我的系列博客里面,Facial Landmark Detection指的是人脸特征点检测,而Face Alignment指的是人脸对齐。人脸特征点检测是人脸对齐的必要步骤,现在有很多端到端(end to end)的方法不需要进行对齐,所以具体要不要对齐这一步需要结合实际分析。

人脸特征点检测的结果如下:

landmark

人脸对齐的效果如下,可以看到右边的脸已经和左边的脸形状大体一致:

face align

言归正传,Procrustes analysis是一种用来分析形状分布的统计方法。Procrustes源于古希腊神话中的一个强盗, 他常切断受害者的肢体使其身形与床相匹配,类似地Procrustes分析方法是对两个形状进行归一化处理 。从数学上来讲,普氏分析就是利用最小二乘法寻找形状A到形状B的仿射变换 。

模型

仿射变换

在高中的几何课程中,一定学过平移,放缩和旋转变换。

仿射变换

将这三种变换写成矩阵形式:

[uv]=[a2b2a1b1a0b0]xy1=s[cosθsinθsinθcosθ][xy]+[t1t2]=sR[xy]+T[uv]=[a2a1a0b2b1b0][xy1]=s[cos⁡θ−sin⁡θsin⁡θcos⁡θ][xy]+[t1t2]=sR[xy]+T

这个式子中,s就是缩放比例,θθ 就是旋转角度,最后的t代表平移的位移,其中R是一个正交矩阵。 

RTR=IRTR=I

Procrustes analysis

我们现在要解决如何旋转、平移和缩放第一个向量,使它们尽可能对齐第二个向量的点。一个想法是使用仿射变换将第一个图像变换覆盖第二个图像。如何判断这种对齐的效果呢?使用最小二乘法,使得变化后所有点与目标点距离和最小。

两个形状矩阵分别为p和q,矩阵的每一行代表一个特征点的x,y坐标,假设有68个特征点坐标,则pR68×2p∈R68×2。写成数学形式:

argmins,θ,ti=168sRpTi+TqTi2argmins,θ,t∑i=168‖sRpiT+T−qiT‖2

其中pipi就是p矩阵的第i行。写成矩阵形式:

argmins,R,TsRpT+TqTFargmins,R,T‖sRpT+T−qT‖F
RTR=IRTR=I

F‖⋅‖F 代表Frobenius范数,就是每一项的平方和。

求解

这个最小值问题是有解析解的。

先放上代码:

#Procrustes analysis
def transformation_from_points(points1, points2):
    points1 = points1.astype(numpy.float64)
    points2 = points2.astype(numpy.float64)

    c1 = numpy.mean(points1, axis=0)
    c2 = numpy.mean(points2, axis=0)
    points1 -= c1
    points2 -= c2

    s1 = numpy.std(points1)
    s2 = numpy.std(points2)
    points1 /= s1
    points2 /= s2

    U, S, Vt = numpy.linalg.svd(points1.T * points2)
    R = (U * Vt).T

    return numpy.vstack([numpy.hstack(((s2 / s1) * R,
                                       c2.T - (s2 / s1) * R * c1.T)),
                         numpy.matrix([0., 0., 1.])])

根据

https://en.wikipedia.org/wiki/Orthogonal_Procrustes_problem

可以知道

argminΩΩABF  subject to ΩTΩ=IargminΩ‖ΩA−B‖F  subject to ΩTΩ=I

是有解的。

需要将式子

argmins,R,TsRpT+TqTFargmins,R,T‖sRpT+T−qT‖F
进行一些变化,写成Wikipedia式子的形状。这里的变化就需要对原始点集p和q进行一些处理,使得最小化式子发生变化。

https://en.wikipedia.org/wiki/Procrustes_analysis#Ordinary_Procrustes_analysis

这里给出了对原始点集的变化步骤。结合代码来看:

    c1 = numpy.mean(points1, axis=0)
    c2 = numpy.mean(points2, axis=0)
    points1 -= c1
    points2 -= c2

这一步处理消除了平移T的影响。

    s1 = numpy.std(points1)
    s2 = numpy.std(points2)
    points1 /= s1
    points2 /= s2

这一步处理消除了缩放系数s的影响。

这两步处理以后,R就可以变成求解下面的式子:

R=argminΩΩABF  subject to ΩTΩ=IR=argminΩ‖ΩA−B‖F  subject to ΩTΩ=I

这里的A,B不再是原始的数据点集,而是变成了处理以后点集。

根据维基百科,这个式子是可以求解的:

M=BATM=BAT
svd(M)=UΣVTsvd(M)=UΣVT
R=UVTR=UVT

这样就解出了R:

    U, S, Vt = numpy.linalg.svd(points1.T * points2)
    R = (U * Vt).T

源代码最后一步返回的是仿射变换矩阵

猜你喜欢

转载自blog.csdn.net/wfei101/article/details/80530867