Skip to content

Commit a8af0bc

Browse files
committed
ENH: Add funcs.crop_image
1 parent a4a667d commit a8af0bc

File tree

1 file changed

+36
-0
lines changed

1 file changed

+36
-0
lines changed

nibabel/funcs.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,3 +219,39 @@ def _aff_is_diag(aff):
219219
''' Utility function returning True if affine is nearly diagonal '''
220220
rzs_aff = aff[:3, :3]
221221
return np.allclose(rzs_aff, np.diag(np.diag(rzs_aff)))
222+
223+
224+
def crop_image(img, mask=None):
225+
''' Crop ``img`` to smallest region that contains all non-zero data
226+
227+
The image is cropped in the current orientation; no rotations or resampling
228+
are performed.
229+
The affine matrix is updated with the new intercept, so that all values are
230+
found at the same RAS locations.
231+
232+
Parameters
233+
----------
234+
img : ``spatialimage``
235+
mask : ``spatialimage``, optional
236+
If supplied, use the bounding box of ``mask``, rather than ``img``
237+
238+
Returns
239+
-------
240+
cropped_img : ``spatialimage``
241+
Version of `img` with cropped data array and updated affine matrix
242+
'''
243+
if mask is None:
244+
mask = img
245+
elif not np.allclose(img.affine == mask.affine):
246+
raise ValueError('Affine for image does not match affine for mask')
247+
248+
bounds = np.sort(np.vstack(np.nonzero(mask.get_data())))[:, [0, -1]]
249+
x, y, z = bounds
250+
new_origin = np.vstack((bounds[:, [0]], [1]))
251+
252+
new_data = img.get_data()[x[0]:x[1] + 1, y[0]:y[1] + 1, z[0]:z[1] + 1]
253+
254+
new_aff = img.affine.copy()
255+
new_aff[:, [3]] = img.affine.dot(new_origin)
256+
257+
return img.__class__(new_data, new_aff, img.header)

0 commit comments

Comments
 (0)