Skip to content

Commit d0eb96d

Browse files
committed
🔧 redo install to follow PEP517 standard
1 parent fcbe718 commit d0eb96d

12 files changed

+375
-352
lines changed

README.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,17 @@ Smith SM. Fast robust automated brain extraction. Hum Brain Mapp.
1313
To install, simply use `pip` to install this repo:
1414

1515
```
16+
# install from pypispheresphere
17+
pip install brainextractor
18+
1619
# install repo with pip
1720
pip install git+https://github.com/vanandrew/brainextractor@main
1821
1922
# install from local copy
2023
pip install /path/to/local/repo
2124
```
2225

23-
Note that is reccomended to use `brainextractor` on python 3.7+
26+
Note that it is recommended to use `brainextractor` on python 3.7+
2427

2528
## Usage
2629

brainextractor/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
from .main import BrainExtractor
1+
from .main import BrainExtractor

brainextractor/helpers.py

+59-104
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55
import trimesh
66
from numba import jit
77

8+
89
def sphere(shape: list, radius: float, position: list):
910
"""
10-
Creates a binary sphere
11+
Creates a binary sphere
1112
"""
1213
# assume shape and position are both a 3-tuple of int or float
1314
# the units are pixels / voxels (px for short)
@@ -30,90 +31,22 @@ def sphere(shape: list, radius: float, position: list):
3031
# the inner part of the sphere will have distance below 1
3132
return arr <= 1.0
3233

33-
def cartesian(arrays, out=None):
34-
"""
35-
Generate a cartesian product of input arrays
36-
"""
37-
arrays = [np.asarray(x) for x in arrays]
38-
dtype = arrays[0].dtype
39-
40-
n = np.prod([x.size for x in arrays])
41-
if out is None:
42-
out = np.zeros([n, len(arrays)], dtype=dtype)
43-
44-
m = int(n / arrays[0].size)
45-
out[:,0] = np.repeat(arrays[0], m)
46-
if arrays[1:]:
47-
cartesian(arrays[1:], out=out[0:m, 1:])
48-
for j in range(1, arrays[0].size):
49-
out[j*m:(j+1)*m, 1:] = out[0:m, 1:]
50-
return out
51-
52-
def find_enclosure(surface: trimesh.Trimesh, data_shape: tuple):
53-
"""
54-
Finds all voxels inside of a surface
55-
56-
This function stores all the surface vertices in a k-d tree
57-
and uses it to quickly look up the closest vertex to each
58-
volume voxel in the image.
59-
60-
Once the closest vertex is found, a vector is created between
61-
the voxel location and the vertex. The resulting vector is dot
62-
product with the corresponding vertex normal. Negative values
63-
indicate that the voxel lies exterior to the surface (since it
64-
is anti-parallel to the vertex normal), while positive values
65-
indicate that they are interior to the surface (parallel to
66-
the vertex normal).
67-
"""
68-
# get vertex normals for each vertex on the surface
69-
normals = surface.vertex_normals
70-
71-
# get KDTree over surface vertices
72-
searcher = surface.kdtree
73-
74-
# get bounding box around surface
75-
max_loc = np.ceil(np.max(surface.vertices, axis=0)).astype(np.int64)
76-
min_loc = np.floor(np.min(surface.vertices, axis=0)).astype(np.int64)
77-
78-
# build a list of locations representing the volume grid
79-
# within the bounding box
80-
locs = cartesian([
81-
np.arange(min_loc[0], max_loc[0]),
82-
np.arange(min_loc[1], max_loc[1]),
83-
np.arange(min_loc[2], max_loc[2])])
84-
85-
# find the nearest vertex to each voxel
86-
# searcher.query returns a list of vertices corresponding
87-
# to the closest vertex to the given voxel location
88-
_, nearest_idx = searcher.query(locs, n_jobs=6)
89-
nearest_vertices = surface.vertices[nearest_idx]
90-
91-
# get the directional vector from each voxel location to it's nearest vertex
92-
direction_vectors = nearest_vertices - locs
93-
94-
# find it's direction by taking the dot product with vertex normal
95-
# this is done row-by-row between directional vectors and the vertex normals
96-
dot_products = np.einsum('ij,ij->i', direction_vectors, normals[nearest_idx])
97-
98-
# get the interior (where dot product is > 0)
99-
interior = (dot_products > 0).reshape((max_loc - min_loc).astype(np.int64))
100-
101-
# create mask
102-
mask = np.zeros(data_shape)
103-
mask[min_loc[0]:max_loc[0],min_loc[1]:max_loc[1],min_loc[2]:max_loc[2]] = interior
104-
105-
# return the mask
106-
return mask
10734

10835
@jit(nopython=True, cache=True)
10936
def closest_integer_point(vertex: np.ndarray):
11037
"""
111-
Gives the closest integer point based on euclidean distance
38+
Gives the closest integer point based on euclidean distance
11239
"""
11340
# get neighboring grid points to search
114-
x = vertex[0]; y = vertex[1]; z = vertex[2]
115-
x0 = np.floor(x); y0 = np.floor(y); z0 = np.floor(z)
116-
x1 = x0 + 1; y1 = y0 + 1; z1 = z0 + 1
41+
x = vertex[0]
42+
y = vertex[1]
43+
z = vertex[2]
44+
x0 = np.floor(x)
45+
y0 = np.floor(y)
46+
z0 = np.floor(z)
47+
x1 = x0 + 1
48+
y1 = y0 + 1
49+
z1 = z0 + 1
11750

