@@ -282,6 +282,79 @@ True
282282See :doc: `images_and_memory ` for more details on managing image memory and
283283controlling the image cache.
284284
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+
285358******************
286359Loading and saving
287360******************
0 commit comments