I have a 3D label matrix.
Using ndimage.sum
I can get the labeled objects sizes, which is great for filtering based on volume.
My question is : can I easily get objects sizes along each axis, to eliminate those that are only in one plane, for instance ?
A little code might be clearer...
from scipy import ndimage
labmat,n = ndimage.label(np.random.rand(30,30,30) > 0.99)
sizes = ndimage.sum(labmat.astype(bool),labmat,range(n+1))
Now instead of a 1-dimensional representing the volumes of the labeled objects, is there a way to have 3D array representing their surfaces in each dimension ? A 30-D array representing their surfaces in each plane would also be OK, though I would prefer the first option.
You could use ndimage.find_objects
to find the bounding box for each label. The bounding box is given by a tuple of slices. For example,
data_slices = ndimage.find_objects(labmat)
# [(slice(0L, 1L, None), slice(4L, 5L, None), slice(28L, 29L, None)),
# (slice(0L, 1L, None), slice(25L, 26L, None), slice(19L, 20L, None)),
# (slice(0L, 1L, None), slice(27L, 28L, None), slice(10L, 11L, None)),
# (slice(0L, 1L, None), slice(28L, 29L, None), slice(7L, 8L, None)),
# ...
You could then find the size of each bounding box using
sizes = np.array([[s.stop-s.start for s in object_slice]
for object_slice in data_slices])
# array([[1, 1, 1],
# [1, 1, 1],
# [1, 1, 1],
# [1, 1, 1],
# ...
and create a boolean mask which is True for each box whose length is greater than 1 in all 3 dimensions:
mask = (sizes > 1).all(axis=1)
Use np.flatnonzero
to find the corresponding indices:
idx = np.flatnonzero(mask)
You can also use the slices to select the region of values from labmat
(or the original array). For example,
for i in idx:
print(labmat[data_slices[i]])
import numpy as np
from scipy import ndimage
np.random.seed(2016)
labmat, n = ndimage.label(np.random.rand(30,30,30) > 0.5)
data_slices = ndimage.find_objects(labmat)
sizes = np.array([[s.stop-s.start for s in object_slice]
for object_slice in data_slices])
mask = (sizes > 1).all(axis=1)
idx = np.flatnonzero(mask)
for i in idx:
print(labmat[data_slices[i]])