face alignment by 3000 fps系列學習總結(二)

準備初始數據

mean_shape

mean_shape就是訓練圖片所有ground_truth points的平均值.那么具體怎么做呢?是不是直接將特征點相加求平均值呢?
顯然這樣做是倉促和不準確的。因為圖片之間人臉是各式各樣的,收到光照、姿勢等各方面的影響。因此我們求取平均值,應該在一個相對統一的框架下求取。如下先給出matlab代碼:

function mean_shape = calc_meanshape(shapepathlistfile)fid = fopen(shapepathlistfile);
shapepathlist = textscan(fid, '%s', 'delimiter', '\n');if isempty(shapepathlist)error('no shape file found');mean_shape = [];return;
endshape_header = loadshape(shapepathlist{1}{1});if isempty(shape_header)error('invalid shape file');mean_shape = [];return;
endmean_shape = zeros(size(shape_header));num_shapes = 0;
for i = 1:length(shapepathlist{1})shape_i = double(loadshape(shapepathlist{1}{i}));if isempty(shape_i)continue;endshape_min = min(shape_i, [], 1);shape_max = max(shape_i, [], 1);% translate to origin pointshape_i = bsxfun(@minus, shape_i, shape_min);% resize shapeshape_i = bsxfun(@rdivide, shape_i, shape_max - shape_min);mean_shape = mean_shape + shape_i;num_shapes = num_shapes + 1;
endmean_shape = mean_shape ./ num_shapes;img = 255 * ones(500, 500, 3);drawshapes(img, 50 + 400 * mean_shape);endfunction shape = loadshape(path)
% function: load shape from pts file
file = fopen(path);
if file == -1shape = [];fclose(file);return;
end
shape = textscan(file, '%d16 %d16', 'HeaderLines', 3, 'CollectOutput', 2);
fclose(file);
shape = shape{1};
end

解析:

公式表示:

{shapegt?[Region(1),Region(2)]}/[Region(3),Region(4)))]]?[0,1]×[0,1]

準備ΔSt

我們知道3000FPS的核心思想是:

ΔSt=WtΦt(I,St?1)

其中 ΔSt=Sgt?St為第t個階段的殘差;而 Φt(I,St?1)則為特征提取函數;W為線性回歸矩陣。由 《人臉配準坐標變換解析》我們可以看到所謂的 ΔSt需進行相似性變換,而 Φt(I,St?1)則不需要.
相似性變換的主要過程是:
先將 St S0中心化變換,再求解如下變換矩陣:
S0=cRSt
,求解完cR后,對 ΔSt施加同樣的變換,即
St?=cRΔSt
.我們將使用變化后的 St?去求解線性回歸矩陣W.
先貼代碼: train_model.m 第103行起

