人脸关键点定位.Face Alignment by Coarse-to-Fine Shape Searching 算法源码详解(下)

首先按照源码中read me配置。可能运行出错的部分,用黄字高亮了解决方案。

以下分别解说训练和测试代码。

====训练部分===============

l learnCFSS.m为核心训练文件。需要顺序运行getParametricModels;addAll; learnCFSS;

运行需要matlabpool。如果数据N<100,则不启动并行。如果没有并行工具箱,可以手工修改代码不启动并行

至少需要约900个样本,才能通过PCA部分的数量断言。需要较大内存要求。

poseVoting.m中使用dist函数,需要神经网络工具箱。如果没有该工具箱,可以手工添加dist函数。

至少需要约2700个样本,才能通过traintestP.m中,训练SVC时的数量断言。

traintestP.m中调用了libsvm的函数svmtrain。未避免调用到VLFEAT中的同名函数,在进入这部分之前,先去除VLFEAT的路径,之后再添加上

 

learnCFSS

各种load

for level = 1:stageTot        实际只用3次迭代

 

% Re-trains仅在第一次迭代调用

trainingSetGeneration:返回旋转对齐图像(images),生成平均脸(referenceShape),图像旋转回归器B,对齐变换T。

Pr:先验概率。,N *N,每行对应一个原始样本,表示取得每一个原始样本的概率。设定为均匀分布,对角线零,其他位置均等。

model.tpt:当前level目标形状。N*2L。用来在测试时依照概率生成样本。

主要作用:归一化样本

% from Pr to sub-region center

traintestReg:生成回归模型regModel和当前形状currentPose(相当于论文中sub-region center)。

T:当前形状到平均脸(referenceShape)的变换

images:用T进一步更新图像

model.tpt:当前level目标性状,记为targetPose。

主要作用:根据概率Pr,生成扩展初始值,用回归器移动形状,得到currentPose。

% Train-test Pr

traintestP:估计当前各个训练图像上,各个训练集形状的概率Pr。

 

 

 

trainingsetGeneration

只在第一次迭代调用

% 输入

 

% Loading original images

Tb:每个原始图像中simple face(左右眼角左右嘴角)到标准形状的变换。N*2L。其中标准形状为target_simple_face(0-1之间)放大到priorsInfo.win_size(250*250)。

targetPose:旋转到标准simple shape之后的L个关键点。

referenceShape:平均形状。

% Label angle estimation according to targetPose

Te:每一个targetPose(已经粗略旋转过)到referenceShape(平均形状)的变换。是一个较小较精细的变换。

angle:Te变换的旋转角度。

% Dataset partition

set_id:N*1。把所有原始数据随机分成均等两组。用于训练两个旋转角度回归器。

% Training

B:两个角度回归器。互为校验。

for s = 1:2           分别使用两组数据训练B{s}

 

Tb_train:本次训练中,从原始图像到标准形状的变换。

angle_train:本次训练中,从粗略旋转到精细旋转的变化角度。

mp:用于本次训练的样本数。约为N/2。

MP:扩展后的样本数。扩展10倍(priorsInfo.augTimes)。

im:本次训练中,原始图像经过旋转得到的augment结果。N/2*扩展数。

label:扩展样本的随机旋转角度,最大旋转45°(priorsInfo.maxRoll)。

for i = 1: augTimes

 

Tr_train:从现有角度到扩展后角度的变换

Tbr_train:总体旋转角度。融合了Tb_train和Tr_train。

im:用Tbr_train对原始图像进行旋转。

F:本次训练的样本特征,图像250*250,从中心部分截取一个3*3窗口,提取31维hog特征。特征长度3*3*31 = 279。

B{s}:用前述特征通过TreeBagger预测旋转角度,得到ensemble of bagged decision trees。记为B。样本随机分成两部分,s=1:2,分别计算两个B。其用意参见测试部分。

images:原始图像通过Tb变换,粗略旋转对齐到标准形状上。

% 返回

粗略旋转对齐到标准形状上的images

priorModel中的平均脸referenceShape

priorModle中的旋转回归器B

旋转对齐到平均形状上的变换T

traintestReg

% 输入

images:原始形状

targetPose:目标形状

Pr:概率。N*N。

% 1. Sampling both for train and test  根据Pr为每个样本生成训练和测试样本

currentPose_train, currentPose_test:对于每一个原始样本,都有10个(regsInfo.trainSampleTot)用于训练和10个(regsInfo.testSampleTot)用于测试的样本,是从N个原始样本中抽取的。N*2L*10.

for i = 1:m     对于每一个样本

 

第一次迭代

index_train:用randSampleNoReplace从原始样本中根据Pr抽取10个样本。此时Pr是除了当前样本之外的均匀分布。

