Switch to unified view

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))