@@ -282,6 +282,80 @@ True
282
282
See :doc: `images_and_memory ` for more details on managing image memory and
283
283
controlling the image cache.
284
284
285
+ .. _image-slicing :
286
+
287
+ Image slicing
288
+ =============
289
+
290
+ At times it is useful to manipulate an image's shape while keeping it in the
291
+ same coordinate system.
292
+ The ``slicer `` attribute provides an array-slicing interface to produce new
293
+ images with an appropriately adjusted header, such that the data at a given
294
+ RAS+ location is unchanged.
295
+
296
+ >>> cropped_img = img.slicer[32 :- 32 , ... ]
297
+ >>> cropped_img.shape
298
+ (64, 96, 24, 2)
299
+
300
+ The data is identical to cropping the data block directly:
301
+
302
+ >>> np.array_equal(cropped_img.get_fdata(), img.get_fdata()[32 :- 32 , ... ])
303
+ True
304
+
305
+ However, unused data did not need to be loaded into memory or scaled.
306
+ Additionally, the image affine was adjusted so that the X-translation is
307
+ 32 voxels (64mm) less:
308
+
309
+ >>> cropped_img.affine
310
+ array([[ -2. , 0. , 0. , 53.86],
311
+ [ -0. , 1.97, -0.36, -35.72],
312
+ [ 0. , 0.32, 2.17, -7.25],
313
+ [ 0. , 0. , 0. , 1. ]])
314
+
315
+ >>> img.affine - cropped_img.affine
316
+ array([[ 0., 0., 0., 64.],
317
+ [ 0., 0., 0., 0.],
318
+ [ 0., 0., 0., 0.],
319
+ [ 0., 0., 0., 0.]])
320
+
321
+ Another use for the slicer object is to choose specific volumes from a
322
+ time series:
323
+
324
+ >>> vol0 = img.slicer[... , 0 ]
325
+ >>> vol0.shape
326
+ (128, 96, 24)
327
+
328
+ Or a selection of volumes:
329
+
330
+ >>> img.slicer[... , :1 ].shape
331
+ (128, 96, 24, 1)
332
+ >>> img.slicer[... , :2 ].shape
333
+ (128, 96, 24, 2)
334
+
335
+ It is also possible to use an integer step when slicing, downsampling
336
+ the image without filtering.
337
+ Note that this *will induce artifacts * in the frequency spectrum
338
+ (`aliasing <wikipedia aliasing >`_) along any axis that is down-sampled.
339
+
340
+ >>> downsampled = vol0.slicer[::2 , ::2 , ::2 ]
341
+ >>> downsampled.header.get_zooms()
342
+ (4.0, 4.0, 4.399998)
343
+
344
+ Finally, an image can be flipped along an axis, maintaining an appropriate
345
+ affine matrix:
346
+
347
+ >>> nib.orientations.aff2axcodes(img.affine)
348
+ ('L', 'A', 'S')
349
+ >>> ras = img.slicer[::- 1 ]
350
+ >>> nib.orientations.aff2axcodes(ras.affine)
351
+ ('R', 'A', 'S')
352
+ >>> ras.affine
353
+ array([[ 2. , 0. , 0. , 117.86],
354
+ [ 0. , 1.97, -0.36, -35.72],
355
+ [ -0. , 0.32, 2.17, -7.25],
356
+ [ 0. , 0. , 0. , 1. ]])
357
+
358
+
285
359
******************
286
360
Loading and saving
287
361
******************
0 commit comments