作者 | Gautam Kumar
来源 | Medium
编辑 | 代码医生团队
在过去的十年中已经提出了几种用于图像处理和计算机视觉应用的机器学习算法。LBP,HAAR是一些流行的算法,广泛用于人脸识别并产生出色的结果。但是大多数这些算法不适合在无约束环境中进行实时识别。最近最先进的深度学习技术已经成为传统机器学习算法的新宠。人脸识别应用程序使用的图像只是范围(0-255)中像素值的组合。算法在那些灰度值中找到区别模式并将其视为被认为对于每个图像唯一的特征。然而在3D图像中,不存在像素信息,而是仅每个点的位置(x,y,z)可用。
最近开始研究FRGC2.0 3D人脸数据集,最初无法找到足够的资源来处理3D图像。最后经过一段时间,发现了一篇基于3D人脸识别的论文,“Ajmal Miyan,要感谢他们提供了有用的建议和参考资料。还想提一下同事Jayeeta Chakraborty,同样为开发这个项目做出了贡献。在本文中,将讨论开发3D人脸识别系统的每个处理步骤,以便其他寻找类似工作的人可以先行一步。
https://pdfs.semanticscholar.org/6643/a7feebd0479916d94fb9186e403a4e5f7cbf.pdf
阅读3D深度图像
对象的3D图像包含对象中每个点的高度,宽度和深度。通常,3D原始数据集(例如FRGC 2.0面部数据库,Collection F和Collection G 3D ear数据库)具有.abs,.abs.Z或.abs.gz格式的图像文件。FRGC 2.0 3D人脸数据库的图像样本如图1所示。
图1
这些图像是压缩的ASCII文本文件。建议不要事先解压缩数据集,因为这些文件的扩展可能需要大的磁盘空间。每个图像文件都有一个三行标题,给出了行数和列数。接下来是四张图片。第一个是所谓的“标志”图像,其中像素值为1意味着该像素处的相应(x,y,z)值是有效的。如果标志值为零,则应忽略该像素的(x,y,z)组件。标志图像之后是X坐标图像,Y坐标图像和Z坐标图像。所有都是浮点图像。您可以使用每个范围像素的3D坐标,也可以丢弃X和Y图像,并仅关注Z值。请注意,图像的“纵横比”不必为1。
代码语言:javascript复制�SLOAD Read a UND database range image from file.
% [X,Y,Z,FL] = ABSLOAD(FILENAME) reads the range image in FILENAME
% into the variables X,Y,Z,FL.
% FILENAME is a string that specifies the name of the file
% to be openned
% X,Y,Z are matrices representing the 3D co-ords of each point
% FL is the flags vector specifying if a point is valid
function [x, y, z, fl] = absload(fname)
% open the file
fid = fopen(fname);
% read number of rows
r = fgetl(fid);
r = sscanf(r, '%d');
% read number of columns
c = fgetl(fid);
c = sscanf(c, '%d');
% read junk line
t = fgetl(fid); clear t;
% get flags
fl = fscanf(fid,'%d',[c r])';
% get x
x = fscanf(fid,'%f',[c r])';
% get y
y = fscanf(fid,'%f',[c r])';
% get z
z = fscanf(fid,'%f',[c r])';
% close the file
fclose(fid);
可以使用imshow()函数打印x,y,z,这将显示摄像机面向x轴,y轴和z轴时的图像捕获。连接所有可以看到的图像,如图所示。
图2
提取了云点,将其转换为.ply文件并将其显示为可视化3D图像形状。下图显示了脸部的3D视图。原始图像包含特征提取处理不需要的包括颈部和肩部的脸部图像。因此必须从整个图像中仅裁剪面部区域,这将在下一节中讨论。
图3(a)
图3(b)
上图是相同的主题。图(a)表示使用Matlab进行三维可视化,而图(b)表示在Meshlab工具中显示时。
人脸检测
为了从整个图像中仅提取面部区域,利用深度信息。如果注意到图4中所示的图像,则可以观察到对象面向z轴,并且传感器捕获正面。因此噪声尖端点将具有来自摄像机的最小深度。
图4:主体在z轴上朝向相机
如果仔细观察图4,会发现当从鼻尖向耳朵方向移动时,深度值会从1500增加到1700。如果仍然不清楚鼻尖的概念,请看图5。
图5:鼻尖检测
会注意到黑点所示的鼻尖(P)的z值(深度)大约在1450到1480之间,假设它是1460.现在考虑将鼻尖“ P ”作为中心,绘制了140个单位的方形如图6所示。
图6:面部区域裁剪
根据经验发现,正方形的大小适合于覆盖面部区域。只有点位于该方块被选中以表示面部区域。最后从整个图像裁剪面部部分,得到如图7所示的面部。
图7(a):裁剪的面部区域
图7(b):裁剪的脸部图像
图7(a)和7(b)表示当以不同角度可视化时的裁剪的面部图像。一旦获得裁剪的面部区域,下一步就是执行去尖峰,孔填充和去噪。
Despiking,填充孔和去噪
Despiking:3D面部噪声很大并且包含尖峰,因此需要应用平滑技术。在研究中,将2D加权中值滤波技术的概念扩展到3D人脸图像。所研究的技术使用网格中值滤波的加权中值实现来执行3D数据集的过滤。
孔填充:去除尖钉会导致孔的形成,因此必须填充这些孔。为此使用了3D插值。在所有插值技术中,使用' 立方'。在三次插值方法中,查询点处的插值基于每个相应维度中的相邻网格点处的值的三次插值。该插值基于三次卷积。
噪声消除:数字图像容易受到各种噪声的影响。噪声是图像采集方法中的错误的结果,导致的值不代表实际场景的真实强度。再次使用3D高斯滤波器来消除噪声。
这是所有预处理步骤之后的最终图像,如图8所示。
图8:预处理图像。
用于面部区域检测,裁剪面,despiking,孔填充和去噪的源代码如下所示。
代码语言:javascript复制 %Modify workspace_add and imgFolder path
workspace_add = 'yourworkspacefolder';
%For example 'F:3d_imagesproject_3d_feature'
imgFolder = strcat(workspace_add,'datafolder');
%For example mat3_facedata_selected
%gunzip image data using matlab inbuilt function if you don't have data in
%.abs format
filePattern = fullfile(imgFolder, '*.abs');
jpegFiles = dir(filePattern);
a=dir([imgFolder, '/*.abs']);
numberofFiles = size(a,1);
for k = 1:length(jpegFiles)
baseFileName = jpegFiles(k).name;
fullFileName = fullfile(imgFolder, baseFileName);
[X,Y,Z,FL] = absload(fullFileName);
Z= abs(Z);
X= X(:);
Y = Y(:);
Z = Z(:);
X1 = X(X~=-999999);
Y1 = Y(Y~=-999999);
Z1 = Z(Z~=999999);
ptCloud = pointCloud2rawMesh([X1 Y1 Z1],0.6,1);
[nose_z, nose_ind] = min(ptCloud.vertices(:,3));
nose_pt = ptCloud.vertices(nose_ind,:);
cropped_points = zeros(1,3);
for ind = 1:length(ptCloud.vertices)
if inxrange(ptCloud.vertices(ind,1),nose_pt) && inyrange(ptCloud.vertices(ind,2), nose_pt)
cropped_points = [cropped_points; ptCloud.vertices(ind,:)];
end
end
cropped_points = cropped_points((2:end),:);
xx = double(cropped_points(:,1));
yy = double(cropped_points(:,2));
zz = double(cropped_points(:,3));
zz = -zz;
%uncomment if you want to see cropped image
%mm = pointCloud2rawMesh([xx yy zz],0.6,1);
%makePly(mm, 'my_cropped.ply');
%ptCloud_cropped = pcread('my_cropped.ply');
%pcshow(ptCloud_cropped);
%remove spike and save despiked image following removing noise
%m_test = pointCloud2mesh([xx,yy,zz]);
%zz_despiked_test = medfilt3(m_test);
%ZI_test = interpn(zz_despiked_test,.9,'cubic');
%zz_denoised_test = imgaussfilt3(ZI_test);
%makePly(zz_denoised_test, 'zz_denoised_test.ply');
%zz_denoised_test = pcread('zz_denoised_test.ply');
%pcshow(zz_denoised_test);
try
�spiking process
zz_despiked = medfilt3(zz);
%Multidimensional data interpolation for filling holes
ZI = interpn([xx,yy,zz_despiked],.9,'cubic');
�noising process
zz_denoised = imgaussfilt3(ZI(:,3));
mesh = pointCloud2mesh([xx,yy,zz_denoised]);
catch MExc
end
end
fclose(fid);
% end
function inRng = inxrange(val, nose_pt)
x_llmt = -70 nose_pt(:,1);
x_ulmt = 70 - nose_pt(:,1);
if val >= x_llmt && val <= x_ulmt
inRng = 1;
else
inRng = 0;
end
end
function inRng = inyrange(val, nose_pt)
y_llmt = -70 nose_pt(:,2);
y_ulmt = 70 - nose_pt(:,2);
if val >= y_llmt && val <= y_ulmt
inRng = 1;
else
inRng = 0;
end
end
完成所有步骤后,得到的最终输出是网格图像。根据应用要求,该网格图像可用于特征提取技术。如果要运行ICP算法,建议使用GPU。
完整的代码可以在GitHub存储库中找到。可以下载并使用它来预处理自己的3D面部数据集。
https://github.com/gautamkumarjaiswal/3DFaceRecognition