index_test:用randSampleNoReplace从原始样本中根据PrI_temp抽取10个样本。其中PrI_temp是刨除10个训练样本之后的概率分布。训练和测试不能重复。

其他次迭代

tmp:将样本按照Pr降序排列

index_train, index_test:概率最大的trainSampleTot个样本。

从目标形状中根据index_XXX取出currentPose_XXX。

% 2. learn regressors to get regModel

% 2A. Augmentation 把训练样本进行随机变换

M:N*训练样本数(10)。每个样本有10个训练,10个测试。

cu:当前形状。10N*2L

tg:目标形状。10N*2L

for i = 1:trainSampleTot      处理所有原始样本的第i个训练样本,共N个。

 

selectPoses:返回每个目标形状(targetPose)中,外眼角(regsInfo.aug_eyes_id)位置。N*4。

Ta:1*N个随机变换。是通过原始样本中随机两个样本之间的变换而得。对于每一个i,都重新随机一次。

cu:把currentPose_train中的相应的N个训练样本施加Ta中的N个变化,得到N个结果。

tg:把targetPose(共N个)施加Ta中的N个变化,得到N个结果。

im:把每个原始图像经过Ta中的N个变化,得到N个结果。

当训练样本序号i为偶数时,把cu、tg、im都镜像。

% 2B. Training iteration

for iter = 1:iterTot   共3次,训练每一个迭代的一系列回归器

 

featOri:每一个原始样本的 关键点SIFT特征,使用自定义函数extractSIFTs_toosimple提取。维度128*L = 8704。所以至少需要871个原始样本。

featReg:对featOri做PCA之后,保留98%能量,压缩到3693维。

pca_model:PCA模型

reg_model:用trainLR_averageHalfBaggin训练一个回归器,从特征featReg预测形状偏差tg-cu。相当于原始SDM中的一级回归器。

regModel:最终返回的模型。平均值mu设为PCA的平均特征meanFeatOri,一次项A设为PCA的投影矩阵coeff和reg_model一次项的乘积,常数项定义为reg_model的常数项。

更新当前形状cu:PCA和回归合并到一步完成。

featOri_batch:所有样本对应测试样本的SIFT特征。N*8704*10。

currentPose_test:用前述特征通过回归器进行更新。

currentPose:从测试样本currentPose_test中,利用poseVoting(论文中的自动权重)计算。N*2L。描述一个概率分布。

% 返回

包含PCA的偏移量回归模型regModel

当前形状currentPose

 

traintestP

计算Pr的核心是inferenceP函数,前面的都在训练模型。

% 输入

images:原始图像

targetPose:目标形状

currentPose:当前形状

% A. Prior Prob Learning      论文中概率第一项:从偏差值推测概率

d:当前形状currentPose到目标性状targetPose偏移。N*2L

d_pca:偏移量PCA结果,压缩到17维。N*17。

PModel.sigma:d_pca的协方差。测试时用高斯模型估计偏差值的概率。

PModel.pca_model:偏移量投影的PCA模型

% B. Features Prob Learning     论文中概率第二项:从特征和偏差推断概率

% 1. Sampling for training and testing

s:采样个数probsInfo.probSamplings=5。扩展样本用于训练点偏移SVM。

ld:有15个semantic点,如下图红色。每个点有一个cell。存储semantic点偏移量位置。

for i = 1 : length(semantic_id)      全部样本的每个semantic点

 

dx,dy:半径0-SVCradius之间,方向0-2PI之间的随机矢量。N*5。

ld的当前cell:N*5*2。全部样本目标形状targetPose的semantic点,加上上述随机偏移。

% 2. Centralized feature extraction

feat_all:每个尺度一级。尺度probsInfo.pyramidScale=3

for pyramid = 1:length(pyramidScale)

 

pose:N*(2*15)*(5+1)。样本数*semantic点数*(采样数+1)。前5维为ld中的偏移位置targetPose+(dx,dy),最后一维是未偏移的当前形状currentPose。

feat_all:在pose上提取SIFT特征。

% Unroll them into training and test set

F_train, L_train, F_current:每个semantic点对应一个cell,

for i = 1:length(semantic_id)        每个semantic点单独训练

 

训练数据个数:N*s。

F_train{i}:(N*s)*(128*3)。3尺度SIFT。偏移的s个采样的特征。

L_train{i}:(N*s)*2。pose到targetPose的偏移量。

F_current{i}:N*(128*3)。当前形状的特征。

% 3. Train SVM classifiers for each landmark

svc_:每个semantic点有一个svc模型。

for i = 1:semantic_id          每个semantic点训练SVC

 

从N*s个原始样本中挑选出正负样本

ind_pos:偏移距离小于probsInfo.SVCthre = 0.3/0.6

ind_neg:偏移距离大于probsInfo.SVCthre

