|
a |
|
b/CLI/MusculoskeletalAnalysisCLITools/thickness.py |
|
|
1 |
def findSpheres(mask): |
|
|
2 |
"""Calculates thickness by finding the largest sphere containing each point.""" |
|
|
3 |
import numpy as np |
|
|
4 |
from math import floor |
|
|
5 |
from scipy.ndimage import distance_transform_edt |
|
|
6 |
|
|
|
7 |
dist = distance_transform_edt(mask) |
|
|
8 |
rads = dist.copy() |
|
|
9 |
|
|
|
10 |
a,b,c=np.nonzero(mask) |
|
|
11 |
order = np.argsort(dist[a,b,c]) |
|
|
12 |
for n in order: |
|
|
13 |
# For each point, find the thickness radius at that point from the distance map |
|
|
14 |
x=a[n] |
|
|
15 |
y=b[n] |
|
|
16 |
z=c[n] |
|
|
17 |
|
|
|
18 |
r=dist[x,y,z] |
|
|
19 |
rf = floor(r) |
|
|
20 |
# Check that ranges are inside boundaries |
|
|
21 |
xr0=min(rf,x) |
|
|
22 |
xr1=min(rf, dist.shape[0]-x-1) |
|
|
23 |
yr0=min(rf,y) |
|
|
24 |
yr1=min(rf, dist.shape[1]-y-1) |
|
|
25 |
zr0=min(rf,z) |
|
|
26 |
zr1=min(rf, dist.shape[2]-z-1) |
|
|
27 |
# Creates a cubic view of the region of interest |
|
|
28 |
roi=rads[x-xr0:x+xr1+1, y-yr0:y+yr1+1, z-zr0:z+zr1+1] |
|
|
29 |
# Creates mask of sphere within radius |
|
|
30 |
i,j,k=np.mgrid[-xr0:xr1+1,-yr0:yr1+1,-zr0:zr1+1] |
|
|
31 |
mask = approxLTE(i**2 + j**2 + k**2, np.full_like(roi, r**2)) |
|
|
32 |
mask = np.bitwise_and(mask, roi>0) |
|
|
33 |
# Sets all values inside region of interest and sphere mask to the radius if it is higher than their current value |
|
|
34 |
mask = mask * r |
|
|
35 |
roi[:,:,:] = np.maximum(roi, mask) |
|
|
36 |
return rads[np.nonzero(rads)] |
|
|
37 |
|
|
|
38 |
def approxLTE(a, b): |
|
|
39 |
# Peforms array elementwise less than or equal comparisons with some tolerance for floating point values |
|
|
40 |
import numpy as np |
|
|
41 |
return np.bitwise_or(a <= b, np.isclose(a,b)) |