Mayavi:围绕y轴旋转

10

我正在使用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轴旋转的方法,因此我猜想我需要对方位角和俯仰角进行一些复杂的计算才能实现相同的结果——但我不知道从哪里开始(我刚接触三维空间工作,并且我的大脑还没有思考过这种方式)。

有人能指点我正确的方向吗?

2个回答

4
原来有一个解决方法。
你可以独立旋转演员的轴,而不受相机的限制。(这会使得可视化与数据标注不同步,但在我隐藏图形轴的情况下并不重要。)
你只需要做以下几点:
m.actor.actor.rotate_y(desired_angle)

只要你准备好了,就可以开始了。


2
顺便提一下,desired_angle 是以度为单位而不是弧度,并且负数也可以。 - BoltzmannBrain

2

这里需要进行一些数学计算。好的,下面是如何在代码中实现它,虽然不是最佳代码,但我想让它能够自我解释。我使用了3D旋转的Rodrigues公式来实现它,az_new和el_new是您的新视角。更改theta的值以获得您参考框架中的不同视角,我在下面的代码中使用了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]))

非常感谢,这看起来很有用。我会在周一尝试一下,看看它的效果如何。 - MassivePenguin
嗯,还差一点(它正在错误的轴上旋转)。我可能得尝试完全不同的方法... - MassivePenguin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接