Python 如何在numpy中将三维密度贴图的主轴与笛卡尔坐标轴对齐?

Python 如何在numpy中将三维密度贴图的主轴与笛卡尔坐标轴对齐?,python,numpy,image-rotation,ndimage,Python,Numpy,Image Rotation,Ndimage,我有一个nxnnumpy数组,它包含立方网格上的密度值。我试图将密度图的惯性主轴与网格的笛卡尔x,y,z轴对齐。到目前为止,我有以下几点: import numpy as np from scipy import ndimage def center_rho(rho): """Move density map so its center of mass aligns with the center of the grid""" rhocom = np.array(ndimage

我有一个nxnnumpy数组,它包含立方网格上的密度值。我试图将密度图的惯性主轴与网格的笛卡尔x,y,z轴对齐。到目前为止,我有以下几点:

import numpy as np
from scipy import ndimage

def center_rho(rho):
    """Move density map so its center of mass aligns with the center of the grid"""
    rhocom = np.array(ndimage.measurements.center_of_mass(rho))
    gridcenter = np.array(rho.shape)/2.
    shift = gridcenter-rhocom
    rho = ndimage.interpolation.shift(rho,shift,order=1,mode='wrap')
    return rho

def inertia_tensor(rho,side):
    """Calculate the moment of inertia tensor for the given density map."""
    halfside = side/2.
    n = rho.shape[0]
    x_ = np.linspace(-halfside,halfside,n)
    x,y,z = np.meshgrid(x_,x_,x_,indexing='ij')
    Ixx = np.sum(rho*(y**2 + z**2))
    Iyy = np.sum(rho*(x**2 + z**2))
    Izz = np.sum(rho*(x**2 + y**2))
    Ixy = -np.sum(rho*x*y)
    Iyz = -np.sum(rho*y*z)
    Ixz = -np.sum(rho*x*z)
    I = np.array([[Ixx, Ixy, Ixz],
                  [Ixy, Iyy, Iyz],
                  [Ixz, Iyz, Izz]])
    return I

def principal_axes(I):
    """Calculate the principal inertia axes and order them in ascending order."""
    w,v = np.linalg.eigh(I)
    return w,v

#number of grid points along side
n = 10
#note n <= 3 produces unit eigenvectors, not sure why
#in practice, n typically between 10 and 50
np.random.seed(1)
rho = np.random.random(size=(n,n,n))
side = 1. #physical width of box, set to 1.0 for simplicity

rho = center_rho(rho)
I = inertia_tensor(rho,side)
PAw, PAv = principal_axes(I)

#print magnitude and direction of principal axes
print "Eigenvalues/eigenvectors before rotation:"
for i in range(3):
    print PAw[i], PAv[:,i]

#sanity check that I = R * D * R.T
#where R is the rotation matrix and D is the diagonalized matrix of eigenvalues
D = np.eye(3)*PAw
print np.allclose(np.dot(PAv,np.dot(D,PAv.T)),I)

#rotate rho to align principal axes with cartesian axes
newrho = ndimage.interpolation.affine_transform(rho,PAv.T,order=1,mode='wrap')

#recalculate principal axes
newI = inertia_tensor(newrho,side)
newPAw, newPAv = principal_axes(newI)

#print magnitude and direction of new principal axes
print "Eigenvalues/eigenvectors before rotation:"
for i in range(3):
    print newPAw[i], newPAv[:,i]
(这可能是错误的)但甚至不要从单位向量开始。我得到的是:

Eigenvalues/eigenvectors before rotation:
102.405523732 [-0.05954221 -0.8616362   0.5040216 ]
103.177395578 [-0.30020273  0.49699978  0.81416801]
104.175688943 [-0.95201526 -0.10283129 -0.288258  ]
True
Eigenvalues/eigenvectors after rotation:
104.414931478 [ 0.38786    -0.90425086  0.17859172]
104.731536038 [-0.74968553 -0.19676735  0.63186566]
106.151322662 [-0.53622405 -0.37896304 -0.75422197]
我不确定问题是我的代码还是我关于旋转主轴的假设,但如果有任何帮助,我将不胜感激。

是我开发的用于进行这种对齐的代码的链接

给定一组具有坐标(x、y、z)的散射点,目标是将与最小特征值相关联的特征向量与三维笛卡尔轴的x轴相匹配,并将与中值特征值相关联的特征向量与来自同一三维笛卡尔轴的y轴相匹配

为此,我遵循了以下步骤:

  • 仅通过以下操作将质心为(xmn,ymn,zmn)的点集转换为质心为(0,0,0)的新点集:(x-xmn,y-ymn,z-zmn)

  • 计算与最小特征值(min_特征值)相关的特征向量xy投影与笛卡尔轴中x轴之间的角度θ(围绕z旋转)。在获得结果θ后,将最小特征旋转给定θ,使其包含在xy平面中。让我们把这个结果向量称为:rotz

  • 计算旋转Z轴和x轴之间的角度φ,以便绕y轴旋转。一旦获得phi,将沿y轴旋转Z a。在最后一次旋转中,与介质特征向量(medium_eigen)相关联的特征向量位于笛卡尔轴的yz投影中,因此我们只需要找到medium_eigen和笛卡尔轴的y轴之间的角度

  • 计算介质特征线和y轴之间的角度α。围绕x轴A应用旋转:完成

  • 注:在将步骤1、2、3应用于点集后,必须重新计算3D_SVD(3D_单值分解)并从生成的特征向量集计算,然后使用新的中间特征向量执行第四步

    我真的希望这有帮助


    旋转是通过这里定义的旋转矩阵来实现的:

    我知道这很旧,但我想ping一下,看看是否有人能帮上忙。结果证明这是可行的,你只需要在循环中运行几次。插值会引起问题。一旦它应用了3次左右,它就在可接受的公差范围内给出了单位矩阵。谢谢你的努力。我实际上在寻找如何旋转一个nxnxn数组,而不是一组N点(这是一个nx3数组)。我认为问题主要在于插值。我现在有了一些代码来解决这个问题。
    Eigenvalues/eigenvectors before rotation:
    102.405523732 [-0.05954221 -0.8616362   0.5040216 ]
    103.177395578 [-0.30020273  0.49699978  0.81416801]
    104.175688943 [-0.95201526 -0.10283129 -0.288258  ]
    True
    Eigenvalues/eigenvectors after rotation:
    104.414931478 [ 0.38786    -0.90425086  0.17859172]
    104.731536038 [-0.74968553 -0.19676735  0.63186566]
    106.151322662 [-0.53622405 -0.37896304 -0.75422197]