def xyz_ordered(self, positive=False): """ Returns an image with the affine diagonal, (optionally with positive entries), in the XYZ coordinate system. Parameters ---------- positive : bool, optional If True, also ensures that the diagonal entries are positive. Notes ----- This may possibly transpose the data array. If positive is True, this may involve creating a new array with data self.get_data()[::-1,::-1] """ A, b = to_matrix_vector(self.affine) if not np.all((np.abs(A) > 0.001).sum(axis=0) == 1): raise ValueError( 'Cannot reorder the axis: the image affine contains rotations' ) axis_numbers = list(np.argmax(np.abs(A), axis=1)) im = self.reordered_axes(axis_numbers + range(3, self.ndim)) if not positive: return im else: # Determine which axes, if any, have to be flipped in the array slice_list = [] diag_values = np.diag(im.affine) for value in np.diag(im.affine)[:-1]: if value < 0: slice_list.append(slice(None,None,-1)) else: slice_list.append(slice(None,None,None)) if slice_list == [slice(None,None,None)]*3: # do nothing return im else: from nipy.core.image.image import subsample im = subsample(im.to_image(), tuple(slice_list)) return XYZImage.from_image(im)
def xyz_ordered(self): """ Returns an image with the affine diagonal and positive in its coordinate system. """ A, b = to_matrix_vector(self.affine) if not np.all((np.abs(A) > 0.001).sum(axis=0) == 1): raise CoordSystemError( 'Cannot reorder the axis: the image affine contains rotations' ) axis_numbers = list(np.argmax(np.abs(A), axis=1)) axis_names = [self.spatial_coordmap.function_domain.coord_names[a] for a in axis_numbers] reordered_coordmap = self.spatial_coordmap.reordered_domain(axis_names) data = self.get_data() transposed_data = np.transpose(data, axis_numbers + range(3, self.ndim)) return AffineImage(transposed_data, reordered_coordmap.affine, reordered_coordmap.function_domain.name)
def __init__(self, affine, input_coords, output_coords): """ Return an CoordinateMap specified by an affine transformation in homogeneous coordinates. Parameters ---------- affine : array-like affine homogenous coordinate matrix input_coords : :class:`CoordinateSystem` input coordinates output_coords : :class:`CoordinateSystem` output coordinates Notes ----- The dtype of the resulting matrix is determined by finding a safe typecast for the input_coords, output_coords and affine. """ affine = np.asarray(affine) dtype = safe_dtype(affine.dtype, input_coords.coord_dtype, output_coords.coord_dtype) inaxes = input_coords.coord_names outaxes = output_coords.coord_names self._input_coords = CoordinateSystem(inaxes, input_coords.name, dtype) self._output_coords = CoordinateSystem(outaxes, output_coords.name, dtype) affine = np.asarray(affine, dtype=dtype) if affine.shape != (self.ndim[1]+1, self.ndim[0]+1): raise ValueError('coordinate lengths do not match ' 'affine matrix shape') self._affine = affine A, b = affines.to_matrix_vector(affine) def _mapping(x): value = np.dot(x, A.T) value += b return value self._mapping = _mapping
def resample(image, target, mapping, shape, order=3, **interp_kws): """ Resample an image to a target CoordinateMap with a "world-to-world" mapping and spline interpolation of a given order. Here, "world-to-world" refers to the fact that mapping should be a callable that takes a physical coordinate in "target" and gives a physical coordinate in "image". Parameters ---------- image : Image instance that is to be resampled target :target CoordinateMap for output image mapping : transformation from target.function_range to image.coordmap.function_range, i.e. 'world-to-world mapping' Can be specified in three ways: a callable, a tuple (A, b) representing the mapping y=dot(A,x)+b or a representation of this in homogeneous coordinates. shape : shape of output array, in target.function_domain order : what order of interpolation to use in `scipy.ndimage` interp_kws : keyword arguments for ndimage interpolator routine Returns ------- output : Image instance with interpolated data and output.coordmap == target """ if not callable(mapping): if type(mapping) is type(()): A, b = mapping ndimout = b.shape[0] ndimin = A.shape[1] mapping = np.zeros((ndimout+1, ndimin+1)) mapping[:ndimout,:ndimin] = A mapping[:ndimout,-1] = b mapping[-1,-1] = 1. # image world to target world mapping TW2IW = AffineTransform(target.function_range, image.coordmap.function_range, mapping) else: TW2IW = CoordinateMap(mapping, target.function_range, image.coordmap.function_range) function_domain = target.function_domain function_range = image.coordmap.function_range # target voxel to image world mapping TV2IW = compose(TW2IW, target) # CoordinateMap describing mapping from target voxel to # image world coordinates if not isinstance(TV2IW, AffineTransform): # interpolator evaluates image at values image.coordmap.function_range, # i.e. physical coordinates rather than voxel coordinates grid = ArrayCoordMap.from_shape(TV2IW, shape) interp = ImageInterpolator(image, order=order) idata = interp.evaluate(grid.transposed_values, **interp_kws) del(interp) else: TV2IV = compose(image.coordmap.inverse(), TV2IW) if isinstance(TV2IV, AffineTransform): A, b = affines.to_matrix_vector(TV2IV.affine) data = np.asarray(image) idata = affine_transform(data, A, offset=b, output_shape=shape, output=data.dtype, order=order, **interp_kws) else: interp = ImageInterpolator(image, order=order) grid = ArrayCoordMap.from_shape(TV2IV, shape) idata = interp.evaluate(grid.values, **interp_kws) del(interp) return Image(idata, target)
def test_to_matrix_vector(): mat, vec, xform = build_xform() newmat, newvec = affines.to_matrix_vector(xform) yield assert_equal, newmat, mat yield assert_equal, newvec, vec