Switch to unified view

a b/ants/utils/matrix_image.py
1
2
__all__ = [
3
    "matrix_to_images",
4
    "images_from_matrix",
5
    "image_list_to_matrix",
6
    "images_to_matrix",
7
    "matrix_from_images",
8
    "timeseries_to_matrix",
9
    "matrix_to_timeseries"
10
]
11
12
import os
13
import json
14
import numpy as np
15
import warnings
16
17
import ants
18
from ants.decorators import image_method
19
20
@image_method
21
def matrix_to_timeseries(image, matrix, mask=None):
22
    """
23
    converts a matrix to a ND image.
24
25
    ANTsR function: `matrix2timeseries`
26
27
    Arguments
28
    ---------
29
30
    image: reference ND image
31
32
    matrix: matrix to convert to image
33
34
    mask: mask image defining voxels of interest
35
36
37
    Returns
38
    -------
39
    ANTsImage
40
41
    Example
42
    -------
43
    >>> import ants
44
    >>> img = ants.make_image( (10,10,10,5 ) )
45
    >>> mask = ants.ndimage_to_list( img )[0] * 0
46
    >>> mask[ 4:8, 4:8, 4:8 ] = 1
47
    >>> mat = ants.timeseries_to_matrix( img, mask = mask )
48
    >>> img2 = ants.matrix_to_timeseries( img,  mat, mask)
49
    """
50
51
    if mask is None:
52
        mask = temp[0] * 0 + 1
53
    temp = matrix_to_images(matrix, mask)
54
    newImage = ants.list_to_ndimage(image, temp)
55
    ants.copy_image_info(image, newImage)
56
    return newImage
57
58
59
def matrix_to_images(data_matrix, mask):
60
    """
61
    Unmasks rows of a matrix and writes as images
62
63
    ANTsR function: `matrixToImages`
64
65
    Arguments
66
    ---------
67
    data_matrix : numpy.ndarray
68
        each row corresponds to an image
69
        array should have number of columns equal to non-zero voxels in the mask
70
71
    mask : ANTsImage
72
        image containing a binary mask. Rows of the matrix are
73
        unmasked and written as images. The mask defines the output image space
74
75
    Returns
76
    -------
77
    list of ANTsImage types
78
79
    Example
80
    -------
81
    >>> import ants
82
    >>> img = ants.image_read(ants.get_ants_data('r16'))
83
    >>> msk = ants.get_mask( img )
84
    >>> img2 = ants.image_read(ants.get_ants_data('r16'))
85
    >>> img3 = ants.image_read(ants.get_ants_data('r16'))
86
    >>> mat = ants.image_list_to_matrix([img,img2,img3], msk )
87
    >>> ilist = ants.matrix_to_images( mat, msk )
88
    """
89
90
    if data_matrix.ndim > 2:
91
        data_matrix = data_matrix.reshape(data_matrix.shape[0], -1)
92
93
    numimages = len(data_matrix)
94
    numVoxelsInMatrix = data_matrix.shape[1]
95
    numVoxelsInMask = (mask >= 0.5).sum()
96
    if numVoxelsInMask != numVoxelsInMatrix:
97
        raise ValueError(
98
            "Num masked voxels %i must match data matrix %i"
99
            % (numVoxelsInMask, numVoxelsInMatrix)
100
        )
101
102
    imagelist = []
103
    for i in range(numimages):
104
        img = mask.clone()
105
        img[mask >= 0.5] = data_matrix[i, :]
106
        imagelist.append(img)
107
    return imagelist
108
109
110
images_from_matrix = matrix_to_images
111
112
113
def images_to_matrix(image_list, mask=None, sigma=None, epsilon=0.5):
114
    """
115
    Read images into rows of a matrix, given a mask - much faster for
116
    large datasets as it is based on C++ implementations.
117
118
    ANTsR function: `imagesToMatrix`
119
120
    Arguments
121
    ---------
122
    image_list : list of ANTsImage types
123
        images to convert to ndarray
124
125
    mask : ANTsImage (optional)
126
        Mask image, voxels in the mask (>= epsilon) are placed in the matrix. If None,
127
        the first image in image_list is thresholded at its mean value to create a mask.
128
129
    sigma : scaler (optional)
130
        smoothing factor
131
132
    epsilon : scalar
133
        threshold for mask, values >= epsilon are included in the mask.
134
135
    Returns
136
    -------
137
    ndarray
138
        array with a row for each image
139
        shape = (N_IMAGES, N_VOXELS)
140
141
    Example
142
    -------
143
    >>> import ants
144
    >>> img = ants.image_read(ants.get_ants_data('r16'))
145
    >>> img2 = ants.image_read(ants.get_ants_data('r16'))
146
    >>> img3 = ants.image_read(ants.get_ants_data('r16'))
147
    >>> mat = ants.image_list_to_matrix([img,img2,img3])
148
    """
149
    if mask is None:
150
        mask = ants.get_mask(image_list[0])
151
152
    num_images = len(image_list)
153
    mask_thresh = mask.clone() >= epsilon
154
    mask_arr = mask.numpy() >= epsilon
155
    num_voxels = np.sum(mask_arr)
156
157
    data_matrix = np.empty((num_images, num_voxels))
158
    do_smooth = sigma is not None
159
    for i, img in enumerate(image_list):
160
        if do_smooth:
161
            img = ants.smooth_image(img, sigma, sigma_in_physical_coordinates=True)
162
        if np.sum(np.array(img.shape) - np.array(mask_thresh.shape)) != 0:
163
            img = ants.resample_image_to_target(img, mask_thresh, 2)
164
        data_matrix[i, :] = img[mask_thresh]
165
    return data_matrix
166
167
168
image_list_to_matrix = images_to_matrix
169
matrix_from_images = images_to_matrix
170
171
@image_method
172
def timeseries_to_matrix(image, mask=None):
173
    """
174
    Convert a timeseries image into a matrix.
175
176
    ANTsR function: `timeseries2matrix`
177
178
    Arguments
179
    ---------
180
    image : image whose slices we convert to a matrix. E.g. a 3D image of size
181
           x by y by z will convert to a z by x*y sized matrix
182
183
    mask : ANTsImage (optional)
184
        image containing binary mask. voxels in the mask are placed in the matrix
185
186
    Returns
187
    -------
188
    ndarray
189
        array with a row for each image
190
        shape = (N_IMAGES, N_VOXELS)
191
192
    Example
193
    -------
194
    >>> import ants
195
    >>> img = ants.make_image( (10,10,10,5 ) )
196
    >>> mat = ants.timeseries_to_matrix( img )
197
    """
198
    temp = ants.ndimage_to_list(image)
199
    if mask is None:
200
        mask = temp[0] * 0 + 1
201
    return image_list_to_matrix(temp, mask)
202