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