11851
# initialize min euclidean distance
11952
min_euclid = 99
@@ -132,12 +65,13 @@ def closest_integer_point(vertex: np.ndarray):
13265
# return the final coords
13366
return final_coords.astype(np.int64)
13467

68+
13569
@jit(nopython=True, cache=True)
13670
def bresenham3d(v0: np.ndarray, v1: np.ndarray):
13771
"""
138-
Bresenham's algorithm for a 3-D line
72+
Bresenham's algorithm for a 3-D line
13973
140-
https://www.geeksforgeeks.org/bresenhams-algorithm-for-3-d-line-drawing/
74+
https://www.geeksforgeeks.org/bresenhams-algorithm-for-3-d-line-drawing/
14175
"""
14276
# initialize axis differences
14377

@@ -150,32 +84,50 @@ def bresenham3d(v0: np.ndarray, v1: np.ndarray):
15084

15185
# determine the driving axis
15286
if dx >= dy and dx >= dz:
153-
d0 = dx; d1 = dy; d2 = dz
154-
s0 = xs; s1 = ys; s2 = zs
155-
a0 = 0; a1 = 1; a2 = 2
87+
d0 = dx
88+
d1 = dy
89+
d2 = dz
90+
s0 = xs
91+
s1 = ys
92+
s2 = zs
93+
a0 = 0
94+
a1 = 1
95+
a2 = 2
15696
elif dy >= dx and dy >= dz:
157-
d0 = dy; d1 = dx; d2 = dz
158-
s0 = ys; s1 = xs; s2 = zs
159-
a0 = 1; a1 = 0; a2 = 2
97+
d0 = dy
98+
d1 = dx
99+
d2 = dz
100+
s0 = ys
101+
s1 = xs
102+
s2 = zs
103+
a0 = 1
104+
a1 = 0
105+
a2 = 2
160106
elif dz >= dx and dz >= dy:
161-
d0 = dz; d1 = dx; d2 = dy
162-
s0 = zs; s1 = xs; s2 = ys
163-
a0 = 2; a1 = 0; a2 = 1
107+
d0 = dz
108+
d1 = dx
109+
d2 = dy
110+
s0 = zs
111+
s1 = xs
112+
s2 = ys
113+
a0 = 2
114+
a1 = 0
115+
a2 = 1
164116

165117
# create line array
166118
line = np.zeros((d0 + 1, 3), dtype=np.int64)
167119
line[0] = v0
168120

169121
# get points
170-
p1 = 2*d1 - d0
171-
p2 = 2*d2 - d0
122+
p1 = 2 * d1 - d0
123+
p2 = 2 * d2 - d0
172124
for i in range(d0):
173125
c = line[i].copy()
174126
c[a0] += s0
175-
if (p1 >= 0):
127+
if p1 >= 0:
176128
c[a1] += s1
177129
p1 -= 2 * d0
178-
if (p2 >= 0):
130+
if p2 >= 0:
179131
c[a2] += s2
180132
p2 -= 2 * d0
181133
p1 += 2 * d1
@@ -185,27 +137,30 @@ def bresenham3d(v0: np.ndarray, v1: np.ndarray):
185137
# return list
186138
return line
187139

140+
188141
@jit(nopython=True, cache=True)
189142
def l2norm(vec: np.ndarray):
190143
"""
191-
Computes the l2 norm for 3d vector
144+
Computes the l2 norm for 3d vector
192145
"""
193-
return np.sqrt(vec[0]**2 + vec[1]**2 + vec[2]**2)
146+
return np.sqrt(vec[0] ** 2 + vec[1] ** 2 + vec[2] ** 2)
147+
194148

195149
@jit(nopython=True, cache=True)
196150
def l2normarray(array: np.ndarray):
197151
"""
198-
Computes the l2 norm for several 3d vectors
152+
Computes the l2 norm for several 3d vectors
199153
"""
200-
return np.sqrt(array[:, 0]**2 + array[:, 1]**2 + array[:, 2]**2)
154+
return np.sqrt(array[:, 0] ** 2 + array[:, 1] ** 2 + array[:, 2] ** 2)
155+
201156

202157
def diagonal_dot(a: np.ndarray, b: np.ndarray):
203158
"""
204-
Dot product by row of a and b.
205-
There are a lot of ways to do this though
206-
performance varies very widely. This method
207-
uses a dot product to sum the row and avoids
208-
function calls if at all possible.
159+
Dot product by row of a and b.
160+
There are a lot of ways to do this though
161+
performance varies very widely. This method
162+
uses a dot product to sum the row and avoids
163+
function calls if at all possible.
209164
"""
210165
a = np.asanyarray(a)
211-
return np.dot(a * b, [1.0] * a.shape[1])
166+
return np.dot(a * b, [1.0] * a.shape[1])

0 commit comments

Comments
 (0)