I am trying to find the 'long axis' of a 3D object (described as a 3D boolean or label array), which passes through (or near) the centroid of that object.
I would like to think I could simply iterate over every pair of points in the object and pick the pair with the largest distance between them, but in the case of the example object below, that line would not pass through the center of the object.
Similarly, I think I could calculate the distance between every pair of points to find that longest pair that passes within some minimum distance of the center, but I'm worried that I'm reinventing the wheel. It seems like there should be some least-squares fit of a line but the only solutions I have been able to dig up have been for 2D arrays.
Any suggestions would be greatly appreciated.
The following code displays the dimensions of a very simple 3D shape. The shapes I am actually interested contains thousands of points and are more complex but are similar in that 1) the largest distance between two points may be far from the center of the object and 2) they are connected such that they could be described by a single connected outline.
import matplotlib.pyplot as plt
import numpy as np
# make a simple 3D shape
t = [[[0,0,0,0,0],
[0,0,1,0,0],
[0,0,0,0,0],
[0,0,0,0,0],
[0,0,0,0,0]],
[[0,0,0,0,0],
[0,0,1,0,0],
[0,1,1,1,0],
[0,0,0,0,0],
[0,0,0,0,0]],
[[0,0,0,0,0],
[0,0,1,0,0],
[0,1,1,1,0],
[0,0,0,0,0],
[0,0,0,0,0]],
[[0,0,0,0,0],
[0,0,1,0,0],
[0,1,1,1,0],
[0,0,0,0,0],
[0,0,0,0,0]],
[[0,0,0,0,0],
[0,0,1,0,0],
[0,0,0,0,0],
[0,0,0,0,0],
[0,0,0,0,0]]]
t = np.array(t)
# find the centroid of the object
coords = np.where(t == 1)
x = np.mean(coords[0])
y = np.mean(coords[1])
z = np.mean(coords[2])
# show the object at different angles
fig, (ax1, ax2, ax3) = plt.subplots(1, 3)
ax1.imshow(np.max(t, axis=0))
ax1.plot(x,y, 'ro')
ax1.set_title('xy')
ax2.imshow(np.max(t, axis=1))
ax2.plot(x,z, 'ro')
ax2.set_title('xz')
ax3.imshow(np.max(t, axis=2))
ax3.plot(y,z, 'ro')
ax3.set_title('yz')
plt.show()