Construct Ellipsoid Given Inertia Tensor #978
-
So my research is in Additive Manufacturing and I work with 3D X-ray CT scans that capture gas pores left over from processing. To extract the pores and calculate physical descriptors I use scikit-image's measure module to label the segmented CT scan and calculate region properties of the labeled pores. With measure.regionprops() I can use inertia_tensor to calculate things like aspect ratio and orientation with respect to the xy plane. What I'm trying to do now is figure out how to construct equivalent ellipsoids for each extracted pore using the inertia tensor. With its eigenvalues I can get the axis lengths and aspect ratio, and the eigenvectors give me the orientation, but I'm not sure how to translate that into the axis parameters for vedo's Ellipsoid. Below is an example script to calculate these quantities and render a visualization of the eigenvectors. How do I get to an Ellipsoid from this information?
|
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 5 replies
-
Beta Was this translation helpful? Give feedback.
-
It lloks to me that there must be some mismatch in xz convention + maybe sorting (?) the eigenvalues from skimage import measure
from vedo import *
settings.use_parallel_projection = True
# Create Ellipsoid
ellipsoid = Ellipsoid(axis1=(1,0,0), axis2=(0,2,0), axis3=(0,0,3))
vol = ellipsoid.binarize(spacing=(0.1,0.1,0.1)).print()
np_vol = vol.tonumpy()
# np_vol = np.transpose(np_vol, axes=[2, 1, 0])
# Get Region Properties
labels = measure.label(np_vol, connectivity=2)
properties = measure.regionprops(labels)
centroid = properties[0].centroid
inertia_tensor = properties[0].inertia_tensor * 0.1
inertia_tensor_eigvals = properties[0].inertia_tensor_eigvals
# Calculate Orientation
eigenvalues, eigenvectors = np.linalg.eig(inertia_tensor)
# eigenvalues = np.clip(eigenvalues, 0, None, out=eigenvalues)
# sorted_indices = np.argsort(eigenvalues)
# eigenvectors = np.take_along_axis(eigenvectors, np.stack([sorted_indices]*3), axis=1)
# eigenvector_0 = eigenvectors[:,0]*eigenvalues[sorted_indices[0]]
# eigenvector_1 = eigenvectors[:,1]*eigenvalues[sorted_indices[1]]
# eigenvector_2 = eigenvectors[:,2]*eigenvalues[sorted_indices[2]]
eigenvector_0 = eigenvectors[:,0]*eigenvalues[0]
eigenvector_1 = eigenvectors[:,1]*eigenvalues[1]
eigenvector_2 = eigenvectors[:,2]*eigenvalues[2]
print("eigenvectors\n", eigenvectors)
print("eigenvalues ", eigenvalues)
# Visualize Eigenvectors
vol = Volume(np_vol).alpha((0, 0.05))
vector_0 = Arrow(start_pt=centroid, end_pt=centroid+eigenvector_0, c='red')
vector_1 = Arrow(start_pt=centroid, end_pt=centroid+eigenvector_1, c='blue')
vector_2 = Arrow(start_pt=centroid, end_pt=centroid+eigenvector_2, c='green')
# Construct Ellipsoid With Inertia Tensor
transform = LinearTransform(inertia_tensor).scale(1).translate(centroid)
ell = Sphere().apply_transform(transform).color('green').alpha(0.5)
assembly = Assembly(vol, vector_0, vector_1, vector_2, ell)
print("inertia_tensor\n", inertia_tensor)
print(transform)
show(assembly,
ellipsoid.scale(10).pos(centroid).wireframe(),
axes=1, bg2='lightblue', viewup='z') i will only have time to look into this tuesday evening.. I also found a bug in the Ellipsoid class (but this should not affect the above), |
Beta Was this translation helpful? Give feedback.
-
Thant happens because the numpy array has no information about positioning in space, but Please do
then from vedo import *
settings.use_parallel_projection = True
# Create Ellipsoid
# ellipsoid = Ellipsoid(axis1=(1,0,0), axis2=(2,2,0), axis3=(3,0,3)) # why??
ellipsoid = Ellipsoid(axis1=(1,0,0), axis2=(0,2,0), axis3=(0,0,3))
ellipsoid.rotate_z(45).rotate_x(20).pos([300,400,500])
s = 0.05
vol = ellipsoid.binarize(spacing=(s,s,s)) # keep equal spacing
vol.print()
origin = vol.origin()
spacing = vol.spacing()
np_vol = vol.tonumpy()
redo_vol = Volume(np_vol)
redo_vol.spacing(spacing).origin(origin)
show(vol, redo_vol, N=2, axes=1, bg2='lightgreen', viewup='z').close()
# ...
# inertia_tensor = properties[0].inertia_tensor * s |
Beta Was this translation helpful? Give feedback.
Ok, I was able to take what you had and consistently match it to the same orientation of the original numpy ellipsoid by sorting the eigenvectors first, and then rotating 90 degrees about the eigenvector axis with the middle eigenvalue. The one thing I can't figure out though is how to match the scale of the original numpy ellipsoid. I scaled it by 0.08 to match this specific case, but the scale needed to match to the original is dependent on its size.