@@ -282,6 +282,79 @@ 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
+
304
+ However, unused data did not need to be loaded into memory or scaled.
305
+ Additionally, the image affine was adjusted so that the X-translation is
306
+ 32 voxels (64mm) less:
307
+
308
+ >>> cropped_img.affine
309
+ array([[ -2. , 0. , 0. , 53.86],
310
+ [ -0. , 1.97, -0.36, -35.72],
311
+ [ 0. , 0.32, 2.17, -7.25],
312
+ [ 0. , 0. , 0. , 1. ]])
313
+
314
+ >>> img.affine - cropped_img.affine
315
+ array([[ 0., 0., 0., 64.],
316
+ [ 0., 0., 0., 0.],
317
+ [ 0., 0., 0., 0.],
318
+ [ 0., 0., 0., 0.]])
319
+
320
+ Another use for the slicer object is to choose specific volumes from a
321
+ time series:
322
+
323
+ >>> vol0 = img.slicer[... , 0 ]
324
+ >>> vol0.shape
325
+ (128, 96, 24)
326
+
327
+ Or a selection of volumes:
328
+
329
+ >>> img.slicer[... , :1 ].shape
330
+ (128, 96, 24, 1)
331
+ >>> img.slicer[... , :2 ].shape
332
+ (128, 96, 24, 2)
333
+
334
+ It is also possible to use an integer step when slicing, downsampling
335
+ the image without filtering.
336
+ Note that this *will induce artifacts * in the frequency spectrum
337
+ (`aliasing <wikipedia aliasing >`_) along any axis that is down-sampled.
338
+
339
+ >>> downsampled = vol0.slicer[::2 , ::2 , ::2 ]
340
+ >>> downsampled.header.get_zooms()
341
+ (4.0, 4.0, 4.399998)
342
+
343
+ Finally, an image can be flipped along an axis, maintaining an appropriate
344
+ affine matrix:
345
+
346
+ >>> nib.orientations.aff2axcodes(img.affine)
347
+ ('L', 'A', 'S')
348
+ >>> ras = img.slicer[::- 1 ]
349
+ >>> nib.orientations.aff2axcodes(ras.affine)
350
+ ('R', 'A', 'S')
351
+ >>> ras.affine
352
+ array([[ 2. , 0. , 0. , 117.86],
353
+ [ 0. , 1.97, -0.36, -35.72],
354
+ [ -0. , 0.32, 2.17, -7.25],
355
+ [ 0. , 0. , 0. , 1. ]])
356
+
357
+
285
358
******************
286
359
Loading and saving
287
360
******************
0 commit comments