Param.meanshape        = S0(Param.ind_usedpts, :); %選取特定的landmarkdbsize = length(Data);% load('Ts_bbox.mat');augnumber = Param.augnumber; %為每張人臉選取的init_shape的個數for i = 1:dbsize        % initializ the shape of current face image by randomly selecting multiple shapes from other face images       % indice = ceil(dbsize*rand(1, augnumber));  indice_rotate = ceil(dbsize*rand(1, augnumber));  indice_shift  = ceil(dbsize*rand(1, augnumber));  scales        = 1 + 0.2*(rand([1 augnumber]) - 0.5);Data{i}.intermediate_shapes = cell(1, Param.max_numstage); %中間shapeData{i}.intermediate_bboxes = cell(1, Param.max_numstage);Data{i}.intermediate_shapes{1} = zeros([size(Param.meanshape), augnumber]); %68*2*augnumber(augnumber為第i圖片設置的初始shape的個數)Data{i}.intermediate_bboxes{1} = zeros([augnumber, size(Data{i}.bbox_gt, 2)]); %augnumber*4Data{i}.shapes_residual = zeros([size(Param.meanshape), augnumber]); %shapes_residual為shape 殘差 維數:68*2*augnumberData{i}.tf2meanshape = cell(augnumber, 1);Data{i}.meanshape2tf = cell(augnumber, 1);% if Data{i}.isdet == 1%    Data{i}.bbox_facedet = Data{i}.bbox_facedet*ts_bbox;% end     % 如下一段的意思是如果augnumber=1,表明每個圖片的Init_shape只有一個,因此這要設置成mean_shape即可,這時你會發現Data{i}.tf2meanshape{1}其實就是% 單位矩陣,因為他是從mean_shape轉化到mean_shape。后面就不一樣了.%;對于augnumber>1的其他init_shape將采用平移、旋轉、% 縮放等方式產生更多的shape,也可以從其他圖片的shape中挑選shapefor sr = 1:params.augnumberif sr == 1% estimate the similarity transformation from initial shape to mean shape% Data{i}.intermediate_shapes{1}(:,:, sr) = resetshape(Data{i}.bbox_gt, Param.meanshape);% Data{i}.intermediate_bboxes{1}(sr, :) = Data{i}.bbox_gt;Data{i}.intermediate_shapes{1}(:,:, sr) = resetshape(Data{i}.bbox_facedet, Param.meanshape);Data{i}.intermediate_bboxes{1}(sr, :) = Data{i}.bbox_facedet;%將mean shape reproject face detection bbox上meanshape_resize = resetshape(Data{i}.intermediate_bboxes{1}(sr, :), Param.meanshape); %meanshape_resize與 Data{i}.intermediate_shapes{1}(:,:, sr) 是相同的%計算當前的shape與mean shape之間的相似性變換         Data{i}.tf2meanshape{1} = fitgeotrans(bsxfun(@minus, Data{i}.intermediate_shapes{1}(1:end,:, 1), mean(Data{i}.intermediate_shapes{1}(1:end,:, 1))), ...(bsxfun(@minus, meanshape_resize(1:end, :), mean(meanshape_resize(1:end, :)))), 'NonreflectiveSimilarity');Data{i}.meanshape2tf{1} = fitgeotrans((bsxfun(@minus, meanshape_resize(1:end, :), mean(meanshape_resize(1:end, :)))), ...bsxfun(@minus, Data{i}.intermediate_shapes{1}(1:end,:, 1), mean(Data{i}.intermediate_shapes{1}(1:end,:, 1))), 'NonreflectiveSimilarity');% calculate the residual shape from initial shape to groundtruth shape under normalization scaleshape_residual = bsxfun(@rdivide, Data{i}.shape_gt - Data{i}.intermediate_shapes{1}(:,:, 1), [Data{i}.intermediate_bboxes{1}(1, 3) Data{i}.intermediate_bboxes{1}(1, 4)]);% transform the shape residual in the image coordinate to the mean shape coordinate[u, v] = transformPointsForward(Data{i}.tf2meanshape{1}, shape_residual(:, 1)', shape_residual(:, 2)'); Data{i}.shapes_residual(:, 1, 1) = u';Data{i}.shapes_residual(:, 2, 1) = v'; else% randomly rotate the shape            % shape = resetshape(Data{i}.bbox_gt, Param.meanshape);       % Data{indice_rotate(sr)}.shape_gtshape = resetshape(Data{i}.bbox_facedet, Param.meanshape);       % Data{indice_rotate(sr)}.shape_gt%根據隨機選取的scale,rotation,translate計算新的初始shape然后投影到bbox上if params.augnumber_scale ~= 0shape = scaleshape(shape, scales(sr));endif params.augnumber_rotate ~= 0shape = rotateshape(shape);endif params.augnumber_shift ~= 0shape = translateshape(shape, Data{indice_shift(sr)}.shape_gt);endData{i}.intermediate_shapes{1}(:, :, sr) = shape;Data{i}.intermediate_bboxes{1}(sr, :) = getbbox(shape);meanshape_resize = resetshape(Data{i}.intermediate_bboxes{1}(sr, :), Param.meanshape); %將Data{i}.tf2meanshape{sr} = fitgeotrans(bsxfun(@minus, Data{i}.intermediate_shapes{1}(1:end,:, sr), mean(Data{i}.intermediate_shapes{1}(1:end,:, sr))), ...bsxfun(@minus, meanshape_resize(1:end, :), mean(meanshape_resize(1:end, :))), 'NonreflectiveSimilarity');Data{i}.meanshape2tf{sr} = fitgeotrans(bsxfun(@minus, meanshape_resize(1:end, :), mean(meanshape_resize(1:end, :))), ...bsxfun(@minus, Data{i}.intermediate_shapes{1}(1:end,:, sr), mean(Data{i}.intermediate_shapes{1}(1:end,:, sr))), 'NonreflectiveSimilarity');shape_residual = bsxfun(@rdivide, Data{i}.shape_gt - Data{i}.intermediate_shapes{1}(:,:, sr), [Data{i}.intermediate_bboxes{1}(sr, 3) Data{i}.intermediate_bboxes{1}(sr, 4)]);[u, v] = transformPointsForward(Data{i}.tf2meanshape{1}, shape_residual(:, 1)', shape_residual(:, 2)');Data{i}.shapes_residual(:, 1, sr) = u';Data{i}.shapes_residual(:, 2, sr) = v';% Data{i}.shapes_residual(:, :, sr) = tformfwd(Data{i}.tf2meanshape{sr}, shape_residual(:, 1), shape_residual(:, 2));endend
end

