-
Notifications
You must be signed in to change notification settings - Fork 9
/
mask.py
103 lines (89 loc) · 3.1 KB
/
mask.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import numpy as np
import numpy.typing as npt
from typing import Optional
def spherical_mask(
box_size: int,
radius: float,
smooth: Optional[float] = None,
cutoff_sd: int = 3,
center: Optional[float] = None,
) -> npt.NDArray[float]:
"""Wrapper around ellipsoidal_mask() to create a spherical mask with just a single radius.
Parameters
----------
box_size: int
box size of the mask, equal in each dimension
radius: float
radius of sphere
smooth: Optional[float], default None
sigma (float relative to number of pixels) of gaussian falloff around mask
cutoff_sd: int, default 3
how many standard deviations of the Gaussian falloff to include, default of 3 is a good choice
center: Optional[float], default None
alternative center for the mask, default is (size - 1) / 2
Returns
-------
mask: npt.NDArray[float]
3D numpy array with mask at center
"""
return ellipsoidal_mask(
box_size, radius, radius, radius, smooth, cutoff_sd=cutoff_sd, center=center
)
def ellipsoidal_mask(
box_size: int,
major: float,
minor1: float,
minor2: float,
smooth: Optional[float] = None,
cutoff_sd: int = 3,
center: Optional[float] = None,
) -> npt.NDArray[float]:
"""Create an ellipsoidal mask in the specified square box. Ellipsoid is defined by 3 radius on x,y, and z axis.
Parameters
----------
box_size: int
box size of the mask, equal in each dimension
major: float
radius of ellipsoid in x
minor1: float
radius of ellipsoid in y
minor2: float
radius of ellipsoid in z
smooth: Optional[float], default None
sigma (float relative to number of pixels) of gaussian falloff around mask
cutoff_sd: int, default 3
how many standard deviations of the Gaussian falloff to include, default of 3 is a good choice
center: Optional[float], default None
alternative center for the mask, default is (size - 1) / 2
Returns
-------
mask: npt.NDArray[float]
3D numpy array with mask at center
"""
if not all([box_size > 0, major > 0, minor1 > 0, minor2 > 0]):
raise ValueError("Invalid input for mask creation: box_size or radii are <= 0")
center = (box_size - 1) / 2 if center is None else center
x, y, z = (
np.arange(box_size) - center,
np.arange(box_size) - center,
np.arange(box_size) - center,
)
# use broadcasting
r = np.sqrt(
((x / major) ** 2)[:, np.newaxis, np.newaxis]
+ ((y / minor1) ** 2)[:, np.newaxis]
+ (z / minor2) ** 2
).astype(np.float32)
if smooth is not None:
if not all([smooth >= 0, cutoff_sd >= 0]):
raise ValueError(
"Invalid input for mask smoothing: smooth or sd cutoff are <= 0"
)
r[r <= 1] = 1
sigma = smooth / ((major + minor1 + minor2) / 3)
mask = np.exp(-1 * ((r - 1) / sigma) ** 2)
mask[mask <= np.exp(-(cutoff_sd**2) / 2.0)] = 0
else:
mask = np.zeros_like(r)
mask[r <= 1] = 1.0
return mask