def register_com(vol_a: Volume, vol_b: Volume) -> Tuple[Volume, Volume]: """ Perform center-of-mass registration on two volumes :param vol_a: The fixed volume :param vol_b: The moving volume :return: The updated volumes """ from dipy.align.imaffine import transform_centers_of_mass affine = transform_centers_of_mass(vol_a, vol_a.grid_to_world, vol_b, vol_b.grid_to_world) vol_b.world_transform[:] = np.array(affine.affine) return vol_a, vol_b
def test_transform_centers_of_mass_3d(): np.random.seed(1246592) shape = (64, 64, 64) rm = 8 sp = vf.create_sphere(shape[0] // 2, shape[1] // 2, shape[2] // 2, rm) moving = np.zeros(shape) # The center of mass will be (16, 16, 16), in image coordinates moving[:shape[0] // 2, :shape[1] // 2, :shape[2] // 2] = sp[...] rs = 16 # The center of mass will be (32, 32, 32), in image coordinates static = vf.create_sphere(shape[0], shape[1], shape[2], rs) # Create arbitrary image-to-space transforms axis = np.array([.5, 2.0, 1.5]) t = 0.15 # translation factor trans = np.array([[1, 0, 0, -t * shape[0]], [0, 1, 0, -t * shape[1]], [0, 0, 1, -t * shape[2]], [0, 0, 0, 1]]) trans_inv = npl.inv(trans) for rotation_angle in [-1 * np.pi / 6.0, 0.0, np.pi / 5.0]: for scale_factor in [0.83, 1.3, 2.07]: # scale rot = np.zeros(shape=(4, 4)) rot[:3, :3] = geometry.rodrigues_axis_rotation(axis, rotation_angle) rot[3, 3] = 1.0 scale = np.array([[1 * scale_factor, 0, 0, 0], [0, 1 * scale_factor, 0, 0], [0, 0, 1 * scale_factor, 0], [0, 0, 0, 1]]) static_grid2world = trans_inv.dot(scale.dot(rot.dot(trans))) moving_grid2world = npl.inv(static_grid2world) # Expected translation c_static = static_grid2world.dot((32, 32, 32, 1))[:3] c_moving = moving_grid2world.dot((16, 16, 16, 1))[:3] expected = np.eye(4) expected[:3, 3] = c_moving - c_static # Implementation under test actual = imaffine.transform_centers_of_mass(static, static_grid2world, moving, moving_grid2world) assert_array_almost_equal(actual.affine, expected)
def mutualInfo_dipy(img1, img2): img1_grid2world = np.identity(3) img2_grid2world = np.identity(3) # compute center of mass c_of_mass = transform_centers_of_mass(img1, img1_grid2world, img2, img2_grid2world) x_shift = c_of_mass.affine[1, -1] y_shift = c_of_mass.affine[0, -1] # prepare affine registration nbins = 32 sampling_prop = None metric = MutualInformationMetric(nbins, sampling_prop) level_iters = [10000, 1000, 100] sigmas = [3.0, 1.0, 0.0] factors = [4, 2, 1] affreg = AffineRegistration(metric=metric, level_iters=level_iters, sigmas=sigmas, factors=factors) # translation translation = affreg.optimize(img1, img2, TranslationTransform2D(), None, img1_grid2world, img2_grid2world, starting_affine=c_of_mass.affine) # rotation # ~ rigid = affreg.optimize(im1, im2, RigidTransform2D(), None, # ~ im1_grid2world, im2_grid2world, # ~ starting_affine=translation.affine) # ~ transformed = rigid.transform(im2) # ~ # resize, shear # ~ affine = affreg.optimize(im1, im2, AffineTransform2D(), None, # ~ im1_grid2world, im2_grid2world, # ~ starting_affine=rigid.affine) x_shift = translation.affine[1, -1] y_shift = translation.affine[0, -1] return np.asarray([-x_shift, -y_shift])
def center_of_mass(self, static, static_grid2world, moving, moving_grid2world): """ Function for the center of mass based image registration. Parameters ---------- static : 2D or 3D array the image to be used as reference during optimization. static_grid2world : array, shape (dim+1, dim+1), optional the voxel-to-space transformation associated with the static image. The default is None, implying the transform is the identity. moving : 2D or 3D array the image to be used as "moving" during optimization. It is necessary to pre-align the moving image to ensure its domain lies inside the domain of the deformation fields. This is assumed to be accomplished by "pre-aligning" the moving image towards the static using an affine transformation given by the 'starting_affine' matrix moving_grid2world : array, shape (dim+1, dim+1), optional the voxel-to-space transformation associated with the moving image. The default is None, implying the transform is the identity. """ img_registration = transform_centers_of_mass(static, static_grid2world, moving, moving_grid2world) transformed = img_registration.transform(moving) return transformed, img_registration.affine
.. figure:: resampled_0.png :align: center .. figure:: resampled_1.png :align: center .. figure:: resampled_2.png :align: center Input images before alignment. """ """ We can obtain a very rough (and fast) registration by just aligning the centers of mass of the two images """ c_of_mass = transform_centers_of_mass(static, static_grid2world, moving, moving_grid2world) """ We can now transform the moving image and draw it on top of the static image, registration is not likely to be good, but at least they will occupy roughly the same space """ transformed = c_of_mass.transform(moving) regtools.overlay_slices(static, transformed, None, 0, "Static", "Transformed", "transformed_com_0.png") regtools.overlay_slices(static, transformed, None, 1, "Static", "Transformed", "transformed_com_1.png") regtools.overlay_slices(static, transformed, None, 2, "Static", "Transformed", "transformed_com_2.png")
def _compute_morph_sdr(mri_from, mri_to, niter_affine=(100, 100, 10), niter_sdr=(5, 5, 3), zooms=(5., 5., 5.)): """Get a matrix that morphs data from one subject to another.""" _check_dep(nibabel='2.1.0', dipy='0.10.1') import nibabel as nib with np.testing.suppress_warnings(): from dipy.align import imaffine, imwarp, metrics, transforms from dipy.align.reslice import reslice logger.info('Computing nonlinear Symmetric Diffeomorphic Registration...') # use voxel size of mri_from if zooms is None: zooms = mri_from.header.get_zooms()[:3] zooms = np.atleast_1d(zooms).astype(float) if zooms.shape == (1,): zooms = np.repeat(zooms, 3) if zooms.shape != (3,): raise ValueError('zooms must be None, a singleton, or have shape (3,),' ' got shape %s' % (zooms.shape,)) # reslice mri_from mri_from_res, mri_from_res_affine = reslice( mri_from.get_data(), mri_from.affine, mri_from.header.get_zooms()[:3], zooms) with warnings.catch_warnings(): # nibabel<->numpy warning mri_from = nib.Nifti1Image(mri_from_res, mri_from_res_affine) # reslice mri_to mri_to_res, mri_to_res_affine = reslice( mri_to.get_data(), mri_to.affine, mri_to.header.get_zooms()[:3], zooms) with warnings.catch_warnings(): # nibabel<->numpy warning mri_to = nib.Nifti1Image(mri_to_res, mri_to_res_affine) affine = mri_to.affine mri_to = np.array(mri_to.dataobj, float) # to ndarray mri_to /= mri_to.max() mri_from_affine = mri_from.affine # get mri_from to world transform mri_from = np.array(mri_from.dataobj, float) # to ndarray mri_from /= mri_from.max() # normalize # compute center of mass c_of_mass = imaffine.transform_centers_of_mass( mri_to, affine, mri_from, affine) # set up Affine Registration affreg = imaffine.AffineRegistration( metric=imaffine.MutualInformationMetric(nbins=32), level_iters=list(niter_affine), sigmas=[3.0, 1.0, 0.0], factors=[4, 2, 1]) # translation translation = affreg.optimize( mri_to, mri_from, transforms.TranslationTransform3D(), None, affine, mri_from_affine, starting_affine=c_of_mass.affine) # rigid body transform (translation + rotation) rigid = affreg.optimize( mri_to, mri_from, transforms.RigidTransform3D(), None, affine, mri_from_affine, starting_affine=translation.affine) # affine transform (translation + rotation + scaling) pre_affine = affreg.optimize( mri_to, mri_from, transforms.AffineTransform3D(), None, affine, mri_from_affine, starting_affine=rigid.affine) # compute mapping sdr = imwarp.SymmetricDiffeomorphicRegistration( metrics.CCMetric(3), list(niter_sdr)) sdr_morph = sdr.optimize(mri_to, pre_affine.transform(mri_from)) shape = tuple(sdr_morph.domain_shape) # should be tuple of int logger.info('done.') return shape, zooms, affine, pre_affine, sdr_morph
def quick_check(): img1_fname = "/home/omar/data/DATA_NeoBrainS12/T1.nii.gz" img2_fname = "/home/omar/data/DATA_NeoBrainS12/set2_i1_t1.nii.gz" img1_nib = nib.load(img1_fname) img1 = img1_nib.get_data().squeeze() img1_affine = img1_nib.get_affine() img2_nib = nib.load(img2_fname) img2 = img2_nib.get_data().squeeze() img2_affine = img2_nib.get_affine() # nib.aff2axcodes(img1_affine) #aff = AffineMap(None, img1.shape, img1_affine, img2.shape, img2_affine) #aff = transform_centers_of_mass(img1, img1_affine, img2, img2_affine) aff = dipy_align(img1, img1_affine, img2, img2_affine, np.eye(4)) img2_resampled = aff.transform(img2) rt.overlay_slices(img1, img2_resampled, slice_type=0) rt.overlay_slices(img1, img2_resampled, slice_type=1) rt.overlay_slices(img1, img2_resampled, slice_type=2) # Verify that original and RAS versions of neo1 describe the same object # Load original data neo1_fname = get_neobrain('train', 1, 'T1') neo1_old, neo1_old_affine, neo1_old_spacing, neo1_old_ori = load_from_raw(neo1_fname) # Load RAS version neo1_nib = nib.load(neo1_fname) neo1 = neo1_nib.get_data() neo1_affine = neo1_nib.get_affine() # Resample RAS on top of original aff = AffineMap(None, neo1_old.shape, neo1_old_affine, neo1.shape, neo1_affine) neo1_resampled = aff.transform(neo1) rt.overlay_slices(neo1_old, neo1_resampled, slice_type=0) rt.overlay_slices(neo1_old, neo1_resampled, slice_type=1) rt.overlay_slices(neo1_old, neo1_resampled, slice_type=2) # Attempt to resample a test volume on top of training neo2_fname = get_neobrain('test', 1, 'i1_t1') neo2_nib = nib.load(neo2_fname) neo2 = neo2_nib.get_data() neo2_affine = neo2_nib.get_affine() aff = transform_centers_of_mass(neo1, neo1_affine, neo2, neo2_affine) #aff = dipy_align(neo1, neo1_affine, neo2, neo2_affine) neo2_resampled = aff.transform(neo2) rt.overlay_slices(neo1, neo2_resampled, slice_type=0) rt.overlay_slices(neo1, neo2_resampled, slice_type=1) rt.overlay_slices(neo1, neo2_resampled, slice_type=2) # Load atlas atlas_fname = get_neobrain('atlas', 'neo-withSkull', None) atlas_nib = nib.load(atlas_fname) atlas_affine = atlas_nib.get_affine() atlas = atlas_nib.get_data() rt.plot_slices(atlas) # Resample atlas on top of neo1 aff = AffineMap(None, neo1.shape, neo1_affine, atlas.shape, atlas_affine) atlas_resampled = aff.transform(atlas) rt.overlay_slices(neo1, atlas_resampled)
def c_of_mass(moving, static, static_affine, moving_affine, reg, starting_affine, params0=None): transform = transform_centers_of_mass(static, static_affine, moving, moving_affine) transformed = transform.transform(moving) return transformed, transform.affine
brainweb_nib = nib.load(brainweb_name) brainweb = brainweb_nib.get_data().squeeze() brainweb_affine = brainweb_nib.get_affine() brainweb = brainweb.transpose([0, 2, 1])[::-1, :, :] rt.plot_slices(brainweb) brainweb_affine = ibsr1_affine.copy() brainweb_affine[brainweb_affine != 0] = 1 brainweb_affine[0, 0] = -1 # Reslice Brainweb on IBSR1 ibsr_to_bw = AffineMap(None, ibsr1.shape, ibsr1_affine, brainweb.shape, brainweb_affine) bw_on_ibsr1 = ibsr_to_bw.transform(brainweb) rt.overlay_slices(ibsr1, bw_on_ibsr1) # misaligned c_of_mass = transform_centers_of_mass(ibsr1, ibsr1_affine, brainweb, brainweb_affine) bw_on_ibsr1 = c_of_mass.transform(brainweb) rt.overlay_slices(ibsr1, bw_on_ibsr1) # roughly aligned # Start affine alignment aff_name = "ibsr1_to_brainweb.p" if os.path.isfile(aff_name): ibsr_bw_affmap = pickle.load(open(aff_name, "r")) else: ibsr_bw_affmap = dipy_align(ibsr1, ibsr1_affine, brainweb, brainweb_affine) pickle.dump(ibsr_bw_affmap, open(aff_name, "w")) bw_on_ibsr1 = ibsr_bw_affmap.transform(brainweb) rt.overlay_slices(ibsr1, bw_on_ibsr1, slice_type=0) # aligned (sagital view) rt.overlay_slices(ibsr1, bw_on_ibsr1, slice_type=1) # aligned (axial view) rt.overlay_slices(ibsr1, bw_on_ibsr1, slice_type=2) # aligned (coronal view)
brainweb_nib = nib.load(brainweb_name) brainweb = brainweb_nib.get_data().squeeze() brainweb_affine = brainweb_nib.get_affine() brainweb = brainweb.transpose([0, 2, 1])[::-1, :, :] rt.plot_slices(brainweb) brainweb_affine = ibsr1_affine.copy() brainweb_affine[brainweb_affine != 0] = 1 brainweb_affine[0, 0] = -1 # Reslice Brainweb on IBSR1 ibsr_to_bw = AffineMap(None, ibsr1.shape, ibsr1_affine, brainweb.shape, brainweb_affine) bw_on_ibsr1 = ibsr_to_bw.transform(brainweb) rt.overlay_slices(ibsr1, bw_on_ibsr1) # misaligned c_of_mass = transform_centers_of_mass(ibsr1, ibsr1_affine, brainweb, brainweb_affine) bw_on_ibsr1 = c_of_mass.transform(brainweb) rt.overlay_slices(ibsr1, bw_on_ibsr1) # roughly aligned # Start affine alignment aff_name = 'ibsr1_to_brainweb.p' if os.path.isfile(aff_name): ibsr_bw_affmap = pickle.load(open(aff_name, 'r')) else: ibsr_bw_affmap = dipy_align(ibsr1, ibsr1_affine, brainweb, brainweb_affine) pickle.dump(ibsr_bw_affmap, open(aff_name, 'w')) bw_on_ibsr1 = ibsr_bw_affmap.transform(brainweb) rt.overlay_slices(ibsr1, bw_on_ibsr1, slice_type=0) # aligned (sagital view) rt.overlay_slices(ibsr1, bw_on_ibsr1, slice_type=1) # aligned (axial view) rt.overlay_slices(ibsr1, bw_on_ibsr1, slice_type=2) # aligned (coronal view)
def quick_check(): img1_fname = "/home/omar/data/DATA_NeoBrainS12/T1.nii.gz" img2_fname = "/home/omar/data/DATA_NeoBrainS12/set2_i1_t1.nii.gz" img1_nib = nib.load(img1_fname) img1 = img1_nib.get_data().squeeze() img1_affine = img1_nib.get_affine() img2_nib = nib.load(img2_fname) img2 = img2_nib.get_data().squeeze() img2_affine = img2_nib.get_affine() # nib.aff2axcodes(img1_affine) #aff = AffineMap(None, img1.shape, img1_affine, img2.shape, img2_affine) #aff = transform_centers_of_mass(img1, img1_affine, img2, img2_affine) aff = dipy_align(img1, img1_affine, img2, img2_affine, np.eye(4)) img2_resampled = aff.transform(img2) rt.overlay_slices(img1, img2_resampled, slice_type=0) rt.overlay_slices(img1, img2_resampled, slice_type=1) rt.overlay_slices(img1, img2_resampled, slice_type=2) # Verify that original and RAS versions of neo1 describe the same object # Load original data neo1_fname = get_neobrain('train', 1, 'T1') neo1_old, neo1_old_affine, neo1_old_spacing, neo1_old_ori = load_from_raw( neo1_fname) # Load RAS version neo1_nib = nib.load(neo1_fname) neo1 = neo1_nib.get_data() neo1_affine = neo1_nib.get_affine() # Resample RAS on top of original aff = AffineMap(None, neo1_old.shape, neo1_old_affine, neo1.shape, neo1_affine) neo1_resampled = aff.transform(neo1) rt.overlay_slices(neo1_old, neo1_resampled, slice_type=0) rt.overlay_slices(neo1_old, neo1_resampled, slice_type=1) rt.overlay_slices(neo1_old, neo1_resampled, slice_type=2) # Attempt to resample a test volume on top of training neo2_fname = get_neobrain('test', 1, 'i1_t1') neo2_nib = nib.load(neo2_fname) neo2 = neo2_nib.get_data() neo2_affine = neo2_nib.get_affine() aff = transform_centers_of_mass(neo1, neo1_affine, neo2, neo2_affine) #aff = dipy_align(neo1, neo1_affine, neo2, neo2_affine) neo2_resampled = aff.transform(neo2) rt.overlay_slices(neo1, neo2_resampled, slice_type=0) rt.overlay_slices(neo1, neo2_resampled, slice_type=1) rt.overlay_slices(neo1, neo2_resampled, slice_type=2) # Load atlas atlas_fname = get_neobrain('atlas', 'neo-withSkull', None) atlas_nib = nib.load(atlas_fname) atlas_affine = atlas_nib.get_affine() atlas = atlas_nib.get_data() rt.plot_slices(atlas) # Resample atlas on top of neo1 aff = AffineMap(None, neo1.shape, neo1_affine, atlas.shape, atlas_affine) atlas_resampled = aff.transform(atlas) rt.overlay_slices(neo1, atlas_resampled)
def warp_syn_dipy(static_fname, moving_fname): import os import numpy as np import nibabel as nb from dipy.align.metrics import CCMetric from dipy.align.imaffine import (transform_centers_of_mass, AffineMap, MutualInformationMetric, AffineRegistration) from dipy.align.transforms import (TranslationTransform3D, RigidTransform3D, AffineTransform3D) from dipy.align.imwarp import (DiffeomorphicMap, SymmetricDiffeomorphicRegistration) from nipype.utils.filemanip import fname_presuffix static = nb.load(static_fname) moving = nb.load(moving_fname) c_of_mass = transform_centers_of_mass(static.get_data(), static.affine, moving.get_data(), moving.affine) nbins = 32 sampling_prop = None metric = MutualInformationMetric(nbins, sampling_prop) level_iters = [10000, 1000, 100] sigmas = [3.0, 1.0, 0.0] factors = [4, 2, 1] affreg = AffineRegistration(metric=metric, level_iters=level_iters, sigmas=sigmas, factors=factors) transform = TranslationTransform3D() params0 = None starting_affine = c_of_mass.affine translation = affreg.optimize(static.get_data(), moving.get_data(), transform, params0, static.affine, moving.affine, starting_affine=starting_affine) transform = RigidTransform3D() params0 = None starting_affine = translation.affine rigid = affreg.optimize(static.get_data(), moving.get_data(), transform, params0, static.affine, moving.affine, starting_affine=starting_affine) transform = AffineTransform3D() params0 = None starting_affine = rigid.affine affine = affreg.optimize(static.get_data(), moving.get_data(), transform, params0, static.affine, moving.affine, starting_affine=starting_affine) metric = CCMetric(3, sigma_diff=3.) level_iters = [25, 10, 5] sdr = SymmetricDiffeomorphicRegistration(metric, level_iters) starting_affine = affine.affine mapping = sdr.optimize( static.get_data(), moving.get_data(), static.affine, moving.affine, starting_affine) warped_filename = os.path.abspath(fname_presuffix(moving_fname, newpath='./', suffix='_warped', use_ext=True)) warped = nb.Nifti1Image(mapping.transform(moving.get_data()), static.affine) warped.to_filename(warped_filename) warp_filename = os.path.abspath(fname_presuffix(moving_fname, newpath='./', suffix='_warp.npz', use_ext=False)) np.savez(warp_filename,prealign=mapping.prealign,forward=mapping.forward,backward=mapping.backward) return warp_filename, warped_filename