@@ -245,16 +245,41 @@ def crop_image(img, bounds, margin=0):
245245 Version of `img` with cropped data array and updated affine matrix
246246 '''
247247
248- try :
249- bounds = np .asanyarray (bounds ) + np .array ([- margin , margin ])
250- assert bounds .shape == (3 , 2 )
251- except (ValueError , AssertionError ):
248+ shape = np .reshape (img .shape [:3 ], (3 , 1 ))
249+ bounds = np .asanyarray (bounds )
250+ if bounds .shape != (3 , 2 ):
252251 raise ValueError ("bounds must be interpretable as a 3x2 array" )
252+ elif np .any (bounds > shape ):
253+ raise ValueError ("bounds must not exceed image dimensions" )
254+
255+ # Permit negative bounds
256+ if np .any (bounds < 0 ):
257+ bounds = (bounds + shape ) % shape
258+
259+ if np .any (bounds < 0 ):
260+ raise ValueError ("negative bounds may not exceed image dimensions" )
261+ elif np .any (bounds [:, 0 ] > bounds [:, 1 ]):
262+ raise ValueError ("degenerate (0 width) crops are not permitted" )
263+
264+ # Add margin in all directions
265+ bounds += np .array ([- margin , margin ])
266+
267+ # Set min/max
268+ bounds [bounds < 0 ] = 0
269+ over = bounds [:, 1 ] > shape .reshape (- 1 ) - 1
270+ bounds [over , 1 ] = shape [over , 0 ] - 1
271+
272+ # Include upper bounds
273+ bounds [:, 1 ] += 1
274+
275+ # Return original image if no cropping required
276+ if np .array_equal (bounds , np .hstack (([[0 ], [0 ], [0 ]], shape ))):
277+ return img
253278
254279 x , y , z = bounds
255280 new_origin = np .vstack ((bounds [:, [0 ]], 1 ))
256281
257- bounded_data = img .get_data ()[x [0 ]:x [1 ] + 1 , y [0 ]:y [1 ] + 1 , z [0 ]:z [1 ] + 1 ]
282+ bounded_data = img .get_data ()[x [0 ]:x [1 ], y [0 ]:y [1 ], z [0 ]:z [1 ]]
258283
259284 new_aff = img .affine .copy ()
260285 new_aff [:, [3 ]] = img .affine .dot (new_origin )
0 commit comments