|
a |
|
b/ants/math/get_neighborhood.py |
|
|
1 |
|
|
|
2 |
__all__ = ['get_neighborhood_in_mask', |
|
|
3 |
'get_neighborhood_at_voxel'] |
|
|
4 |
|
|
|
5 |
import numpy as np |
|
|
6 |
|
|
|
7 |
import ants |
|
|
8 |
|
|
|
9 |
from ants.internal import get_lib_fn |
|
|
10 |
from ants.decorators import image_method |
|
|
11 |
|
|
|
12 |
@image_method |
|
|
13 |
def get_neighborhood_in_mask(image, mask, radius, physical_coordinates=False, |
|
|
14 |
boundary_condition=None, spatial_info=False, get_gradient=False): |
|
|
15 |
""" |
|
|
16 |
Get neighborhoods for voxels within mask. |
|
|
17 |
|
|
|
18 |
This converts a scalar image to a matrix with rows that contain neighbors |
|
|
19 |
around a center voxel |
|
|
20 |
|
|
|
21 |
ANTsR function: `getNeighborhoodInMask` |
|
|
22 |
|
|
|
23 |
Arguments |
|
|
24 |
--------- |
|
|
25 |
image : ANTsImage |
|
|
26 |
image to get values from |
|
|
27 |
|
|
|
28 |
mask : ANTsImage |
|
|
29 |
image indicating which voxels to examine. Each voxel > 0 will be used as the |
|
|
30 |
center of a neighborhood |
|
|
31 |
|
|
|
32 |
radius : tuple/list |
|
|
33 |
array of values for neighborhood radius (in voxels) |
|
|
34 |
|
|
|
35 |
physical_coordinates : boolean |
|
|
36 |
whether voxel indices and offsets should be in voxel or physical coordinates |
|
|
37 |
|
|
|
38 |
boundary_condition : string (optional) |
|
|
39 |
how to handle voxels in a neighborhood, but not in the mask. |
|
|
40 |
None : fill values with `NaN` |
|
|
41 |
`image` : use image value, even if not in mask |
|
|
42 |
`mean` : use mean of all non-NaN values for that neighborhood |
|
|
43 |
|
|
|
44 |
spatial_info : boolean |
|
|
45 |
whether voxel locations and neighborhood offsets should be returned along with pixel values. |
|
|
46 |
|
|
|
47 |
get_gradient : boolean |
|
|
48 |
whether a matrix of gradients (at the center voxel) should be returned in |
|
|
49 |
addition to the value matrix (WIP) |
|
|
50 |
|
|
|
51 |
Returns |
|
|
52 |
------- |
|
|
53 |
if spatial_info is False: |
|
|
54 |
if get_gradient is False: |
|
|
55 |
ndarray |
|
|
56 |
an array of pixel values where the number of rows is the size of the |
|
|
57 |
neighborhood and there is a column for each voxel |
|
|
58 |
|
|
|
59 |
else if get_gradient is True: |
|
|
60 |
dictionary w/ following key-value pairs: |
|
|
61 |
values : ndarray |
|
|
62 |
array of pixel values where the number of rows is the size of the |
|
|
63 |
neighborhood and there is a column for each voxel. |
|
|
64 |
|
|
|
65 |
gradients : ndarray |
|
|
66 |
array providing the gradients at the center voxel of each |
|
|
67 |
neighborhood |
|
|
68 |
|
|
|
69 |
else if spatial_info is True: |
|
|
70 |
dictionary w/ following key-value pairs: |
|
|
71 |
values : ndarray |
|
|
72 |
array of pixel values where the number of rows is the size of the |
|
|
73 |
neighborhood and there is a column for each voxel. |
|
|
74 |
|
|
|
75 |
indices : ndarray |
|
|
76 |
array provinding the center coordinates for each neighborhood |
|
|
77 |
|
|
|
78 |
offsets : ndarray |
|
|
79 |
array providing the offsets from center for each voxel in a neighborhood |
|
|
80 |
|
|
|
81 |
Example |
|
|
82 |
------- |
|
|
83 |
>>> import ants |
|
|
84 |
>>> r16 = ants.image_read(ants.get_ants_data('r16')) |
|
|
85 |
>>> mask = ants.get_mask(r16) |
|
|
86 |
>>> mat = ants.get_neighborhood_in_mask(r16, mask, radius=(2,2)) |
|
|
87 |
""" |
|
|
88 |
if not ants.is_image(image): |
|
|
89 |
raise ValueError('image must be ANTsImage type') |
|
|
90 |
if not ants.is_image(mask): |
|
|
91 |
raise ValueError('mask must be ANTsImage type') |
|
|
92 |
if isinstance(radius, (int, float)): |
|
|
93 |
radius = [radius]*image.dimension |
|
|
94 |
if (not isinstance(radius, (tuple,list))) or (len(radius) != image.dimension): |
|
|
95 |
raise ValueError('radius must be tuple or list with length == image.dimension') |
|
|
96 |
|
|
|
97 |
boundary = 0 |
|
|
98 |
if boundary_condition == 'image': |
|
|
99 |
boundary = 1 |
|
|
100 |
elif boundary_condition == 'mean': |
|
|
101 |
boundary = 2 |
|
|
102 |
|
|
|
103 |
libfn = get_lib_fn('getNeighborhoodMatrix%s' % image._libsuffix) |
|
|
104 |
retvals = libfn(image.pointer, |
|
|
105 |
mask.pointer, |
|
|
106 |
list(radius), |
|
|
107 |
int(physical_coordinates), |
|
|
108 |
int(boundary), |
|
|
109 |
int(spatial_info), |
|
|
110 |
int(get_gradient)) |
|
|
111 |
|
|
|
112 |
if not spatial_info: |
|
|
113 |
if get_gradient: |
|
|
114 |
retvals['values'] = np.asarray(retvals['values']) |
|
|
115 |
retvals['gradients'] = np.asarray(retvals['gradients']) |
|
|
116 |
else: |
|
|
117 |
retvals = np.asarray(retvals['matrix']) |
|
|
118 |
else: |
|
|
119 |
retvals['values'] = np.asarray(retvals['values']) |
|
|
120 |
retvals['indices'] = np.asarray(retvals['indices']) |
|
|
121 |
retvals['offsets'] = np.asarray(retvals['offsets']) |
|
|
122 |
|
|
|
123 |
return retvals |
|
|
124 |
|
|
|
125 |
@image_method |
|
|
126 |
def get_neighborhood_at_voxel(image, center, kernel, physical_coordinates=False): |
|
|
127 |
""" |
|
|
128 |
Get a hypercube neighborhood at a voxel. Get the values in a local |
|
|
129 |
neighborhood of an image. |
|
|
130 |
|
|
|
131 |
ANTsR function: `getNeighborhoodAtVoxel` |
|
|
132 |
|
|
|
133 |
Arguments |
|
|
134 |
--------- |
|
|
135 |
image : ANTsImage |
|
|
136 |
image to get values from. |
|
|
137 |
|
|
|
138 |
center : tuple/list |
|
|
139 |
indices for neighborhood center |
|
|
140 |
|
|
|
141 |
kernel : tuple/list |
|
|
142 |
either a collection of values for neighborhood radius (in voxels) or |
|
|
143 |
a binary collection of the same dimension as the image, specifying the shape of the neighborhood to extract |
|
|
144 |
|
|
|
145 |
physical_coordinates : boolean |
|
|
146 |
whether voxel indices and offsets should be in voxel |
|
|
147 |
or physical coordinates |
|
|
148 |
|
|
|
149 |
Returns |
|
|
150 |
------- |
|
|
151 |
dictionary w/ following key-value pairs: |
|
|
152 |
values : ndarray |
|
|
153 |
array of neighborhood values at the voxel |
|
|
154 |
|
|
|
155 |
indices : ndarray |
|
|
156 |
matrix providing the coordinates for each value |
|
|
157 |
|
|
|
158 |
Example |
|
|
159 |
------- |
|
|
160 |
>>> import ants |
|
|
161 |
>>> img = ants.image_read(ants.get_ants_data('r16')) |
|
|
162 |
>>> center = (2,2) |
|
|
163 |
>>> radius = (3,3) |
|
|
164 |
>>> retval = ants.get_neighborhood_at_voxel(img, center, radius) |
|
|
165 |
""" |
|
|
166 |
if not ants.is_image(image): |
|
|
167 |
raise ValueError('image must be ANTsImage type') |
|
|
168 |
|
|
|
169 |
if (not isinstance(center, (tuple,list))) or (len(center) != image.dimension): |
|
|
170 |
raise ValueError('center must be tuple or list with length == image.dimension') |
|
|
171 |
|
|
|
172 |
if (not isinstance(kernel, (tuple,list))) or (len(kernel) != image.dimension): |
|
|
173 |
raise ValueError('kernel must be tuple or list with length == image.dimension') |
|
|
174 |
|
|
|
175 |
radius = [int((k-1)/2) for k in kernel] |
|
|
176 |
|
|
|
177 |
libfn = get_lib_fn('getNeighborhood%s' % image._libsuffix) |
|
|
178 |
retvals = libfn(image.pointer, |
|
|
179 |
list(center), |
|
|
180 |
list(kernel), |
|
|
181 |
list(radius), |
|
|
182 |
int(physical_coordinates)) |
|
|
183 |
for k in retvals.keys(): |
|
|
184 |
retvals[k] = np.asarray(retvals[k]) |
|
|
185 |
return retvals |
|
|
186 |
|
|
|
187 |
|