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,St1)

其中 ΔSt=SgtSt为第t个阶段的残差;而 Φt(I,St1)则为特征提取函数;W为线性回归矩阵。由 《人脸配准坐标变换解析》我们可以看到所谓的 ΔSt需进行相似性变换,而 Φt(I,St1)则不需要.
相似性变换的主要过程是:
先将 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¯¯¯¯=S0mean(S0)=S1mean(S1)}S0¯¯¯¯=c1R1S1¯¯¯¯

因此根据
ΔS=SgS1
可推出
Δ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=S0Ratio+[Region(1),Region(2)]
这里Ratio实际上是intermediate_bboxes的大小。
于是同样按照上面的方法计算:
S0˜=S0_Resizemean(S0_Resize)=S0Ratiomean(S0)Ratio=(S0mean(S0))Ratio=S0¯¯¯¯Ratio

经过计算得 S0˜=RatioS0¯¯¯¯=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.mzph.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. 分别求出来组合数的分子和分母然后相除/******************************…

linux服务器选ubantu或centos_如何通过SSH连接阿里云上的Linux系统

首先SSH是啥&#xff0c;维基一下&#xff1a;Secure Shell&#xff08;安全外壳协议&#xff0c;简称SSH&#xff09;是一种加密的网络传输协议&#xff0c;可在不安全的网络中为网络服务提供安全的传输环境[1]。SSH通过在网络中创建安全隧道来实现SSH客户端与服务器之间的连接…

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…

键盘改键软件_一秒五键,一键三招,万种光污染,杜伽K310樱桃轴机械键盘感受...

机械键盘我一直用的青轴&#xff0c;或者各种其他名字但其实本质就是青轴的。喜欢青轴那种清脆的声音&#xff0c;在我听来如同山间小溪流水般的叮咚。不过这声音在夜间分外的具有穿透力&#xff0c;更会在人身体不好的时候难以承受&#xff0c;所以每每用过之后却又不得不换回…

codeigniter钩子的使用

CodeIgniter 的钩子功能&#xff0c;使得我们可以在不修改系统核心文件的基础上&#xff0c;来改变或增加系统的核心运行功能。可是钩子究竟该怎么用呢&#xff1f;虽然不是很难&#xff0c;不过很多刚用ci的朋友可能还是不明白怎么用。 通过本文的简单实例&#xff0c;大家一下…

powerdesigner画关系图_想画好手绘,这些图你一定要画一下!

画好手绘除了对透视要深入了解掌握以及线条运用把握之外&#xff0c;还有很重要的就是要对空间物体的关系、比例、光影关系都要理解透彻。大体快可分割成多个x小体块。其实当年学习的绘画基础也是画好手绘的基础&#xff0c;画手绘依然需要去理解整体画面的空间黑白灰、物体穿插…

internetreadfile读取数据长度为0_【完结】TensorFlow2.0 快速上手手册

大家好&#xff0c;这是专栏《TensorFlow2.0》的第五篇文章&#xff0c;我们对专栏《TensorFlow2.0》进行一个总结。我们知道全新的TensorFlow2.0 Alpha已经于2019年3月被发布&#xff0c;新版本对TensorFLow的使用方式进行了重大改进&#xff0c;为了满足各位AI人对TensorFlow…

Facial Landmark Detection(人脸特征点检测)

原文地址&#xff1a;http://www.learnopencv.com/facial-landmark-detection/#comment-2471797375 作为计算机视觉研究员&#xff0c;我们很早就开始研究人脸。人脸分析领域最广为人知的就是人脸识别&#xff08;face recognition&#xff09;.但是为了识别一幅图像中的人脸&…

Java中的Error和Exceptiond的异同点

Error和Exception的异同点&#xff1a; &#xff08;1&#xff09;Error类和Exception类都继承超类Java.lang.Throwable &#xff08;2&#xff09;Error&#xff1a;一般指与虚拟机相关的问题&#xff0c;如系统崩溃&#xff0c;内存溢出等。对于这类错误&#xff0c;仅靠程序…

superviseddescent (SDM C++11实现)环境配置

今天试着用了一下SDM的C11实现&#xff0c;本来以为挺简单的&#xff0c;可是配置环境还是花了一些时间。为了给自己留下一些记忆&#xff0c;特把配置过程记录下来。 这个实现是C11的版本&#xff0c;是一个通用版本&#xff0c;里面包含了很多的功能&#xff0c;比如函数的最…

python图形小游戏代码_手把手制作Python小游戏:俄罗斯方块(一)

手把手制作Python小游戏&#xff1a;俄罗斯方块1大家好&#xff0c;新手第一次写文章&#xff0c;请多多指教 A.准备工作&#xff1a; 这里我们运用的是Pygame库&#xff0c;因为Python没有内置&#xff0c;所以需要下载 如果没有pygame&#xff0c;可以到官网下载 pygame官网&…

关于Git使用的一些心得

2019独角兽企业重金招聘Python工程师标准>>> 本篇稍微记录下Git使用的一些心得。 对Git的使用&#xff0c;应该是从搭建自己的博客开始的。当时看到开源中国推荐的一篇基于码云hexo搭建自己博客的文章。所以就花了一天时间鼓捣了下博客。 顺带整理下目前能看到我写的…