我正在使用mayavi的triangular_mesh
方法绘制三维网格。该数据描述了人脸朝下躺在3D空间中的人体轮廓(因此cmap
可用于表示与相机的距离(。
以下是用于生成绘图的代码(面和顶点来自外部对象,这里显示的太多了(:
from mayavi import mlab
import math
import numpy as np
import sys
import os
fig = mlab.figure(fgcolor=(0, 0, 0), bgcolor=(1, 1, 1), size=(1920, 980))
a = np.array(this_mesh.vertices - refC.conj().transpose()) # this_mesh is an object created from external data files
this_mesh.faces = this_mesh.faces.astype(int) -1 # mesh data is generated by matlab, which is 1-indexed
m = mlab.triangular_mesh(x, y, z, this_mesh.faces, opacity=0.75)
mlab.axes(extent=[-1100, 1100, -1100, 1100, -1100, 1100])
在不移动相机的情况下,轮廓面朝下。为了在上面查看模型面,我正在更改相机的方位角和仰角,以便从上到下查看图形。这显示了预期的轮廓。
mlab.view(azimuth=0, elevation=180)
mlab.show()
我的下一个任务是创建一系列图像,相机在情节中平移,从剪影向右开始,到剪影向左结束。
复杂的是,为了获得深度信息的颜色图,我已经在移动视图的方位角和仰角(如上面的代码所示(。Mayavi比matplotlib有更多的移动相机的选择,但它似乎没有绕Y轴旋转的方法,所以我猜我需要对方位角和仰角进行一些复杂的计算才能获得相同的结果,但我不知道从哪里开始(我是3D空间的新手,我的大脑还没有这样想(。
有人能给我指正确的方向吗?
事实证明,有一个解决方法。
可以在独立于摄影机的轴上旋转演员。(这使可视化与数据标记不同步,但由于我实际上隐藏了图形的轴,在这种情况下这无关紧要。(
你所需要做的就是:
m.actor.actor.rotate_y(desired_angle)
你可以走了。
这里需要一些数学知识。好吧,这是如何从代码的角度来做的,这不是最好的代码,但我想让它不言自明。我使用罗德里格斯公式在3d中旋转来实现这一点,az_new和el_new是你的新视角。改变θ的值,在你的参考系中获得不同的视角,我在下面的代码中使用了45度:
import numpy as np
import math
def rotation_matrix(axis, theta):
"""
Return the rotation matrix associated with counterclockwise rotation about
the given axis by theta radians.
"""
axis = np.asarray(axis)
theta = np.asarray(theta)
axis = axis/math.sqrt(np.dot(axis, axis))
a = math.cos(theta/2.0)
b, c, d = -axis*math.sin(theta/2.0)
aa, bb, cc, dd = a*a, b*b, c*c, d*d
bc, ad, ac, ab, bd, cd = b*c, a*d, a*c, a*b, b*d, c*d
return np.array([[aa+bb-cc-dd, 2*(bc+ad), 2*(bd-ac)],
[2*(bc-ad), aa+cc-bb-dd, 2*(cd+ab)],
[2*(bd+ac), 2*(cd-ab), aa+dd-bb-cc]])
az = 90
el = -75
x = np.cos(np.deg2rad(el))*np.cos(np.deg2rad(az))
y = np.cos(np.deg2rad(el))*np.sin(np.deg2rad(az))
z = np.sin(np.deg2rad(el))
# So your viewing vector in x,y coordinates on unit sphere
v = [x,y,z]
# Since you want to rotate about the y axis from this viewing angle, we just increase the
# elevation angle by 90 degrees to obtain our axis of rotation
az2 = az
el2 = el+90
x = np.cos(np.deg2rad(el2))*np.cos(np.deg2rad(az2))
y = np.cos(np.deg2rad(el2))*np.sin(np.deg2rad(az2))
z = np.sin(np.deg2rad(el2))
axis = [x,y,z]
# Now to rotate about the y axis from this viewing angle we use the rodrigues formula
# We compute our new viewing vector, lets say we rotate by 45 degrees
theta = 45
newv = np.dot(rotation_matrix(axis,np.deg2rad(theta)), v)
#Get azimuth and elevation for new viewing vector
az_new = np.rad2deg(np.arctan(newv[1]/newv[0]))
el_new = np.rad2deg(np.arcsin(newv[2]))