dbdicom 0.2.1__py3-none-any.whl → 0.2.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of dbdicom might be problematic. Click here for more details.

Files changed (50) hide show
  1. dbdicom/__init__.py +4 -3
  2. dbdicom/create.py +34 -97
  3. dbdicom/dro.py +174 -0
  4. dbdicom/ds/dataset.py +29 -3
  5. dbdicom/ds/types/mr_image.py +18 -7
  6. dbdicom/extensions/__init__.py +10 -0
  7. dbdicom/{wrappers → extensions}/dipy.py +191 -205
  8. dbdicom/extensions/elastix.py +503 -0
  9. dbdicom/extensions/matplotlib.py +107 -0
  10. dbdicom/extensions/numpy.py +271 -0
  11. dbdicom/{wrappers → extensions}/scipy.py +130 -31
  12. dbdicom/{wrappers → extensions}/skimage.py +1 -1
  13. dbdicom/extensions/sklearn.py +243 -0
  14. dbdicom/extensions/vreg.py +1390 -0
  15. dbdicom/external/dcm4che/bin/emf2sf +57 -57
  16. dbdicom/manager.py +70 -36
  17. dbdicom/pipelines.py +66 -0
  18. dbdicom/record.py +266 -43
  19. dbdicom/types/instance.py +17 -3
  20. dbdicom/types/series.py +1900 -404
  21. dbdicom/utils/image.py +152 -21
  22. dbdicom/utils/vreg.py +327 -135
  23. dbdicom-0.2.3.dist-info/METADATA +88 -0
  24. {dbdicom-0.2.1.dist-info → dbdicom-0.2.3.dist-info}/RECORD +27 -41
  25. {dbdicom-0.2.1.dist-info → dbdicom-0.2.3.dist-info}/WHEEL +1 -1
  26. dbdicom/external/__pycache__/__init__.cpython-310.pyc +0 -0
  27. dbdicom/external/__pycache__/__init__.cpython-37.pyc +0 -0
  28. dbdicom/external/dcm4che/__pycache__/__init__.cpython-310.pyc +0 -0
  29. dbdicom/external/dcm4che/__pycache__/__init__.cpython-37.pyc +0 -0
  30. dbdicom/external/dcm4che/bin/__pycache__/__init__.cpython-310.pyc +0 -0
  31. dbdicom/external/dcm4che/bin/__pycache__/__init__.cpython-37.pyc +0 -0
  32. dbdicom/external/dcm4che/lib/linux-x86/libclib_jiio.so +0 -0
  33. dbdicom/external/dcm4che/lib/linux-x86-64/libclib_jiio.so +0 -0
  34. dbdicom/external/dcm4che/lib/linux-x86-64/libopencv_java.so +0 -0
  35. dbdicom/external/dcm4che/lib/solaris-sparc/libclib_jiio.so +0 -0
  36. dbdicom/external/dcm4che/lib/solaris-sparc/libclib_jiio_vis.so +0 -0
  37. dbdicom/external/dcm4che/lib/solaris-sparc/libclib_jiio_vis2.so +0 -0
  38. dbdicom/external/dcm4che/lib/solaris-sparcv9/libclib_jiio.so +0 -0
  39. dbdicom/external/dcm4che/lib/solaris-sparcv9/libclib_jiio_vis.so +0 -0
  40. dbdicom/external/dcm4che/lib/solaris-sparcv9/libclib_jiio_vis2.so +0 -0
  41. dbdicom/external/dcm4che/lib/solaris-x86/libclib_jiio.so +0 -0
  42. dbdicom/external/dcm4che/lib/solaris-x86-64/libclib_jiio.so +0 -0
  43. dbdicom/wrappers/__init__.py +0 -7
  44. dbdicom/wrappers/elastix.py +0 -855
  45. dbdicom/wrappers/numpy.py +0 -119
  46. dbdicom/wrappers/sklearn.py +0 -151
  47. dbdicom/wrappers/vreg.py +0 -273
  48. dbdicom-0.2.1.dist-info/METADATA +0 -276
  49. {dbdicom-0.2.1.dist-info → dbdicom-0.2.3.dist-info}/LICENSE +0 -0
  50. {dbdicom-0.2.1.dist-info → dbdicom-0.2.3.dist-info}/top_level.txt +0 -0
