def test_applyDeformation_premat(): src2ref = affine.compose( np.random.randint(2, 5, 3), np.random.randint(1, 10, 3), [0, 0, 0]) ref2src = affine.invert(src2ref) srcdata = np.random.randint(1, 65536, (10, 10, 10)) refdata = np.random.randint(1, 65536, (10, 10, 10)) src = fslimage.Image(srcdata) ref = fslimage.Image(refdata, xform=src2ref) field = _affine_field(src, ref, ref2src, 'world', 'world') # First try a down-sampled version # of the original source image altsrc, xf = resample.resample(src, (5, 5, 5), origin='corner') altsrc = fslimage.Image(altsrc, xform=xf, header=src.header) expect, xf = resample.resampleToReference( altsrc, ref, matrix=src2ref, order=1, mode='nearest') premat = affine.concat(src .getAffine('world', 'voxel'), altsrc.getAffine('voxel', 'world')) result = nonlinear.applyDeformation( altsrc, field, order=1, mode='nearest', premat=premat) assert np.all(np.isclose(expect, result)) # Now try a down-sampled ROI # of the original source image altsrc = roi.roi(src, [(2, 9), (2, 9), (2, 9)]) altsrc, xf = resample.resample(altsrc, (4, 4, 4)) altsrc = fslimage.Image(altsrc, xform=xf, header=src.header) expect, xf = resample.resampleToReference( altsrc, ref, matrix=src2ref, order=1, mode='nearest') premat = affine.concat(src .getAffine('world', 'voxel'), altsrc.getAffine('voxel', 'world')) result = nonlinear.applyDeformation( altsrc, field, order=1, mode='nearest', premat=premat) assert np.all(np.isclose(expect, result)) # down-sampled and offset ROI # of the original source image altsrc = roi.roi(src, [(-5, 8), (-5, 8), (-5, 8)]) altsrc, xf = resample.resample(altsrc, (6, 6, 6)) altsrc = fslimage.Image(altsrc, xform=xf, header=src.header) expect, xf = resample.resampleToReference( altsrc, ref, matrix=src2ref, order=1, mode='nearest') premat = affine.concat(src .getAffine('world', 'voxel'), altsrc.getAffine('voxel', 'world')) result = nonlinear.applyDeformation( altsrc, field, order=1, mode='nearest', premat=premat) assert np.all(np.isclose(expect, result))
def test_applyDeformation_worldAligned(): refv2w = affine.scaleOffsetXform([1, 1, 1], [10, 10, 10]) fieldv2w = affine.scaleOffsetXform([2, 2, 2], [10.5, 10.5, 10.5]) src2ref = refv2w ref2src = affine.invert(src2ref) srcdata = np.random.randint(1, 65536, (10, 10, 10)) src = fslimage.Image(srcdata) ref = fslimage.Image(srcdata, xform=src2ref) field = _affine_field(src, ref, ref2src, 'world', 'world', shape=(5, 5, 5), fv2w=fieldv2w) field = nonlinear.DeformationField( nonlinear.convertDeformationType(field, 'absolute'), header=field.header, src=src, ref=ref, srcSpace='world', refSpace='world', defType='absolute') expect, xf = resample.resampleToReference( src, ref, matrix=src2ref, order=1, mode='constant', cval=0) result = nonlinear.applyDeformation( src, field, order=1, mode='constant', cval=0) expect = expect[1:-1, 1:-1, 1:-1] result = result[1:-1, 1:-1, 1:-1] assert np.all(np.isclose(expect, result))
def test_applyDeformation_altref(): src2ref = affine.compose( np.random.randint(2, 5, 3), np.random.randint(1, 10, 3), np.random.random(3)) ref2src = affine.invert(src2ref) srcdata = np.random.randint(1, 65536, (10, 10, 10)) refdata = np.random.randint(1, 65536, (10, 10, 10)) src = fslimage.Image(srcdata) ref = fslimage.Image(refdata, xform=src2ref) field = _affine_field(src, ref, ref2src, 'world', 'world') altrefxform = affine.concat( src2ref, affine.scaleOffsetXform([1, 1, 1], [5, 0, 0])) altref = fslimage.Image(refdata, xform=altrefxform) expect, xf = resample.resampleToReference( src, altref, matrix=src2ref, order=1, mode='constant', cval=0) result = nonlinear.applyDeformation( src, field, ref=altref, order=1, mode='constant', cval=0) # boundary voxels can get truncated # (4 is the altref-ref overlap boundary) expect[4, :, :] = 0 result[4, :, :] = 0 expect = expect[1:-1, 1:-1, 1:-1] result = result[1:-1, 1:-1, 1:-1] assert np.all(np.isclose(expect, result))
def test_nonlinear(seed): with tempdir.tempdir(): src2ref = _random_affine() ref2src = affine.invert(src2ref) src = _random_image(np.eye(4)) ref = _random_image(src2ref) field = _affine_field(src, ref, ref2src, 'world', 'world') x5.writeNonLinearX5('xform.x5', field) src.save('src') fsl_apply_x5.main('src xform.x5 out'.split()) result = fslimage.Image('out') expect = resample.resampleToReference(src, ref, matrix=src2ref, smooth=False)[0] assert result.sameSpace(ref) # We might get truncation on the edges result = result.data[1:-1, 1:-1, 1:-1] expect = expect[1:-1, 1:-1, 1:-1] tol = dict(atol=1e-3, rtol=1e-3) assert np.all(np.isclose(result, expect, **tol))
def test_linear_altsrc(seed): with tempdir.tempdir(): src2ref = _random_affine() src = _random_image(np.eye(4), (20, 20, 20)) ref = _random_image(src2ref) x5.writeLinearX5('xform.x5', src2ref, src, ref) src.save('src') ref.save('ref') srclo, xf = resample.resample(src, (10, 10, 10)) srclo = fslimage.Image(srclo, xform=xf) srchi, xf = resample.resample(src, (40, 40, 40)) srchi = fslimage.Image(srchi, xform=xf) srcoff = roi.roi(src, [(-10, 10), (-10, 10), (-10, 10)]) srclo.save('srclo') srchi.save('srchi') srcoff.save('srcoff') fsl_apply_x5.main('src xform.x5 out'.split()) fsl_apply_x5.main('srclo xform.x5 outlo'.split()) fsl_apply_x5.main('srchi xform.x5 outhi'.split()) fsl_apply_x5.main('srcoff xform.x5 outoff'.split()) out = fslimage.Image('out') outlo = fslimage.Image('outlo') outhi = fslimage.Image('outhi') outoff = fslimage.Image('outoff') exp = resample.resampleToReference(src, ref, matrix=src2ref)[0] explo = resample.resampleToReference(srclo, ref, matrix=src2ref)[0] exphi = resample.resampleToReference(srchi, ref, matrix=src2ref)[0] expoff = resample.resampleToReference(srcoff, ref, matrix=src2ref)[0] assert out.sameSpace(ref) assert outlo.sameSpace(ref) assert outhi.sameSpace(ref) assert outoff.sameSpace(ref) assert np.all(np.isclose(out.data, exp)) assert np.all(np.isclose(outlo.data, explo)) assert np.all(np.isclose(outhi.data, exphi)) assert np.all(np.isclose(outoff.data, expoff))
def test_resampleToReference3(): # Test resampling image to ref # with mismatched dimensions imgdata = np.random.randint(0, 65536, (5, 5, 5)) img = fslimage.Image(imgdata, xform=affine.scaleOffsetXform((2, 2, 2), (0.5, 0.5, 0.5))) # reference/expected data when # resampled to ref (using nn interp). # Same as image, upsampled by a # factor of 2 refdata = np.repeat(np.repeat(np.repeat(imgdata, 2, 0), 2, 1), 2, 2) refdata = np.array([refdata] * 8).transpose((1, 2, 3, 0)) ref = fslimage.Image(refdata) # We should be able to use a 4D reference resampled, xform = resample.resampleToReference(img, ref, order=0, mode='nearest') assert np.all(resampled == ref.data[..., 0]) # If resampling a 4D image with a 3D reference, # the fourth dimension should be passed through resampled, xform = resample.resampleToReference(ref, img, order=0, mode='nearest') exp = np.array([imgdata] * 8).transpose((1, 2, 3, 0)) assert np.all(resampled == exp) # When resampling 4D to 4D, only the # first 3 dimensions should be resampled imgdata = np.array([imgdata] * 15).transpose((1, 2, 3, 0)) img = fslimage.Image(imgdata, xform=img.voxToWorldMat) exp = np.array([refdata[..., 0]] * 15).transpose((1, 2, 3, 0)) resampled, xform = resample.resampleToReference(img, ref, order=0, mode='nearest') assert np.all(resampled == exp)
def __resample(self): """Called when this ``ResampleAction`` is invoked. Shows a ``ResampleDialog``, and then resamples the currently selected overlay. """ ovl = self.displayCtx.getSelectedOverlay() opts = self.displayCtx.getOpts(ovl) def refCandidate(o): return (isinstance(o, fslimage.Nifti) and (o is not ovl) and not o.sameSpace(ovl)) refs = [o for o in self.overlayList if refCandidate(o)] dlg = ResampleDialog(self.__frame, title=ovl.name, shape=ovl.shape, pixdim=ovl.pixdim, refs=refs) if dlg.ShowModal() != wx.ID_OK: return newShape = dlg.GetVoxels() interp = dlg.GetInterpolation() origin = dlg.GetOrigin() dtype = dlg.GetDataType() smoothing = dlg.GetSmoothing() ref = dlg.GetReference() allvols = dlg.GetAllVolumes() interp = {'nearest': 0, 'linear': 1, 'cubic': 3}[interp] name = '{}_resampled'.format(ovl.name) if allvols or ovl.ndim == 3: slc = None else: slc = opts.index() if allvols and ovl.ndim > 3: newShape = list(newShape) + list(ovl.shape[3:]) kwargs = dict(sliceobj=slc, dtype=dtype, order=interp, origin=origin, smooth=smoothing) if ref is not None: resampled, xform = resample.resampleToReference(ovl, ref, **kwargs) else: resampled, xform = resample.resample(ovl, newShape, **kwargs) resampled = fslimage.Image(resampled, xform=xform, header=ovl.header, name=name) self.overlayList.append(resampled)
def test_resampleToReference4(): # the image and ref are out of # alignment, but this affine # will bring them into alignment img2ref = affine.scaleOffsetXform([2, 2, 2], [10, 10, 10]) imgdata = np.random.randint(0, 65536, (5, 5, 5)) refdata = np.zeros((5, 5, 5)) img = fslimage.Image(imgdata) ref = fslimage.Image(refdata, xform=img2ref) # Without the affine, the image # will be out of the FOV of the # reference resampled, xform = resample.resampleToReference(img, ref) assert np.all(resampled == 0) # But applying the affine will # cause them to overlap # perfectly in world coordinates resampled, xform = resample.resampleToReference(img, ref, matrix=img2ref) assert np.all(resampled == imgdata)
def test_resampleToReference1(): # Basic test - output has same # dimensions/space as reference for i in range(25): ishape = np.random.randint(5, 50, 3) rshape = np.random.randint(5, 50, 3) iv2w = random_affine() rv2w = random_affine() img = fslimage.Image(make_random_image(dims=ishape, xform=iv2w)) ref = fslimage.Image(make_random_image(dims=rshape, xform=rv2w)) res = resample.resampleToReference(img, ref) res = fslimage.Image(res[0], header=ref.header) assert res.sameSpace(ref)
def test_resampleToReference2(): # More specific test - output # data gets transformed correctly # into reference space img = np.zeros((5, 5, 5), dtype=float) img[1, 1, 1] = 1 img = fslimage.Image(img) refv2w = affine.scaleOffsetXform([1, 1, 1], [-1, -1, -1]) ref = np.zeros((5, 5, 5), dtype=float) ref = fslimage.Image(ref, xform=refv2w) res = resample.resampleToReference(img, ref, order=0) exp = np.zeros((5, 5, 5), dtype=float) exp[2, 2, 2] = 1 assert np.all(np.isclose(res[0], exp))
def test_linear(seed): with tempdir.tempdir(): src2ref = _random_affine() src = _random_image(np.eye(4)) ref = _random_image(src2ref) x5.writeLinearX5('xform.x5', src2ref, src, ref) src.save('src') ref.save('ref') fsl_apply_x5.main('src xform.x5 out'.split()) result = fslimage.Image('out') expect = resample.resampleToReference(src, ref, matrix=src2ref)[0] assert result.sameSpace(ref) assert np.all(np.isclose(result.data, expect))
def applyLinear(args): """Applies a linear X5 transformation file to the input. :arg args: ``argparse.Namespace`` object :returns: The transformed input as an :class:`.Image` object """ input = args.input xform, src, ref = x5.readLinearX5(args.xform) if args.ref is not None: ref = args.ref res, xform = resample.resampleToReference(input, ref, matrix=xform, order=args.interp) return fslimage.Image(res, xform=xform, header=ref.header)
def test_applyDeformation(): src2ref = affine.compose(np.random.randint(2, 5, 3), np.random.randint(1, 10, 3), np.random.random(3)) ref2src = affine.invert(src2ref) srcdata = np.random.randint(1, 65536, (10, 10, 10)) refdata = np.random.randint(1, 65536, (10, 10, 10)) src = fslimage.Image(srcdata) ref = fslimage.Image(refdata, xform=src2ref) field = _affine_field(src, ref, ref2src, 'world', 'world') expect, xf = resample.resampleToReference(src, ref, matrix=src2ref, order=1, mode='nearest') result = nonlinear.applyDeformation(src, field, order=1, mode='nearest') assert np.all(np.isclose(expect, result))
def applyDeformation(image, field, ref=None, order=1, mode=None, cval=None, premat=None): """Applies a :class:`DeformationField` to an :class:`.Image`. The image is transformed into the space of the field's reference image space. See the ``scipy.ndimage.interpolation.map_coordinates`` function for details on the ``order``, ``mode`` and ``cval`` options. If an alternate reference image is provided via the ``ref`` argument, the deformation field is resampled into its space, and then applied to the input image. It is therefore assumed that an alternate ``ref`` is aligned in world coordinates with the field's actual reference image. :arg image: :class:`.Image` to be transformed :arg field: :class:`DeformationField` to use :arg ref: Alternate reference image - if not provided, ``field.ref`` is used :arg order: Spline interpolation order, passed through to the ``scipy.ndimage.affine_transform`` function - ``0`` corresponds to nearest neighbour interpolation, ``1`` (the default) to linear interpolation, and ``3`` to cubic interpolation. :arg mode: How to handle regions which are outside of the image FOV. Defaults to `''nearest'``. :arg cval: Constant value to use when ``mode='constant'``. :arg premat: Optional affine transform which can be used if ``image`` is not in the same space as ``field.src``. Assumed to transform from ``image`` **voxel** coordinates into ``field.src`` **voxel** coordinates. :return: ``numpy.array`` containing the transformed image data. """ if order is None: order = 1 if mode is None: mode = 'nearest' if cval is None: cval = 0 if ref is None: ref = field.ref # We need the field to contain # absolute source image voxel # coordinates field = convertDeformationSpace(field, 'voxel', 'voxel') if field.deformationType != 'absolute': field = DeformationField(convertDeformationType(field, 'absolute'), header=field.header, src=field.src, ref=field.ref, srcSpace='voxel', refSpace='voxel', defType='absolute') # If the field is not voxel-aligned # to the reference, we need to # resample the field itself into the # reference image space (assumed to # be world-aligned). If field and ref # are not not world aligned, regions # of the field outside of the # reference image space will contain # -1s, so will be detected as out of # bounds by map_coordinates below. # # This will potentially result in # truncation at the field boundaries, # but there's nothing we can do about # that. src = field.src if not field.sameSpace(ref): field = resample.resampleToReference(field, ref, order=order, mode='constant', cval=-1)[0] else: field = field.data # If the input image is in a # different space to the field # source space, we need to # adjust the resampling matrix. # We assume world-world alignment # between the original source # and the image to be resampled if (premat is not None) or (not image.sameSpace(src)): if premat is None: premat = affine.concat(image.getAffine('world', 'voxel'), src.getAffine('voxel', 'world')) else: premat = affine.invert(premat) shape = field.shape field = field.reshape((-1, 3)) field = affine.transform(field, premat) field = field.reshape(shape) field = field.transpose((3, 0, 1, 2)) return ndinterp.map_coordinates(image.data, field, order=order, mode=mode, cval=cval)
def test_nonlinear_altsrc(seed): with tempdir.tempdir(): src2ref = _random_affine() ref2src = affine.invert(src2ref) src = _random_image(np.eye(4), (20, 20, 20)) ref = _random_image(src2ref, (20, 20, 20)) field = _affine_field(src, ref, ref2src, 'world', 'world') x5.writeNonLinearX5('xform.x5', field) src.save('src') ref.save('ref') # use origin=corner so that the # resampled variants are exactly # aligned in the world coordinate # system srclo, xf = resample.resample(src, (10, 10, 10), origin='corner', smooth=False) srclo = fslimage.Image(srclo, xform=xf) srchi, xf = resample.resample(src, (40, 40, 40), origin='corner', smooth=False) srchi = fslimage.Image(srchi, xform=xf) srcoff = roi.roi(src, [(-10, 10), (-10, 10), (-10, 10)]) srclo.save('srclo') srchi.save('srchi') srcoff.save('srcoff') fsl_apply_x5.main('src xform.x5 out'.split()) fsl_apply_x5.main('srclo xform.x5 outlo'.split()) fsl_apply_x5.main('srchi xform.x5 outhi'.split()) fsl_apply_x5.main('srcoff xform.x5 outoff'.split()) out = fslimage.Image('out') outlo = fslimage.Image('outlo') outhi = fslimage.Image('outhi') outoff = fslimage.Image('outoff') exp, x1 = resample.resampleToReference(src, ref, matrix=src2ref, mode='constant', smooth=False) explo, x2 = resample.resampleToReference(srclo, ref, matrix=src2ref, mode='constant', smooth=False) exphi, x3 = resample.resampleToReference(srchi, ref, matrix=src2ref, mode='constant', smooth=False) expoff, x4 = resample.resampleToReference(srcoff, ref, matrix=src2ref, mode='constant', smooth=False) assert out.sameSpace(ref) assert outlo.sameSpace(ref) assert outhi.sameSpace(ref) assert outoff.sameSpace(ref) # We get boundary cropping, # so ignore edge slices out = out.data[1:-1, 1:-1, 1:-1] outlo = outlo.data[1:-1, 1:-1, 1:-1] outhi = outhi.data[1:-1, 1:-1, 1:-1] outoff = outoff.data[:9, :9, :9] exp = exp[1:-1, 1:-1, 1:-1] explo = explo[1:-1, 1:-1, 1:-1] exphi = exphi[1:-1, 1:-1, 1:-1] expoff = expoff[:9, :9, :9] tol = dict(atol=1e-3, rtol=1e-3) assert np.all(np.isclose(out, exp, **tol)) assert np.all(np.isclose(outlo, explo, **tol)) assert np.all(np.isclose(outhi, exphi, **tol)) assert np.all(np.isclose(outoff, expoff, **tol))