這段代碼的理解需要結合上面給出的那篇文章《人臉配準坐標變換解析》。

按照《人臉配準坐標變換解析》文章所述,

S0ˉˉˉˉS1ˉˉˉˉ=S0?mean(S0)=S1?mean(S1)}?S0ˉˉˉˉ=c1R1S1ˉˉˉˉ

因此根據
ΔS=Sg?S1
可推出
ΔS?=c1R1ΔS

但是現在問題比較特殊,需要多操作一下:
由:

 %將mean shape reproject face detection bbox上meanshape_resize = resetshape(Data{i}.intermediate_bboxes{1}(sr, :), Param.meanshape);

查看resetshape的定義知meanshape被映射到intermediate_bboxes中,使得S0S1處于同樣的尺度下和大致相似的位置上。用數學語言表達為:

S0_resize=S0?Ratio+[Region(1),Region(2)]
這里Ratio實際上是intermediate_bboxes的大小。
于是同樣按照上面的方法計算:
S0?=S0_Resize?mean(S0_Resize)=S0?Ratio?mean(S0)?Ratio=(S0?mean(S0))?Ratio=S0ˉˉˉˉ?Ratio

經過計算得 S0?=Ratio?S0ˉˉˉˉ=c1?R1?S1ˉˉˉˉ.(
這也就是上面的代碼:

 Data{i}.tf2meanshape{1} = fitgeotrans(bsxfun(@minus, Data{i}.intermediate_shapes{1}(1:end,:, 1), mean(Data{i}.intermediate_shapes{1}(1:end,:, 1))), ...(bsxfun(@minus, meanshape_resize(1:end, :), mean(meanshape_resize(1:end, :)))), 'NonreflectiveSimilarity');

Data{i}.tf2meanshape{1}即為這里算出的c1?R1?.
但我們想要的是S0ˉˉˉˉ=c1R1S1ˉˉˉˉ,不用著急,()為我們指明了方向。
c1R1=c1?R1?/Ratio=c1?R1?/intermediate_bboxes.因此:

ΔS?=c1?R1?/intermediate_bboxes?ΔS

也就是代碼中提的:

 %計算當前的shape與mean shape之間的相似性變換         
Data{i}.tf2meanshape{1} = fitgeotrans(bsxfun(@minus, Data{i}.intermediate_shapes{1}(1:end,:, 1), mean(Data{i}.intermediate_shapes{1}(1:end,:, 1))),(bsxfun(@minus, meanshape_resize(1:end, :), mean(meanshape_resize(1:end, :)))), 'NonreflectiveSimilarity');Data{i}.meanshape2tf{1} = fitgeotrans((bsxfun(@minus, meanshape_resize(1:end, :), mean(meanshape_resize(1:end, :)))),bsxfun(@minus, Data{i}.intermediate_shapes{1}(1:end,:, 1), mean(Data{i}.intermediate_shapes{1}(1:end,:, 1))), 'NonreflectiveSimilarity');% calculate the residual shape from initial shape to groundtruth shape under normalization scale
shape_residual = bsxfun(@rdivide, Data{i}.shape_gt - Data{i}.intermediate_shapes{1}(:,:, 1), [Data{i}.intermediate_bboxes{1}(1, 3) Data{i}.intermediate_bboxes{1}(1, 4)]);% transform the shape residual in the image coordinate to the mean shape coordinate
[u, v] = transformPointsForward(Data{i}.tf2meanshape{1}, shape_residual(:, 1)', shape_residual(:, 2)'); Data{i}.shapes_residual(:, 1, 1) = u';Data{i}.shapes_residual(:, 2, 1) = v'; 

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/259047.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/259047.shtml
英文地址,請注明出處:http://en.pswp.cn/news/259047.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

parasoft Jtest 使用教程:功能配置之查找錯誤

2019獨角獸企業重金招聘Python工程師標準>>> parasoft Jtest介紹和試用>>> 今天開始為大家帶來parasoft Jtest功能配置板塊教程,也是系列教程中最重要的一部分。 通過運行Jtest的BugDetective和使用最重要的一套規則來進行編碼標準靜態分析&…

kmp入門小結

void get_next(char *s) {int len strlen(s);int j 0; int k -1;while (j < len){if (k -1 || s[j] s[k]){j; k; next[j] k;}else k next[k];} } 設t next[i]; next[i] 表示的是 i之前最大的t滿足 s[0...t-1] s[i-t...i-1] 比如 0123 4 0123 5 &#xff0c;next[…

基于visual Studio2013解決面試題之0807strstr函數

&#xfeff;&#xfeff;&#xfeff;題目解決代碼及點評/*寫strstr函數簡單的遍歷去查找吧 */#include <iostream> #include <stdio.h>const char *my_strstr(const char *str, const char *sub_str) {// 遍歷for(int i 0; str[i] ! \0; i){int tem i; //tem保…

aop在項目中的實際運用_mypy在實際項目中的應用

我認為靜態類型似乎被吹捧過高了。盡管如此&#xff0c;mypy極低的侵入性能帶來許多好處。關于如何在現有的Python項目中添加類型&#xff0c;以下是我的一些想法&#xff0c;大致按重要性排序。首先確保mypy成功運行 Mypy上手時兩個很常見的問題有&#xff1a;1.Mypy沒有作為構…

face alignment by 3000 fps系列學習總結(三)

訓練 我們主要以3000fps matlab實現為敘述主體。 總體目標 我們需要為68個特征點的每一個特征點訓練5棵隨機樹&#xff0c;每棵樹4層深&#xff0c;即為所謂的隨機森林。 開始訓練 分配樣本 事實上&#xff0c;對于每個特征點&#xff0c;要訓練隨機森林&#xff0c;我們需…

HDU 2049 不容易系列之(4)——考新郎( 錯排 )

鏈接&#xff1a;傳送門思路&#xff1a;錯排水題&#xff0c;從N個人中選出M個人進行錯排&#xff0c;即 C(n,m)*d[m]補充&#xff1a;組合數C(n,m)能用double計算嗎&#xff1f;第二部分有解釋 Part 1. 分別求出來組合數的分子和分母然后相除/******************************…

級聯sql

select ID, PID, NAME,KEY from HS_DICT start with KEY HS_EXP_WORK_LOCATIONconnect by prior ID PID order by DISPLAYORDER轉載于:https://www.cnblogs.com/dazhaxie/p/3483532.html

獲取母版中的控件

1 通過findcontrol找控件ID需要在此事件中~因為Page_load中時是先內容頁加載然后才是母版頁加載 protected void Page_LoadComplete(object sender, EventArgs e) { Label2.Text "現在時間是" (Master.FindControl("Label1") as Label).Text; if (Reques…

linux服務器選ubantu或centos_如何通過SSH連接阿里云上的Linux系統

首先SSH是啥&#xff0c;維基一下&#xff1a;Secure Shell&#xff08;安全外殼協議&#xff0c;簡稱SSH&#xff09;是一種加密的網絡傳輸協議&#xff0c;可在不安全的網絡中為網絡服務提供安全的傳輸環境[1]。SSH通過在網絡中創建安全隧道來實現SSH客戶端與服務器之間的連接…

face alignment by 3000 fps系列學習總結

我們主要講一講Github上給出的matlab開源代碼《jwyang/face-alignment》的配置。 首先聲明&#xff1a;本人第一次配置的時候也是參考了csdn一個作者和github給出的說明配置成功的。其實后來想想很簡單的&#xff0c;但是可能對于初學者&#xff0c;還是有一定的困難。為此&am…

paypal之nodejs 框架 Kraken-js 源碼分析

本文是基于 kraken-js 0.6.1 版本的 關于如何使用kraken-js 可以去看看官網的使用文檔 點擊這里 。kraken-js 是基于express之上的&#xff0c;目的在于讓工程師更多的去關注代碼邏輯&#xff0c;少關注自身的開發環境&#xff0c;所以他將express所有的一些公用的配置都寫在了…

go build 參數_Go語言 通過go bulid -tags 實現編譯控制

Go語言提供的build tag 條件編譯特性&#xff0c;顧名思義&#xff0c;只有在特定條件下才會構建對應的代碼。比如下面的源文件只有在設置debug構建標志時才會被構建&#xff1a;// build debugpackage mainvar buildMode "debug"可以用以下命令構建&#xff1a;go …

selinux 的管理

第十單元selinux 的管理一 顯示及更改 SELINUX 模式getenforce ###顯示selinux模式setenforce 0|1 ##0指permissive警告&#xff0c;1 表示 enforcing強制###vim /etc/sysconfig/selinux ###修改selinux開機狀態###注&#xff1a;disable表示關閉&…

ubuntu15.10下安裝opencv2.4.9python上調用opencv庫

對于centos&#xff0c;可以參考&#xff1a;Install OpenCV-Python in Fedora 如果IPP難以下載可以在cmake時禁掉它&#xff0c;只需&#xff1a;cmake -DWITH_IPPOFF OpenCV3.3CUDA9.0 安裝過程中遇到的問題&#xff0c;解析&#xff1a; https://blog.csdn.net/u014613745/a…

【轉】jquery 注冊事件的方法

原文鏈接&#xff1a;http://outofmemory.cn/code-snippet/2123/jquery-zhuce-event-method 1.使用事件名來綁定&#xff0c;可用的事件名有 change,click,dblclick,error,focus,focusin,focusout,keydown,keypress,keyup,mousedown,mouseenter,mouseleave,mousemove,mouseout,…

ffmpeg 時間戳

轉http://blog.csdn.net/yfh1985sdq/article/details/5721953 AVpacket里的時間戳pts和dts.單位好像是us. 問 : 時間戳pts和dts,這里兩個時間戳各有什么意義? 答 : 顯示時間,解碼時間. DTS&#xff1a;decoding time stamp PTS&#xff1a;presentation time stamp Generally …

鍵盤改鍵軟件_一秒五鍵,一鍵三招,萬種光污染,杜伽K310櫻桃軸機械鍵盤感受...

機械鍵盤我一直用的青軸&#xff0c;或者各種其他名字但其實本質就是青軸的。喜歡青軸那種清脆的聲音&#xff0c;在我聽來如同山間小溪流水般的叮咚。不過這聲音在夜間分外的具有穿透力&#xff0c;更會在人身體不好的時候難以承受&#xff0c;所以每每用過之后卻又不得不換回…

ubuntu 15.10下cmake 的安裝

因為原先ubuntu自帶的cmake有點舊&#xff0c;就想著安裝個最新的&#xff0c;可是直接安裝卡在了某一步上&#xff0c;后面有說明。現將正確的安裝方法列出來。1.卸載原有的版本sudo apt-get autoremove cmake2. 下載最新的cmake :https://cmake.org/download/3. 解壓&#xf…

codeigniter鉤子的使用

CodeIgniter 的鉤子功能&#xff0c;使得我們可以在不修改系統核心文件的基礎上&#xff0c;來改變或增加系統的核心運行功能。可是鉤子究竟該怎么用呢&#xff1f;雖然不是很難&#xff0c;不過很多剛用ci的朋友可能還是不明白怎么用。 通過本文的簡單實例&#xff0c;大家一下…

wxWidgets之wxGrid控件

1. 介紹wxGrid控件時wxWidgets界面庫中內置的網格控件。通經常使用來顯示表格數據。該控件擁有強大的功能。開發人員可依據自己的需求對其進行定制。 2. 經常使用API 構造函數&#xff1a;wxGrid ()wxGrid (wxWindow *parent, wxWindowID id, const wxPoint &poswxDef…