dbdicom/wrappers/numpy.py DELETED
@@ -1,119 +0,0 @@
1
- """
2
- Functions for a new (sub)package dbimage inside dbdicom
3
-
4
- A set of dbdicom wrappers for numpy
5
- """
6
-
7
- import numpy as np
8
-
9
-
10
- def mean_intensity_projection(series):
11
- """
12
- Segment by thresholding
13
-
14
- Parameters
15
- ----------
16
- series: dbdicom series (4D: slice + time)
17
-
18
- Returns
19
- -------
20
- mean : dbdicom series (3D)
21
-
22
- Example:
23
-
24
- mean_series = mean(series, axis=-1)
25
- """
26
- # Get numpy array with dimensions (slice, time, x, y)
27
- # array = series.array('SliceLocation')
28
-
29
- # Get numpy array with dimensions (x, y, slice, time)
30
- array, headers = series.array('SliceLocation', pixels_first=True)
31
- array = np.mean(array, axis=-1)
32
- desc = series.instance().SeriesDescription + ' [Mean Intensity Projection]'
33
- new_series = series.new_sibling(SeriesDescription=desc)
34
- new_series.set_array(array, headers[:,0], pixels_first=True)
35
- return new_series
36
-
37
-
38
- def maximum_intensity_projection(series):
39
- """
40
- Segment by thresholding
41
-
42
- Parameters
43
- ----------
44
- series: dbdicom series (4D: slice + time)
45
-
46
- Returns
47
- -------
48
- mean : dbdicom series (3D)
49
-
50
- Example:
51
-
52
- mean_series = mean(series, axis=-1)
53
- """
54
- # Get numpy array with dimensions (slice, time, x, y)
55
- # array = series.array('SliceLocation')
56
-
57
- # Get numpy array with dimensions (x, y, slice, time)
58
- array, headers = series.array('SliceLocation', pixels_first=True)
59
- array = np.amax(array, axis=-1)
60
- desc = series.instance().SeriesDescription + ' [Maximum Intensity Projection]'
61
- new_series = series.new_sibling(SeriesDescription=desc)
62
- new_series.set_array(array, headers[:,0], pixels_first=True)
63
- return new_series
64
-
65
- def norm_projection(series, ord=None):
66
- array, headers = series.array('SliceLocation', pixels_first=True)
67
- array = np.linalg.norm(array, ord=ord, axis=-1)
68
- desc = series.instance().SeriesDescription + ' [Norm projection]'
69
- new_series = series.new_sibling(SeriesDescription=desc)
70
- new_series.set_array(array, headers[:,0], pixels_first=True)
71
- return new_series
72
-
73
-
74
-
75
- def threshold(input, low_threshold=0, high_threshold=1, method='absolute'):
76
- """
77
- Segment by thresholding
78
-
79
- Parameters
80
- ----------
81
- input: dbdicom series
82
-
83
- Returns
84
- -------
85
- filtered : dbdicom series
86
- """
87
- suffix = ' [Threshold segmentation]'
88
- desc = input.instance().SeriesDescription
89
- filtered = input.copy(SeriesDescription = desc+suffix)
90
- #images = filtered.instances()
91
- images = filtered.images()
92
- for i, image in enumerate(images):
93
- input.status.progress(i+1, len(images), 'Filtering ' + desc)
94
- image.read()
95
- array = image.array()
96
- if method == 'quantiles':
97
- range = np.quantile(array, [low_threshold, high_threshold])
98
- elif method == 'range':
99
- min, max = np.amin(array), np.amax(array)
100
- range = [min+low_threshold*(max-min), min+high_threshold*(max-min)]
101
- else:
102
- range = [low_threshold, high_threshold]
103
- array = np.logical_and(array > range[0], array < range[1])
104
- image.set_array(array)
105
- array = array.astype(np.ubyte)
106
- _reset_window(image, array)
107
- image.clear()
108
- input.status.hide()
109
- return filtered
110
-
111
-
112
-
113
- # Helper functions
114
-
115
- def _reset_window(image, array):
116
- min = np.amin(array)
117
- max = np.amax(array)
118
- image.WindowCenter= (max+min)/2
119
- image.WindowWidth = 0.9*(max-min)
@@ -1,151 +0,0 @@
1
- import numpy as np
2
- from sklearn.cluster import KMeans
3
- import dbdicom.wrappers.scipy as scipy
4
-
5
-
6
- # https://scikit-learn.org/stable/modules/generated/sklearn.cluster.KMeans.html#sklearn.cluster.KMeans
7
- def kmeans(features, mask=None, n_clusters=2, multiple_series=False):
8
- """
9
- Labels structures in an image
10
-
11
- Wrapper for sklearn.cluster.KMeans function.
12
-
13
- Parameters
14
- ----------
15
- input: list of dbdicom series (one for each feature)
16
- mask: optional mask for clustering
17
-
18
- Returns
19
- -------
20
- clusters : list of dbdicom series, with labels per cluster.
21
- """
22
-
23
- # If a mask is provided, map it onto the reference feature and
24
- # extract the indices of all pixels under the mask
25
- if mask is not None:
26
- mask.status.message('Reading mask array..')
27
- mask = scipy.map_to(mask, features[0], mask=True)
28
- mask_array, _ = mask.array(['SliceLocation', 'AcquisitionTime'], pixels_first=True)
29
- mask_array = np.ravel(mask_array)
30
- mask_indices = tuple(mask_array.nonzero())
31
-
32
- # Ensure all the features are in the same geometry as the reference feature
33
- features = scipy.overlay(features)
34
-
35
- # Create array with shape (n_samples, n_features) and mask if needed.
36
- array = []
37
- for s, series in enumerate(features):
38
- series.status.progress(s+1, len(features), 'Reading features..')
39
- arr, headers = series.array(['SliceLocation', 'AcquisitionTime'], pixels_first=True)
40
- shape = arr.shape
41
- arr = np.ravel(arr)
42
- if mask is not None:
43
- arr = arr[mask_indices]
44
- array.append(arr)
45
- array = np.vstack(array).T
46
-
47
- # Perform the K-Means clustering.
48
- series.status.message('Clustering. Please be patient - this is hard work..')
49
- kmeans = KMeans(n_clusters=n_clusters, random_state=0, n_init=3, verbose=1).fit(array)
50
-
51
- # Create an output array for the labels
52
- if mask is not None:
53
- mask.status.message('Creating output array..')
54
- array = np.zeros(shape)
55
- array = np.ravel(array)
56
- array[mask_indices] = 1+kmeans.labels_
57
- else:
58
- array = 1+kmeans.labels_
59
- array = array.reshape(shape)
60
-
61
- # Save the results
62
- series.status.message('Saving clusters..')
63
- if multiple_series:
64
- # Save each cluster as a separate mask
65
- clusters = []
66
- for cluster in range(1,1+n_clusters):
67
- array_cluster = np.zeros(array.shape)
68
- array_cluster[array == cluster] = 1
69
- series_cluster = features[0].new_sibling(SeriesDescription = 'KMeans cluster ' + str(cluster))
70
- series_cluster.set_array(array_cluster, headers, pixels_first=True)
71
- _reset_window(series_cluster, array_cluster)
72
- clusters.append(series_cluster)
73
- else:
74
- # Save the label array in a single series
75
- clusters = features[0].new_sibling(SeriesDescription = 'KMeans')
76
- clusters.set_array(array, headers, pixels_first=True)
77
- _reset_window(clusters, array)
78
-
79
- return clusters
80
-
81
-
82
-
83
- def sequential_kmeans(features, mask=None, n_clusters=2, multiple_series=False):
84
- """
85
- Labels structures in an image using sequential k-means clustering
86
-
87
- Sequential here means that the clustering is always performed on a single feature
88
- using the output of the previous iteration as a mask for the next.
89
-
90
- Parameters
91
- ----------
92
- input: list of dbdicom series (one for each feature)
93
- mask: optional mask for clustering
94
-
95
- Returns
96
- -------
97
- clusters : list of dbdicom series, with labels per cluster.
98
- """
99
-
100
- f = features[0]
101
- clusters = kmeans([f], mask=mask, n_clusters=n_clusters, multiple_series=True)
102
- for f in features[1:]:
103
- cf = []
104
- for mask in clusters:
105
- cf += kmeans([f], mask=mask, n_clusters=n_clusters, multiple_series=True)
106
- mask.remove()
107
- clusters = cf
108
-
109
- # Return clusters as a list
110
- if multiple_series:
111
- return clusters
112
-
113
- # Return a single label series
114
- label = masks_to_label(clusters)
115
- for c in clusters:
116
- c.remove()
117
- return label
118
-
119
-
120
-
121
- def masks_to_label(masks):
122
- "Convert a list of masks into a single label series"
123
-
124
- # Ensure all the masks are in the same geometry
125
- masks = scipy.overlay(masks)
126
-
127
- # Create a single label array
128
- array, headers = masks[0].array(['SliceLocation', 'AcquisitionTime'], pixels_first=True)
129
- msg = 'Creating a single label image'
130
- for m, mask in enumerate(masks[1:]):
131
- mask.status.progress(m+1, len(masks)-1, msg)
132
- arr, _ = mask.array(['SliceLocation', 'AcquisitionTime'], pixels_first=True)
133
- ind = tuple(arr.nonzero())
134
- array[ind] = m+2
135
-
136
- # Save label array to disk
137
- desc = masks[0].SeriesDescription
138
- label = masks[0].new_sibling(SeriesDescription = desc + ' [Label]')
139
- label.set_array(array, headers, pixels_first=True)
140
-
141
- return label
142
-
143
-
144
-
145
- # Helper functions
146
-
147
- def _reset_window(image, array):
148
- min = np.amin(array)
149
- max = np.amax(array)
150
- image.WindowCenter= (max+min)/2
151
- image.WindowWidth = 0.9*(max-min)
dbdicom/wrappers/vreg.py DELETED
@@ -1,273 +0,0 @@
1
- import numpy as np
2
- from dbdicom.utils import vreg
3
-
4
- def print_current(vk):
5
- print(vk)
6
-
7
-
8
- def _get_input(moving, static):
9
-
10
- # Get affine matrices and check that there is a single value
11
- affine_moving = moving.affine_matrix()
12
- if isinstance(affine_moving, list):
13
- msg = 'This function only works for series with a single slice group. \n'
14
- msg += 'Multiple slice groups detected in moving series - please split the series first.'
15
- raise ValueError(msg)
16
- else:
17
- affine_moving = affine_moving[0]
18
- affine_static = static.affine_matrix()
19
- if isinstance(affine_static, list):
20
- msg = 'This function only works for series with a single slice group. \n'
21
- msg += 'Multiple slice groups detected in static series - please split the series first.'
22
- raise ValueError(msg)
23
- else:
24
- affine_static = affine_static[0]
25
-
26
- # Get arrays for static and moving series
27
- array_static, headers_static = static.array('SliceLocation', pixels_first=True, first_volume=True)
28
- if array_static is None:
29
- msg = 'Fixed series is empty - cannot perform alignment.'
30
- raise ValueError(msg)
31
- array_moving, headers_moving = moving.array('SliceLocation', pixels_first=True, first_volume=True)
32
- if array_moving is None:
33
- msg = 'Moving series is empty - cannot perform alignment.'
34
- raise ValueError(msg)
35
-
36
- moving.message('Performing coregistration. Please be patient. Its hard work and I need to concentrate..')
37
-
38
- return array_static, affine_static, array_moving, affine_moving, headers_static, headers_moving
39
-
40
-
41
-
42
-
43
-
44
- def translation_sos(moving, static, tolerance=0.1):
45
-
46
- array_static, affine_static, array_moving, affine_moving, headers, _ = _get_input(moving, static)
47
-
48
- # Define initial values and optimization
49
- _, _, static_pixel_spacing = vreg.affine_components(affine_static)
50
- optimization = {
51
- 'method': 'GD',
52
- 'options': {'gradient step': static_pixel_spacing, 'tolerance': tolerance},
53
- 'callback': lambda vk: moving.status.message('Current parameter: ' + str(vk)),
54
- }
55
-
56
- # Align volumes
57
- try:
58
- translation_estimate = vreg.align(
59
- moving = array_moving,
60
- moving_affine = affine_moving,
61
- static = array_static,
62
- static_affine = affine_static,
63
- parameters = np.array([0, 0, 0], dtype=np.float32),
64
- resolutions = [4,2,1],
65
- transformation = vreg.translate,
66
- metric = vreg.sum_of_squares,
67
- optimization = optimization,
68
- )
69
- except:
70
- print('Failed to align volumes..')
71
- return None
72
-
73
- coregistered = vreg.translate(array_moving, affine_moving, array_static.shape, affine_static, translation_estimate)
74
-
75
- # Save results as new dicom series
76
- moving.message('Writing coregistered series to database..')
77
- desc = moving.instance().SeriesDescription
78
- coreg = moving.new_sibling(SeriesDescription = desc + ' [translation]')
79
- coreg.set_array(coregistered, headers, pixels_first=True)
80
- return coreg
81
-
82
-
83
- def rigid_sos(moving, static, tolerance=0.1):
84
-
85
- array_static, affine_static, array_moving, affine_moving, headers, _ = _get_input(moving, static)
86
-
87
- # Define initial values and optimization
88
- _, _, static_pixel_spacing = vreg.affine_components(affine_static)
89
- rot_gradient_step, translation_gradient_step, _ = vreg.affine_resolution(array_static.shape, static_pixel_spacing)
90
- gradient_step = np.concatenate((1.0*rot_gradient_step, 0.5*translation_gradient_step))
91
- optimization = {
92
- 'method': 'GD',
93
- 'options': {'gradient step': gradient_step, 'tolerance': tolerance},
94
- 'callback': lambda vk: moving.message('Current parameter: ' + str(vk)),
95
- }
96
-
97
- # Align volumes
98
- try:
99
- rigid_estimate = vreg.align(
100
- moving = array_moving,
101
- moving_affine = affine_moving,
102
- static = array_static,
103
- static_affine = affine_static,
104
- parameters = np.array([0, 0, 0, 0, 0, 0], dtype=np.float32),
105
- resolutions = [4,2,1],
106
- transformation = vreg.rigid,
107
- metric = vreg.sum_of_squares,
108
- optimization = optimization,
109
- )
110
- except:
111
- print('Failed to align volumes..')
112
- return None
113
-
114
- coregistered = vreg.rigid(array_moving, affine_moving, array_static.shape, affine_static, rigid_estimate)
115
-
116
- moving.message('Writing coregistered series to database..')
117
-
118
- # Save results as new dicom series
119
- desc = moving.instance().SeriesDescription
120
- coreg = moving.new_sibling(SeriesDescription = desc + ' [rigid]')
121
- coreg.set_array(coregistered, headers, pixels_first=True)
122
- return coreg
123
-
124
-
125
-
126
- def sbs_translation_sos(moving, static, tolerance=0.1):
127
-
128
- array_static, affine_static, array_moving, affine_moving, headers, headers_moving = _get_input(moving, static)
129
- slice_thickness = [headers_moving[z].SliceThickness for z in range(headers_moving.size)]
130
-
131
- # Define initial values and optimization
132
- _, _, static_pixel_spacing = vreg.affine_components(affine_static)
133
- optimization = {
134
- 'method': 'GD',
135
- 'options': {'gradient step': static_pixel_spacing, 'tolerance': tolerance},
136
- # 'callback': lambda vk: moving.message('Current parameter: ' + str(vk)),
137
- }
138
-
139
- # Perform coregistration
140
- estimate = vreg.align_slice_by_slice(
141
- moving = array_moving,
142
- static = array_static,
143
- parameters = np.array([0, 0, 0], dtype=np.float32),
144
- moving_affine = affine_moving,
145
- static_affine = affine_static,
146
- transformation = vreg.translate,
147
- metric = vreg.sum_of_squares,
148
- optimization = optimization,
149
- resolutions = [4,2,1],
150
- slice_thickness = slice_thickness,
151
- progress = lambda z, nz: moving.progress(z, nz, 'Coregistering slice-by-slice using translations'),
152
- )
153
-
154
- # Calculate coregistered
155
- coregistered = vreg.transform_slice_by_slice(array_moving, affine_moving, array_static.shape, affine_static, estimate, vreg.translate, slice_thickness)
156
- # coregistered = vreg.transform_slice_by_slice(
157
- # moving = array_moving,
158
- # moving_affine = affine_moving,
159
- # static_shape = array_static.shape,
160
- # static_affine = affine_static,
161
- # parameters = estimate,
162
- # transformation = vreg.translate,
163
- # slice_thickness = slice_thickness)
164
-
165
- # Save results as new dicom series
166
- moving.message('Writing coregistered series to database..')
167
- desc = moving.instance().SeriesDescription
168
- coreg = moving.new_sibling(SeriesDescription = desc + ' [sbs translation]')
169
- coreg.set_array(coregistered, headers, pixels_first=True)
170
-
171
- return coreg
172
-
173
-
174
- def sbs_rigid_around_com_sos(moving, static, tolerance=0.1):
175
-
176
- array_static, affine_static, array_moving, affine_moving, headers, headers_moving = _get_input(moving, static)
177
- slice_thickness = [headers_moving[z].SliceThickness for z in range(headers_moving.size)]
178
-
179
- # Define initial values and optimization
180
- _, _, static_pixel_spacing = vreg.affine_components(affine_static)
181
- rot_gradient_step, translation_gradient_step, _ = vreg.affine_resolution(array_static.shape, static_pixel_spacing)
182
- gradient_step = np.concatenate((1.0*rot_gradient_step, 0.5*translation_gradient_step))
183
- optimization = {
184
- 'method': 'GD',
185
- 'options': {'gradient step': gradient_step, 'tolerance': tolerance},
186
- #'callback': lambda vk: moving.message('Current parameter: ' + str(vk)),
187
- }
188
-
189
- # Perform coregistration
190
- estimate = vreg.align_slice_by_slice(
191
- moving = array_moving,
192
- static = array_static,
193
- parameters = np.array([0, 0, 0, 0, 0, 0], dtype=np.float32),
194
- moving_affine = affine_moving,
195
- static_affine = affine_static,
196
- transformation = vreg.rigid_around_com,
197
- metric = vreg.sum_of_squares,
198
- optimization = optimization,
199
- resolutions = [4,2,1],
200
- slice_thickness = slice_thickness,
201
- progress = lambda z, nz: moving.progress(z, nz, 'Coregistering slice-by-slice using rigid transformations'),
202
- )
203
-
204
- # The generic slice-by-slice transform does not work for center of mass rotations.
205
- # Calculate rotation center and use rigid rotation around given center instead.
206
- estimate_center = []
207
- for z in range(len(estimate)):
208
- array_moving_z, affine_moving_z = vreg.extract_slice(array_moving, affine_moving, z, slice_thickness)
209
- center = estimate[z][3:] + vreg.center_of_mass(vreg.to_3d(array_moving_z), affine_moving_z)
210
- pars = np.concatenate((estimate[z][:3], center, estimate[z][3:]))
211
- estimate_center.append(pars)
212
-
213
- # Calculate coregistered (using rigid around known center)
214
- coregistered = vreg.transform_slice_by_slice(array_moving, affine_moving, array_static.shape, affine_static, estimate_center, vreg.rigid_around, slice_thickness)
215
- # coregistered = vreg.transform_slice_by_slice(
216
- # moving = array_moving,
217
- # moving_affine = affine_moving,
218
- # static_shape = array_static.shape,
219
- # static_affine = affine_static,
220
- # parameters = estimate_center,
221
- # transformation = vreg.rigid_around,
222
- # slice_thickness = slice_thickness)
223
-
224
- # Save results as new dicom series
225
- moving.message('Writing coregistered series to database..')
226
- desc = moving.instance().SeriesDescription
227
- coreg = moving.new_sibling(SeriesDescription = desc + ' [sbs rigid com]')
228
- coreg.set_array(coregistered, headers, pixels_first=True)
229
-
230
- return coreg
231
-
232
-
233
-
234
- def rigid_around_com_sos(moving, static, tolerance=0.1):
235
-
236
- array_static, affine_static, array_moving, affine_moving, headers, _ = _get_input(moving, static)
237
-
238
- # Define initial values and optimization
239
- _, _, static_pixel_spacing = vreg.affine_components(affine_static)
240
- rot_gradient_step, translation_gradient_step, _ = vreg.affine_resolution(array_static.shape, static_pixel_spacing)
241
- gradient_step = np.concatenate((1.0*rot_gradient_step, 0.5*translation_gradient_step))
242
- optimization = {
243
- 'method': 'GD',
244
- 'options': {'gradient step': gradient_step, 'tolerance': tolerance},
245
- 'callback': lambda vk: moving.message('Current parameter: ' + str(vk)),
246
- }
247
-
248
- # Align volumes
249
- try:
250
- rigid_estimate = vreg.align(
251
- moving = array_moving,
252
- moving_affine = affine_moving,
253
- static = array_static,
254
- static_affine = affine_static,
255
- parameters = np.array([0, 0, 0, 0, 0, 0], dtype=np.float32),
256
- resolutions = [4,2,1],
257
- transformation = vreg.rigid_around_com,
258
- metric = vreg.sum_of_squares,
259
- optimization = optimization,
260
- )
261
- except:
262
- print('Failed to align volumes..')
263
- return None
264
-
265
- coregistered = vreg.rigid_around_com(array_moving, affine_moving, array_static.shape, affine_static, rigid_estimate)
266
-
267
- moving.message('Writing coregistered series to database..')
268
-
269
- # Save results as new dicom series
270
- desc = moving.instance().SeriesDescription
271
- coreg = moving.new_sibling(SeriesDescription = desc + ' [rigid com]')
272
- coreg.set_array(coregistered, headers, pixels_first=True)
273
- return coreg