我有两个人脸3D点云样本。蓝点云表示目标面部,红点云表示模板。下图显示目标和模板面在不同方向上对齐(目标面大致沿x轴,模板面大致沿y轴)。
我想以鼻尖为旋转中心旋转目标脸(蓝色脸)(我将目标平移到图1之前的模板上,以便鼻尖(即centerpt
)用于两个面都叠加)以与模板面(红色面)大致对齐。我使用以下MATLAB代码旋转了目标面部:
% PCA for the target face
targetFaceptfmt = pointCloud(targetFace); % Convert to point cloud format
point = [templateFace(3522, 1), templateFace(3522, 2), templateFace(3522, 3)]; % The 3522th point in the templateFace is the nasal tip point used as center of rotation later on
radius = 20; % 20mm
[NNTarIndex, NNTarDist] = findNeighborsInRadius(Locationptfmt, point, radius); % Find all vertices within 20 of the nasal tip point on the target face
NNTar = select(Locationptfmt, NNTarIndex); % Select the identified points for PCA
[TarVec,TarSCORE,TarVal] = pca(NNTar.Location); % Do PCA for target face using vertices close to the nasal tip
% PCA for the template face
templateFaceptfmt = pointCloud(templateFace); % Convert to point cloud format
[NNTemIndex, NNTemDist] = findNeighborsInRadius( templateFaceptfmt, point, radius); % Find all vertices within 20 of the nasal tip point on the template
NNTem = select(templateFaceptfmt, NNTemIndex); % Select the identified points for PCA
[TemVec,TemSCORE,TemVal] = pca(NNTem.Location); % Do PCA for template face using vertices close to the nasal tip
% Rotate target face with nasal tip point as the center of rotation
targetFace_r = R * (targetFace-cenertpt)' + centerpt';
targetFace_new = targetFace_r';
其中targetFace
和templateFace
分别包含未旋转目标面和模板面的坐标。 targetFace_r
包含围绕鼻尖旋转后目标脸的坐标,R
是通过PCA计算的旋转矩阵(有关旋转公式的来源,请参见here),{{1} }是鼻尖,用作旋转中心。然后,我绘制了转置的centerpt
,即targetFace_r
,并向每个顶点添加了法线:
在旋转之前,目标面和模板面的法线通常指向相似的方向(图1)。旋转后,目标和模板面都沿y轴对齐(这是我想要的),但是,目标面和模板面的法线指向相反的方向。考虑到模板面未做任何更改,我意识到旋转后计算出的目标面的法线会翻转。但是我不知道为什么。我在R中使用了Rvcg包的targetFace_new
函数来检查沿法线的扩展是否会增加质心的大小。模板面返回TRUE,目标面返回FALSE,这确认目标面的顶点法线已翻转。
顶点法线在MATLAB中的计算如下:
checkFaceOrientation
其中TR = triangulation(Faces, Vertices); % Triangulation based on face and vertex information
VN = vertexNormal(TR); % Calculate vertext normal
包含面部信息,即连接列表,而Faces
包含顶点的坐标。对于旋转前的目标面,旋转后的目标面以及模板面,顶点法线分别进行计算。在旋转目标面前后,我使用相同的Vertices
数据来计算顶点法线。
顶点法线翻转会导致错误,需要进一步分析。结果,我必须手动翻转法线以使其指向与模板面法线相似的位置。
图3: 图3显示,手动翻转法线后,目标和模板面的法线通常指向相似的方向。
我的问题是,旋转翻转后为什么要计算目标面部的法线?在什么情况下3D点云的旋转会导致顶点法线翻转?
可能有用的其他信息:我获得的旋转矩阵Faces
如下:
R
自0.0473096146726546 0.867593376108813 -0.495018720950670
0.987013081649028 0.0355601323276586 0.156654567895508
-0.153515396665006 0.496001220483328 0.854643675613313
起,我通过trace(R) = 1 + 2cos(alpha)
计算了alpha值,相对于鼻尖点,旋转角度为91.7904。
答案 0 :(得分:3)
如果我正确理解了所有内容,则看来您的旋转矩阵实际上是对旋转加反射进行编码。如果您的矩阵大约是:
0.04 0.86 -0.49
0.98 0.03 0.15
-0.15 0.49 0.85
则沿正轴指向的每个单位矢量的图像为:
x = [ 0.04 0.98 -0.15]
y = [ 0.86 0.03 0.49]
z = [-0.49 0.15 0.85]
但是,如果取x
和y
(cross(x, y)
)的叉积,您将得到大约[0.49 -0.15 -0.85]
,这是{{1}的否定},表示矩阵同时编码旋转和反射。自然地,将网格的顶点乘以反射矩阵会反转其多边形的缠绕顺序,从而产生倒置的法线。
在您引用的幻灯片中,它指出生成旋转矩阵的PCA方法在3D情况下应仅考虑轴的四个不同组合,以确保输出矩阵遵循右手法则。如果检查了所有轴组合,则PCA在搜索最佳匹配时将考虑旋转空间和反射空间。如果是这种情况,并且如果数据中存在一些噪声,使得模板的左半部分与目标的右半部分稍有匹配,反之亦然,则PCA方法可能会生成一个像你观察。也许您可能想重新审视如何从PCA结果中生成z
的逻辑?
答案 1 :(得分:2)
如in the comments所指,顶点法线的方向将取决于您如何对Faces
矩阵中的三角形小平面进行排序。这将遵循right-hand rule,其中您的手指遵循三角形周围的顶点顺序,而您的拇指指示表面法线方向。这是一个简单的示例来帮助说明:
Vertices = [0 0; 0 1; 1 1; 1 0]; % Points clockwise around a unit square in x-y plane
Faces = [1 2 3; 1 3 4]; % Two triangular facets, clockwise vertex ordering
TR = triangulation(Faces, Vertices);
VN = vertexNormal(TR)
VN =
0 0 -1
0 0 -1
0 0 -1
0 0 -1
在此示例中,Vertices
包含x-y平面中单位正方形的4个顶点,如果从正z向下看则按顺时针方向排列。 Faces
中定义了两个三角形小平面,并且每行中索引的顺序也沿顺时针方向沿着顶点跟踪。这会导致指向负z方向的每个面的表面法线。计算 vertex 法线时,它们也指向负z方向。
当我们翻转一个三角形的阶以使其点为逆时针时会发生什么?...
Faces = [1 2 3; 1 4 3]; % Second facet is 1 4 3 instead of 1 3 4
TR = triangulation(Faces, Vertices);
VN = vertexNormal(TR)
VN =
0 0 0
0 0 -1
0 0 0
0 0 1
现在,第二个三角形的表面法线将指向z的正方向。仅由一个三角形(第2行和第4行)使用的顶点将具有与曲面法线匹配的顶点法线,而每个三角形(行1和3)共享的顶点将具有0的顶点法线(两个曲面法线抵消)
这将如何帮助您解决问题?好吧,很难说,因为我不知道您是如何定义Faces
和Vertices
的。但是,如果您确定网格中的每个顶点法线都指向错误的方向,则可以通过在计算法线之前交换Faces
矩阵中的两列来轻松地将它们全部翻转:
Faces = [1 2 3; 1 3 4]; % Clockwise-ordered vertices
TR = triangulation(Faces(:, [1 3 2]), Vertices); % Change to counter-clockwise
VN = vertexNormal(TR)
VN =
0 0 1 % Normals are now pointing in positive z
0 0 1
0 0 1
0 0 1