1. 程式人生 > >人臉關鍵點定位.Face Alignment by Coarse-to-Fine Shape Searching 演算法原始碼詳解(下)

人臉關鍵點定位.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:當前形狀概率。


analyse_tpt.m

其核心函式為analyse_tpt_base:從若干個location中選擇出representativeNum個代表性點。

返回代表性點為picked_id,初始為空。

首先找出所有點的中心cent,距離cent最近的點放入picked_id。(knnsearch:返回距離某個點/某一組點最近的k個點序號)

而後,找出剩下的點。

對於每個點,找出所有點到現有picked_id的距離的最短距離。這個距離最大的點,認為和現有的點最不相似,放入picked_id中。下圖是從100個隨機點中選擇10個代表點。

返回的序號是從外圍到中心。最後一個點是最開始找出的cent。

 

% 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分配給這些代表性點。

 


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在當前影象上,屬於訓練樣本的概率。