要求正负样本中较少的数量 > 8倍维度 = 3072。约需要2700个样本。

用正负样本训练当前SVC。偏差小的输出1,偏差大的输出0。(libsvm自动把+-1标记转换为0/1标记??)

PModel.SVC赋值为刚训练出的模型。

% 4. tpt analysis

PModel.representativeLocation:长度为semantic点数

for i = 1:length(semantic_id)

 

location:全部目标形状中当前semantic点位置

picked_id:用analyse_tpt.m函数找出该点在不同形状中的代表位置。(详细参看analyse_tpt)从全部形状中选出probsInfo.representativ2Num1个, 从居于中心的形状中选出probsInfo.representativeNum2个,共20个。

PModel.representativeLocation{i}:20*2,20个代表形状的位置。

% C. Testing and training

Pr:使用reference.Pm函数计算在PModel下,每一个当前形状属于每一个目标形状的概率。(详细参看inferenceP.m)

% 返回

PModel:包含第一项PCA,以及第二项SVC的模型

Pr:当前形状概率。

 

人脸关键点定位.Face Alignment by Coarse-to-Fine Shape Searching 算法源码详解(下)_第1张图片

analyse_tpt.m

其核心函数为analyse_tpt_base:从若干个location中选择出representativeNum个代表性点。

返回代表性点为picked_id,初始为空。

首先找出所有点的中心cent,距离cent最近的点放入picked_id。(knnsearch:返回距离某个点/某一组点最近的k个点序号)

而后,找出剩下的点。

对于每个点,找出所有点到现有picked_id的距离的最短距离。这个距离最大的点,认为和现有的点最不相似,放入picked_id中。下图是从100个随机点中选择10个代表点。

返回的序号是从外围到中心。最后一个点是最开始找出的cent。

 人脸关键点定位.Face Alignment by Coarse-to-Fine Shape Searching 算法源码详解(下)_第2张图片

% Step A: For all locations

pA:从location中找出的representativeNum1个代表性点序号(绿圈)。

capital_id:如果一个location点到pA所有点的距离。如果距离最近的点是pA的最后一点,则返回该location的序号(红圈)。由于pA是按照从外围到中心排列,的capital_id中包含location中中心部分的点。

% Step B: For capital location in Step A

pB:从capital_id的店中,找出represntativeNum2+1个代表性点。由于最后一个点返回的中心和pA的相同,所以要多找一个。

% Merge and get assign

picked_id:pA和pB拼合,去除重复的中心点。

assign:location到picked_id中最近的picked_id序号。相当于把location分配给这些代表性点。

 人脸关键点定位.Face Alignment by Coarse-to-Fine Shape Searching 算法源码详解(下)_第3张图片

人脸关键点定位.Face Alignment by Coarse-to-Fine Shape Searching 算法源码详解(下)_第4张图片

referenceP.m

先计算包含纹理信息的后验概率,而后计算只由形状决定的先验概率。

% 输入

images:对齐的图像。数量为M。

model:semantic点纹理->偏移的SVC模型,semantic点代表性位置representativeLocation,点偏移量的PCA模型

currentPose:当前形状。数量为M。训练时等于为训练集样本数N。测试时为测试集样本数。

level:外层迭代次数,用于确定参数

probsInfo:参数

tpt:标定的目标形状(targetPose)。数量为训练集样本数记为N。

% Validation over currentPose

feat_current:当前形状semantic点上的3尺度SIFT特征。高为M,宽为128*15*3 = 5760。

scoring_board:长度=semantic点数。每个cell中是M*N,表示第i测试样本和第j训练样本相似程度。

Pr:M*N*25,其中25为15个semantic点和10个fix点(人脸图绿色点)。概率拆解为关键点概率的连乘。

record_point:M*(2*25)。semantic点和fix点。

record_mask:M*25。没用。

for i = 1:length(semantic_id)            % 处理全部当前形状的第i个semantic点。

% 靠谱的用当前形状,不靠谱的用模型中的代表性点

 

confidence_current:从feat_curretn中找出当前点对应的特征,用model中的SVC模型,预测一个置信度。第一列为结果:离真实位置近,为1;离真实位置远,为0;第二列为accuracy,删除不用。

ind:当前形状中置信度>=acceptThre=0.9的点序号。这些样本离真实值足够近。数量设为M1。

% for only current

dX, dY:M1个当前正确形状到目标形状tpt的偏差。M1*N。

scoring_board{i}: 用M1个形状偏差dX,dY的高斯 函数计算。其方差为预设的gamma_current。填入scoring_board{i}对应的测试样本行内。

record_point:把当前形状对应点,填入record_point中,semantic部分的对应位置。

ind:当前形状中置信度<acceptThre=0.9的点序号。数量设为M2。M1+M2 = M

% for considering resamping

