最近一直在做3D人脸鼻尖识别项目,因为之前没有相关经验,所以前后花了一个半月才做完。

在此记录一下自己的思路:

1.读取人脸点云数据,代码为Matlab代码:

clc;
read_file = importdata('C:\myfiles\xyz\test1\test3\3.xyz'); %读取文件
file_x = read_file(:,1);
file_y = read_file(:,2);
file_z = read_file(:,3);
set(figure,'name','点云');
plot3(file_x,file_y,file_z,'.')

显示的点云:

2.对人脸数据做插值处理,这里直接做的网格化。

[X,Y,Z] = griddata(file_x,file_y,file_z,linspace(min(file_x),max(file_x),200)',linspace(min(file_y),max(file_y),20),'cubic'); %插值
set(figure,'name','网格');
surf(Z);  %显示三维曲面

网格化:

3.对每个Y轴的切片做半圆相交处理(这里我选择用半圆,因为人脸的俯视图是凹的,这跟深度摄像头采集的数据有关,FRGC数据集里面的人脸俯视图是凸的),圆心在切片上滑动,半径采用固定值(我用的是30),相交得到两个交点,计算这两个点和圆心组成的三角形中,以这两个点为底的三角形高H。H的值就是鼻尖置信点的值

这里我写了一个演示代码,方便大家理解这个在切片上做圆,找鼻尖置信点的过程:

% 单层切片遍历所有点,标出鼻尖置信点和两个交点
clc;
read_file = importdata('C:\myfiles\xyz\test1\test3\3.xyz'); %读取文件
file_x = read_file(:,1);
file_y = read_file(:,2);
file_z = read_file(:,3);
% set(figure,'name','点云');
% plot3(file_x,file_y,file_z,'.')
[X,Y,Z] = griddata(file_x,file_y,file_z,linspace(min(file_x),max(file_x),200)',linspace(min(file_y),max(file_y),20),'cubic'); %插值
% set(figure,'name','网格');
% surf(Z);  %显示三维曲面xz = Z(13,:); %获取水平切片,这里的13是自己随便取的一层切片
x = 1:200;
yqu = xz(1,x);
set(figure,'name','切片');
plot(x,yqu);
%画圆
I = find(~isnan(xz)); %获取水平切片非空位置
[x_s,~] = min(I); %水平切片有效起始位置
[x_e,~] = max(I); %水平切片有效终止位置
%r = round((x_e-x_s)/5); %自适应因切圆半径(效果并不好)
r = 30; %指定切圆的半斤,效果更好
h_gaos = []; %切片中每个点作为圆心和切片形成的交点所形成的三角形的高集合
for x1 = x_s+r:x_e-r %圆心的可取值范围if x1>1 %避免水平切片太小z1 = xz(1,x1); %切片中对应z的坐标i = x1-r:x1+r; %圆心的取值范围y2 = sqrt(r.^2-(i-x1).^2)+z1; %切圆的z坐标(上半圆)y = xz(1,i);cy = y2-y;pos = cy>0;neg = cy<=0;%确定变号位置fro = diff(pos)~=0; %变号的前导位置rel = diff(neg)~=0; %变号的尾巴位置zpf = find(fro==1); %记录索引zpr = find(rel==1)+1; %记录索引zpfr = [zpf,zpr];x0 = (i(zpr).*(y2(zpf)-y(zpf))-i(zpf).*(y2(zpr)-y(zpr)))./(y(zpr)+y2(zpf)-y(zpf)-y2(zpr));y0 = y(zpf)+(x0-i(zpf)).*(y(zpr)-y(zpf))./(i(zpr)-i(zpr)-i(zpf));x0 = [x0 x0].';y0 = [y0 y0].';jie = unique([x0,y0],'rows'); %得到切片与下半圆的交点集合[mm,nn] = size(jie);%fprintf('解的个数:');%disp(mm);if mm == 2;jie1 = jie(1,:);jie2 = jie(2,:);if jie1(:,1)<x1 && jie2(:,1)>x1 %确保两个交点在圆心的两侧l1 = ((jie1(:,1)-x1)^2+(jie1(:,2)-z1)^2)^(1/2);l2 = ((jie2(:,1)-x1)^2+(jie2(:,2)-z1)^2)^(1/2);l3 = ((jie1(:,1)-jie2(:,1))^2+(jie1(:,2)-jie2(:,2))^2)^(1/2); %内接三角形的底为p = (l1+l2+l3)/2;s = sqrt(p*(p-l1)*(p-l2)*(p-l3)); %内接三角形的面积h_gao = 2*s/l3;  %内接三角形的高为h_gaos = [h_gaos;[x1,h_gao]]; %形成的高的集合endendend
end
if length(h_gaos)>0[m,p] = max(h_gaos(:,2));x_gao = h_gaos(p,1); %得到最大的高的圆心x坐标% x_gaos = [x_gaos;[j_new,x_gao,m]]; %切片Y坐标,圆心X坐标,最大三角形的高
end
disp('鼻尖置信值:');
disp(h_gaos);
if length(h_gaos)>0disp(size(h_gaos));[m,p]=max(h_gaos(:,2));x_gaos=h_gaos(p,1);z_gaos=xz(1,x_gaos);fprintf('最大三角形的x坐标为:');disp(x_gaos);fprintf('最大三角形的高为:');disp(m);hold on;i = x_gao-r:x_gao+r; %圆心的取值范围y2 = sqrt(r.^2-(i-x_gao).^2)+z_gaos; %切圆的z坐标(上半圆)y = xz(1,i);h=plot(i,y2,'b');cy = y2-y;pos = cy>0;neg = cy<=0;%确定变号位置fro = diff(pos)~=0; %变号的前导位置rel = diff(neg)~=0; %变号的尾巴位置zpf = find(fro==1); %记录索引zpr = find(rel==1)+1; %记录索引zpfr = [zpf,zpr];hold on;% 线性求交x0 = (i(zpr).*(y2(zpf)-y(zpf))-i(zpf).*(y2(zpr)-y(zpr)))./(y(zpr)+y2(zpf)-y(zpf)-y2(zpr));y0 = y(zpf)+(x0-i(zpf)).*(y(zpr)-y(zpf))./(i(zpr)-i(zpr)-i(zpf));x0 = [x0 x0].';y0 = [y0 y0].';hc=plot(x0,y0,'r*',x_gao,z_gaos,'g*');legend([h;hc],'切平面','交点','圆心','Location','northwest');xlabel('x'),ylabel('y'),zlabel('z');title('平面曲线焦点')
elsedisp('找不到置信点');
end

演示的结果如下图:

说明:这里的圆看起来像椭圆,那是因为显示的问题,具体可以在matlab显示中设置。这里的绿点表示在当前切片层中找到的鼻尖置信点,红点是圆和切片相交的两个交点,以两个红点为底,和绿点构成的三角形的高即为鼻尖的置信值

4.为了提高鼻尖检测的速度,采用从粗到细的方法,也就是说先将点云数据网格化20行,对这20行的每一行做步骤3处理,得到置信值最高的那一行,然后对那一行的上一行和下一行再做细致的切片处理。取第二次得到的所有置信点中的前10个,将这0个点转化到点云坐标系中。对这0个数据做RANSAC直线拟合,计算这10个点到直线的距离,在满足一定阈值的点中,选择深度值最小的那个点。(这一步的目的是去除置信点中的点云噪点)

5.经过第四步取到的那个点即为鼻尖点

最终效果如下图所示:图中红圈是10个鼻尖置信点,绿色部分为最终判断的鼻尖点。

完整代码如下:

clc;
read_file = importdata('C:\myfiles\xyz\test1\test3\3.xyz'); %读取文件
file_x = read_file(:,1);
file_y = read_file(:,2);
file_z = read_file(:,3);
set(figure,'name','点云');
plot3(file_x,file_y,file_z,'.')
[X,Y,Z] = griddata(file_x,file_y,file_z,linspace(min(file_x),max(file_x),200)',linspace(min(file_y),max(file_y),20),'cubic'); %插值
set(figure,'name','网格');
surf(Z);  %显示三维曲面
nose = []; %鼻尖候选点
x_gaos = []; %鼻尖置信点
II = [];
% 求Y轴的切片有效范围
for j_new = 1:20 %鲁莽的直接选择切片高度xz = Z(j_new,:); %获取水平切片%画圆I = find(~isnan(xz)); %获取水平切片非空位置[x_s,~] = min(I); %水平切片有效起始位置[x_e,~] = max(I); %水平切片有效终止位置%r = round((x_e-x_s)/5); %自适应因切圆半径(效果并不好)r = 30; %指定切圆的半斤,效果更好h_gaos = []; %切片中每个点作为圆心和切片形成的交点所形成的三角形的高集合for x1 = x_s+r:x_e-r %圆心的可取值范围if x1>1 %避免水平切片太小z1 = xz(1,x1); %切片中对应z的坐标i = x1-r:x1+r; %圆心的取值范围y2 = sqrt(r.^2-(i-x1).^2)+z1; %切圆的z坐标(上半圆)y = xz(1,i);cy = y2-y;pos = cy>0;neg = cy<=0;%确定变号位置fro = diff(pos)~=0; %变号的前导位置rel = diff(neg)~=0; %变号的尾巴位置zpf = find(fro==1); %记录索引zpr = find(rel==1)+1; %记录索引zpfr = [zpf,zpr];x0 = (i(zpr).*(y2(zpf)-y(zpf))-i(zpf).*(y2(zpr)-y(zpr)))./(y(zpr)+y2(zpf)-y(zpf)-y2(zpr));y0 = y(zpf)+(x0-i(zpf)).*(y(zpr)-y(zpf))./(i(zpr)-i(zpr)-i(zpf));x0 = [x0 x0].';y0 = [y0 y0].';jie = unique([x0,y0],'rows'); %得到切片与下半圆的交点集合[mm,nn] = size(jie);%fprintf('解的个数:');%disp(mm);if mm == 2;jie1 = jie(1,:);jie2 = jie(2,:);if jie1(:,1)<x1 && jie2(:,1)>x1 %确保两个交点在圆心的两侧l1 = ((jie1(:,1)-x1)^2+(jie1(:,2)-z1)^2)^(1/2);l2 = ((jie2(:,1)-x1)^2+(jie2(:,2)-z1)^2)^(1/2);l3 = ((jie1(:,1)-jie2(:,1))^2+(jie1(:,2)-jie2(:,2))^2)^(1/2); %内接三角形的底为p = (l1+l2+l3)/2;s = sqrt(p*(p-l1)*(p-l2)*(p-l3)); %内接三角形的面积h_gao = 2*s/l3;  %内接三角形的高为h_gaos = [h_gaos;[x1,h_gao]]; %形成的高的集合endendendendif length(h_gaos)>0[m,p] = max(h_gaos(:,2));x_gao = h_gaos(p,1); %得到最大的高的圆心x坐标x_gaos = [x_gaos;[j_new,x_gao,m]]; %切片Y坐标,圆心X坐标,最大三角形的高end
end
[max_h_1,max_p_1] = max(x_gaos(:,3));
j_max_1 = x_gaos(max_p_1,1);
j_2_s = Y((j_max_1-1),1);
j_2_e = Y((j_max_1+1),1);number = size(read_file,1);
new_file = [];
for i = 1:numberif j_2_s < read_file(i,2) && read_file(i,2) < j_2_enew_file = [new_file;read_file(i,:)];end
end
new_x = new_file(:,1);
new_y = new_file(:,2);
new_z = new_file(:,3);
[Xx,Yy,Zz] = griddata(new_x,new_y,new_z,linspace(min(new_x),max(new_x),200)',linspace(min(new_y),max(new_y),40),'cubic'); %插值for j_new = 1:40 %鲁莽的直接选择切片高度xz = Zz(j_new,:); %获取水平切片%画圆I = find(~isnan(xz)); %获取水平切片非空位置[x_s,~] = min(I); %水平切片有效起始位置[x_e,~] = max(I); %水平切片有效终止位置%r = round((x_e-x_s)/5); %自适应因切圆半径(效果并不好)r = 30; %指定切圆的半斤,效果更好h_gaos = []; %切片中每个点作为圆心和切片形成的交点所形成的三角形的高集合for x1 = x_s+r:x_e-r %圆心的可取值范围if x1>1 %避免水平切片太小z1 = xz(1,x1); %切片中对应z的坐标i = x1-r:x1+r; %圆心的取值范围y2 = sqrt(r.^2-(i-x1).^2)+z1; %切圆的z坐标(上半圆)y = xz(1,i);cy = y2-y;pos = cy>0;neg = cy<=0;%确定变号位置fro = diff(pos)~=0; %变号的前导位置rel = diff(neg)~=0; %变号的尾巴位置zpf = find(fro==1); %记录索引zpr = find(rel==1)+1; %记录索引zpfr = [zpf,zpr];x0 = (i(zpr).*(y2(zpf)-y(zpf))-i(zpf).*(y2(zpr)-y(zpr)))./(y(zpr)+y2(zpf)-y(zpf)-y2(zpr));y0 = y(zpf)+(x0-i(zpf)).*(y(zpr)-y(zpf))./(i(zpr)-i(zpr)-i(zpf));x0 = [x0 x0].';y0 = [y0 y0].';jie = unique([x0,y0],'rows'); %得到切片与下半圆的交点集合[mm,nn] = size(jie);%fprintf('解的个数:');%disp(mm);if mm == 2;jie1 = jie(1,:);jie2 = jie(2,:);if jie1(:,1)<x1 && jie2(:,1)>x1 %确保两个交点在圆心的两侧l1 = ((jie1(:,1)-x1)^2+(jie1(:,2)-z1)^2)^(1/2);l2 = ((jie2(:,1)-x1)^2+(jie2(:,2)-z1)^2)^(1/2);l3 = ((jie1(:,1)-jie2(:,1))^2+(jie1(:,2)-jie2(:,2))^2)^(1/2); %内接三角形的底为p = (l1+l2+l3)/2;s = sqrt(p*(p-l1)*(p-l2)*(p-l3)); %内接三角形的面积h_gao = 2*s/l3;  %内接三角形的高为h_gaos = [h_gaos;[x1,h_gao]]; %形成的高的集合endendendendif length(h_gaos)>0[m,p] = max(h_gaos(:,2));x_gao = h_gaos(p,1); %得到最大的高的圆心x坐标x_gaos = [x_gaos;[j_new,x_gao,m]]; %切片Y坐标,圆心X坐标,最大三角形的高end
end
ans = sortrows(x_gaos,-3); %按照高的大小顺序排列(倒序)
nose_cut = ans(1:20,:); %取前20个最大的高对应的圆心坐标
for mq = 1:20nose = [nose;[Xx(1,nose_cut(mq,2)),Yy(nose_cut(mq,1),1),Zz(nose_cut(mq,1),nose_cut(mq,2))]];
end
% fprintf('鼻尖置信点的维度:');
% disp(x_gaos);
% fprintf('列出置信点:');
% disp(nose_cut);
% fprintf('在原坐标系中显示出鼻尖置信点的位置:');
% disp(nose);
hold on;
nose_x = nose(:,1);
nose_y = nose(:,2);
nose_z = nose(:,3);
plot3(nose_x,nose_y,nose_z,'o');% RANSAC直线拟合
data=[nose(:,1)';nose(:,2)'];
iter = 500;
number = size(data,2); % 总点数
bestParameter1=0; bestParameter2=0; % 最佳匹配的参数
sigma = 1;
pretotal=0;     %符合拟合模型的数据的个数
for i=1:iteridx = randperm(number,2);  %随机选择两个点sample = data(:,idx); line = zeros(1,3);%拟合直线方程 y=kx+bx = sample(1, :);y = sample(2, :);if x(1)==x(2)a = 1;b = 0;c = -x(1);line = [a b c];elsek=(y(1)-y(2))/(x(1)-x(2)); %直线斜率a = sqrt(1-1/(1+k^2));b = sqrt(1-a^2);if k > 0b = -b;endc = -a*x(1)-b*y(1);line = [a b c];endmask=abs(line*[data; ones(1,size(data,2))]);    %求每个数据到拟合直线的距离total=sum(mask<sigma);              %计算数据距离直线小于一定阈值的数据的个数if total>pretotal            %找到符合拟合直线数据最多的拟合直线pretotal=total;bestline=line;          %找到最好的拟合直线end
end
%显示符合最佳拟合的数据
mask=abs(bestline*[data; ones(1,size(data,2))])<sigma;
hold on;
k=1;
nose_z = 1000;
for i=1:length(mask)if mask(i)if nose(i,3) < nose_znose_z = nose(i,3);nose_i = i;endend
end
hold on;
nose_max_x = nose(nose_i,1);
nose_max_y = nose(nose_i,2);
nose_max_z = nose(nose_i,3);
plot3(nose_max_x,nose_max_y,nose_max_z,'g*');

6.根据鼻尖置信点,裁剪人脸。思路很简单,算每个点距离置信点的欧式距离,满足阈值内的点保存下来就行了

截取人脸
radius = 90;
[file_row,file_list] = size(read_file);
face = [];
for cut_i = 1:file_rowface_x = read_file(cut_i,1);face_y = read_file(cut_i,2);face_z = read_file(cut_i,3);distance = ((face_x-nose_max_x)^2+(face_y-nose_max_y)^2+(face_z-nose_max_z)^2)^0.5;if distance < radiusface = [face;read_file(cut_i,:)];end
end
xx = face(:,1);
yy = face(:,2);
zz = face(:,3);
set(figure,'name','人脸');
plot3(xx,yy,zz,'.');
%[face_row,face_list] = size(face);
output_file = 'C:\myfiles\xyz\test1\test2\face_1_1_1.xyz';
fid = fopen(output_file,'w');
for i = 1:length(face)
%     for j = 1:face_list
%         fprintf(fid,'%f\n',face(i,j));
%     endfprintf(fid,'%.3f %.3f %.3f\n',face(i,:));
%     fprintf(fid,'\r\n');
end
fclose(fid);

7.以上只是对单个文件进行处理,那么如果想怎么办。贴心的我当然给大家准备好了!

% 第二版鼻尖算法,批处理,自采数据使用
clc;
input_path = 'D:\.....\pending\';  % 要处理的原文件夹
output_path = 'D:\.....\result\';  % 要保存到的文件夹
fileExt = '*.xyz';
files = dir(fullfile(input_path,fileExt));
len = size(files,1);
for file_num = 1:lenfileName = strcat(input_path,files(file_num,1).name);read_file = importdata(fileName);file_x = read_file(:,1);file_y = read_file(:,2);file_z = read_file(:,3);...output_file = strcat(output_path,files(file_num,1).name);...
end

说明:中间省略的内容就是步骤5和步骤6中的代码,其中主要涉及的是读取的文件名和保存的文件名,我已经给大家写好了。请享用!

这是我花了很长时间做出来的,切勿转载!切勿转载!切勿转载!如果有什么改进的地方,欢迎大家指出。

3D点云人脸鼻尖检测算法相关推荐

  1. 百度智能云人脸活体检测系统获得公安部一所首批安全性能认证

    随着人工智能视觉技术的迅速发展,"刷脸"远程实名认证因其核验流程快捷,用户体验良好的优点被各行业所接受和应用,在银行开户.手机办卡.社交直播.电商用户认证等业务环节中随处可见,且往 ...

  2. Tensorflow2实现人脸关键点检测算法PFLD——一个精度高,速度快,模型小的人脸关键点检测模型

    1. 前言 最近,学了人脸关键点检测算法,发现一个比较好的人脸关键点检测模型,打算学一学,让我们来看看算法是如何实现的吧! 论文地址:https://arxiv.org/pdf/1902.10859. ...

  3. 基于HSV+HOG特征和SVM的人脸口罩检测算法

    基于HSV+HOG特征和SVM的人脸口罩检测算法 基于python语言编写,使用retinaface检测人脸和定位五个特征点,利用特征点进一步定位口鼻区域,提取该区域的HSV特征和HOG特征,使用SV ...

  4. 3D点云two-stage目标检测方法优化综述

    点击上方"3D视觉工坊",选择"星标" 干货第一时间送达 前言 和二维图像目标检测一样,3D点云目标检测除了按照输入模态划分为基于点云.基于单目.基于双目或者是 ...

  5. PFLD:简单高效的实用人脸关键点检测算法

    作者丨杜敏 学校丨华中科技大学硕士 研究方向丨模式识别与智能系统 研究背景 人脸关键点检测,在很多人脸相关的任务中,属于基础模块,很关键.比如人脸识别.人脸验证.人脸编辑等等.想做人脸相关的更深层次的 ...

  6. 人脸识别,人脸关键点检测算法

    from http://blog.csdn.net/sloanqin/article/details/48193119 1 Face++:http://www.faceplusplus.com.cn/ ...

  7. 【论文解读】PFLD:高精度实时人脸关键点检测算法

    这篇文章作者分别来自天津大学.武汉大学.腾讯AI实验室.美国天普大学.该算法对在高通ARM 845处理器可达140fps:另外模型大小较小,仅2.1MB:此外在许多关键点检测的benchmark中也取 ...

  8. 【毕业设计】基于程序化生成和音频检测的生态仿真与3D内容生成系统----音频检测算法设计

    (2条消息) [开发日志]2022.09.02 ZENO----Audio----Beat detection algorithm----Combine Wav&Mp3_minimp3 和 f ...

  9. 「每周CV论文推荐」 初学深度学习人脸关键点检测必读文章

    人脸关键点检测是人脸图像中重要的基石,今天给大家介绍入门深度学习人脸关键点检测必读的文章. 作者&编辑 | 言有三 1 DCNN Cascade 听这个名字就知道是一个很早期的,使用Casca ...

  10. 【每周CV论文推荐】 初学深度学习人脸关键点检测必读文章

    欢迎来到<每周CV论文推荐>.在这个专栏里,还是本着有三AI一贯的原则,专注于让大家能够系统性完成学习,所以我们推荐的文章也必定是同一主题的. 人脸关键点检测是人脸图像中重要的基石,今天给 ...

最新文章

  1. Redis缓存使用技巧和设计方案
  2. uni-app编译配置
  3. vim 同一行内单字符搜索跳转(笔记)
  4. Twipstopixels java_17.9.3 与设备无关的绘制(4)
  5. swift 原生给h5发消息_Swift-WKWebView与JavaScript的细节,H5页面跳转原生界面
  6. spring整合问题集合1
  7. windows下c 用mysql数据库_Windows环境下C/C++访问PostgreSQL数据库
  8. cvpr2020 人脸检测与识别_CVPR2020 论文分类下载 「人脸识别+目标检测」
  9. 使用 Jenkins + GitHub + Nginx + HTTPS 搭建静态网站
  10. spring5.0学习笔记8
  11. private访问权限java_Java 访问权限控制:public、private、protected
  12. linux命令详解词典pdf,[计算机]linux命令详解词典
  13. sqlite 服务器数据库文件,sqlite可以做服务器数据库吗
  14. JS搜索省份匹配出省份的所有城市
  15. 容量治理-扩容、限流和降级
  16. 互联网企业实习面试经验分享(谷歌微软hulu阿里腾讯字节美团百度等等)
  17. CMM(Capability Maturity Model) 能力成熟度模型
  18. 服务器无线桥接怎么设置,WDS无线桥接如何设置
  19. 【转载】HTML自定义滚动条(仿网易邮箱滚动条)
  20. 学习软件测试的一天(11.4)

热门文章

  1. 优秀LOGO设计的规则
  2. 从达特茅斯会议到图灵奖---人工智能学习分享
  3. JQuery 学习总结及实例 !! (转载)
  4. gif一键抠图 在线_高效抠图PS竟全然不是对手?堪称黑科技的AI一键抠图网站
  5. 阿里云服务器哪个便宜?
  6. 移动H5前端性能优化指南
  7. 《王道》第13章 树--PART1
  8. java如何获取hostid_将Unix hostid转换为Java
  9. 将Spring Boot Web应用部署到Tomcat服务器
  10. 通软终端安全管理系统V6 卸载脚本