2525from .funcs import as_closest_canonical
2626from .spaces import vox2out_vox
2727from .nifti1 import Nifti1Header , Nifti1Image
28+ from .orientations import axcodes2ornt
2829from .imageclasses import spatial_axes_first
2930
3031SIGMA2FWHM = np .sqrt (8 * np .log (2 ))
@@ -313,36 +314,12 @@ def smooth_image(img,
313314 return out_class (sm_data , img .affine , img .header )
314315
315316
316- def _transform_range (x , new_min , new_max ):
317- """ Transform data to a new range, while maintaining ratios.
318-
319- Parameters
320- ----------
321- x : array-like
322- The data to transform.
323- new_min, new_max : scalar
324- The minimum and maximum of the output array.
325-
326- Returns
327- -------
328- transformed : array-like
329- A copy of the transformed data.
330-
331- Examples
332- --------
333- >>> _transform_range([2, 4, 6], -1, 1)
334- array([-1., 0., 1.])
335- """
336- x = np .asarray (x )
337- x_min , x_max = x .min (), x .max ()
338- return (x - x_min ) * (new_max - new_min ) / (x_max - x_min ) + new_min
339-
340-
341317def conform (from_img ,
342318 out_shape = (256 , 256 , 256 ),
343319 voxel_size = (1.0 , 1.0 , 1.0 ),
344320 order = 3 ,
345321 cval = 0.0 ,
322+ orientation = 'RAS' ,
346323 out_class = Nifti1Image ):
347324 """ Resample image to ``out_shape`` with voxels of size ``voxel_size``.
348325
@@ -351,10 +328,12 @@ def conform(from_img,
351328 function:
352329 - Resamples data to ``output_shape``
353330 - Resamples voxel sizes to ``voxel_size``
354- - Transforms data to range [0, 255] (while maintaining ratios)
355- - Casts to unsigned eight-bit integer
356331 - Reorients to RAS (``mri_convert --conform`` reorients to LIA)
357332
333+ Unlike ``mri_convert --conform``, this command does not:
334+ - Transform data to range [0, 255]
335+ - Cast to unsigned eight-bit integer
336+
358337 Parameters
359338 ----------
360339 from_img : object
@@ -373,6 +352,8 @@ def conform(from_img,
373352 Value used for points outside the boundaries of the input if
374353 ``mode='constant'``. Default is 0.0 (see
375354 ``scipy.ndimage.affine_transform``)
355+ orientation : str, optional
356+ Orientation of output image. Default is "RAS".
376357 out_class : None or SpatialImage class, optional
377358 Class of output image. If None, use ``from_img.__class__``.
378359
@@ -383,24 +364,29 @@ def conform(from_img,
383364 resampling `from_img` into axes aligned to the output space of
384365 ``from_img.affine``
385366 """
386- if from_img .ndim != 3 :
367+ # Only support 3D images. This can be made more general in the future, once tests
368+ # are written.
369+ required_ndim = 3
370+ if from_img .ndim != required_ndim :
387371 raise ValueError ("Only 3D images are supported." )
372+ elif len (out_shape ) != required_ndim :
373+ raise ValueError ("`out_shape` must have {} values" .format (required_ndim ))
374+ elif len (voxel_size ) != required_ndim :
375+ raise ValueError ("`voxel_size` must have {} values" .format (required_ndim ))
376+
388377 # Create fake image of the image we want to resample to.
389378 hdr = Nifti1Header ()
390379 hdr .set_data_shape (out_shape )
391380 hdr .set_zooms (voxel_size )
392381 dst_aff = hdr .get_best_affine ()
393382 to_img = Nifti1Image (np .empty (out_shape ), affine = dst_aff , header = hdr )
383+
394384 # Resample input image.
395385 out_img = resample_from_to (
396386 from_img = from_img , to_vox_map = to_img , order = order , mode = "constant" ,
397387 cval = cval , out_class = out_class )
398- # Cast to uint8.
399- data = out_img .get_fdata ()
400- data = _transform_range (data , new_min = 0.0 , new_max = 255.0 )
401- data = data .round (out = data ).astype (np .uint8 )
402- out_img ._dataobj = data
403- out_img .set_data_dtype (data .dtype )
404- # Reorient to RAS.
405- out_img = as_closest_canonical (out_img )
406- return out_img
388+
389+ labels = list (zip ('LPI' , 'RAS' ))
390+ # list(zip('RPI', 'LAS')
391+ # Reorient to desired orientation.
392+ return out_img .as_reoriented (axcodes2ornt (orientation , labels = labels ))
0 commit comments