feat_search:M2个偏差形状,第i个点的representativeLocation(共20个样本)上提取的3级SIFT特征。高度M2,宽度20*3*128 = 7680。

confidence_search:代表性点的置信度。用model中的SVC模型,预测feat_search。结果小于0.5的置为0,按行归一化。M2*20。

searched_point:confidence_search(M2*20)*representativeLocation(20*2)。代表性点,用置信度加权的平均值。M2*2。

scoring_board{i}, record_point:同前处理。填入相应位置内。

Pr:把i对应的概率赋值为scoring_board{i}

for i = 1:length(fix_id)

 

record_point:把当前形状的对应点填入

dX, dY:当前形状到目标形状偏差

Pr:用dX, dY计算的高斯概率。

连乘Pr的第三维,得到M*N的矩阵。此时得到的Pr为论文中概率第二项:和纹理相关的后验概率。

% Multiply the prior

for i = 1:m          % 对于每个当前形状

 

d:第i个当前形状到目标形状偏差。N*(2*L)

d_pca:用模型中的PCA对d进行投影。N*(2*17)。

prior:每一行(1*N) = d_pca自身数乘,而后对第二维求和。相当于在投影后空间里,到原点的距离。

prior:用高斯函数计算。方差为gamma_prior。

Pr:用Pr(后验)乘上prior(先验)。之后归一化。

% 返回

Pr:M*N矩阵。第i个当前形状等于第j个训练集形状的概率。

 

====测试部分===============

inferenceCFSS.m为核心训练文件。

测试单张图片相当慢,超过5s,和论文所述25fps不符。不知是否并行未启动所致。

如果更改了11行的测试数据数量,则末尾再次载入数据也要相应更改。

占用内存较大,即使是只测试2个样本,在家用PC上也会有low memory警报。

 

inferenceCFSS

和训练流程非常相似。

载入各种数据,模型

m:测试样本数

mt:训练样本数

for level = 1:stageTot

 

% 61. Re-trans

testingsetGeneration:利用图像旋转回归器生成对齐的图像images,以及对齐的刚性形变T。

Pr:m×mt,设定为均匀分布。

% 62. from Pr to sub-region center

currentPose:m×(2L)。通过inferenceReg函数从Pr估计初始形状,用回归器进行迭代。

T:记录当前形状到平均形状priorModel.referenceShape的变换

images:用上述变换继续对图像进行矫正。下图示出迭代三次图像的变化。

currentPose:用上述变换对当前形状进行矫正。

% 63. from sub-region center to Pr

Pr:通过inferenceP函数,计算当前图像上,训练样本的概率分布。

estimatedPose:用各次迭代记录的变换T把currentPose反变换回去。

最后计算估计值estimatedPose和真实值data的误差,用瞳距归一化。

 

testingsetGeneration

和训练流程中预处理部分很像。只在第一次迭代调用

m:测试样本数

p:m×8,平均simple_face(眼角嘴角),数量和测试样本数相同

Tb:每个原始图像中simple face到标准simple shape的变换。只有平移缩放剪切,不包含旋转。

images:原始灰度图像经过Tb的转换,进行对齐。取代人脸框作用,不算作弊。

F:图像中部3*3网格中的HOG特征,共279维。

predicted:样本数*2。分别用两个ensemble of bagged decision trees(记为priorModel.B),从特征F预测本图片的旋转角度。

此处的B模型有两个,各由一半训练样本生成。如果两个预测结果角度之差<180°,则将两个结果平均输出;否则,直接输出0°正脸。

另外设定了参数priorsInfo.predictedVoteThre。对预测结果绝对值进行限制。

Tr:预测角度的反旋转。

T:缩放平移的Tb + 预测出的旋转Tr

images:经过T变换的图像

% 返回

归一化图像images,归一化变换T。

 

inferenceReg

m:测试样本数

tpt:本次迭代的训练集样本:N*2L

mt:训练集样本数

currentPose_inference:N*2L*采样数(regsInfo.samplingTot,每级都是10)。初始形状。第一次迭代时,均匀从训练样本中取;其他次迭代,先对Pr进行排序,而后取概率最大的训练样本。

% inference Iteration

for iter = 1:iterTot              % 4个回归,更新初始形状

 

featOri_batch:样本数*8704*采样数。使用128*L = 8704维SIFT特征。

currentPose_inference:形状变化量如下计算:(feaOri – model.reg.mu) * model.reg.A + model.reg.b。

currentPose:通过poseVoting从10个currentPose_inference中得到加权平均值。迭代次数为regsInfo.dominantIterTot=100。

 

inferenceP

和训练中的infereceP一样。计算当前形状currentPose在当前图像上,属于训练样本的概率。

你可能感兴趣的:(人脸关键点定位.Face Alignment by Coarse-to-Fine Shape Searching 算法源码详解(下))