def test_MIMetric_invalid_params(): transform = regtransforms[('AFFINE', 3)] static = np.random.rand(20, 20, 20) moving = np.random.rand(20, 20, 20) n = transform.get_number_of_parameters() sampling_proportion = 0.3 theta_sing = np.zeros(n) theta_nan = np.zeros(n) theta_nan[...] = np.nan theta_inf = np.zeros(n) theta_nan[...] = np.inf mi_metric = imaffine.MutualInformationMetric(32, sampling_proportion) mi_metric.setup(transform, static, moving) for theta in [theta_sing, theta_nan, theta_inf]: # Test metric value at invalid params actual_val = mi_metric.distance(theta) assert(np.isinf(actual_val)) # Test gradient at invalid params expected_grad = np.zeros(n) actual_grad = mi_metric.gradient(theta) assert_equal(actual_grad, expected_grad) # Test both actual_val, actual_grad = mi_metric.distance_and_gradient(theta) assert(np.isinf(actual_val)) assert_equal(actual_grad, expected_grad)
def test_affreg_all_transforms(): # Test affine registration using all transforms with typical settings # Make sure dictionary entries are processed in the same order regardless # of the platform. # Otherwise any random numbers drawn within the loop would make # the test non-deterministic even if we fix the seed before the loop. # Right now, this test does not draw any samples, # but we still sort the entries # to prevent future related failures. for ttype in sorted(factors): dim = ttype[1] if dim == 2: nslices = 1 else: nslices = 45 factor = factors[ttype][0] sampling_pc = factors[ttype][1] transform = regtransforms[ttype] static, moving, static_grid2world, moving_grid2world, smask, mmask, T = \ setup_random_transform(transform, factor, nslices, 1.0) # Sum of absolute differences start_sad = np.abs(static - moving).sum() metric = imaffine.MutualInformationMetric(32, sampling_pc) affreg = imaffine.AffineRegistration(metric, [1000, 100, 50], [3, 1, 0], [4, 2, 1], 'L-BFGS-B', None, options=None) x0 = transform.get_identity_parameters() affine_map = affreg.optimize(static, moving, transform, x0, static_grid2world, moving_grid2world) transformed = affine_map.transform(moving) # Sum of absolute differences end_sad = np.abs(static - transformed).sum() reduction = 1 - end_sad / start_sad print("%s>>%f" % (ttype, reduction)) assert(reduction > 0.9) # Verify that exception is raised if level_iters is empty metric = imaffine.MutualInformationMetric(32) assert_raises(ValueError, imaffine.AffineRegistration, metric, [])
def test_mi_gradient(): np.random.seed(2022966) # Test the gradient of mutual information h = 1e-5 # Make sure dictionary entries are processed in the same order regardless # of the platform. Otherwise any random numbers drawn within the loop would # make the test non-deterministic even if we fix the seed before the loop: # in this case the samples are drawn with `np.random.randn` below for ttype in sorted(factors): transform = regtransforms[ttype] dim = ttype[1] if dim == 2: nslices = 1 else: nslices = 45 factor = factors[ttype][0] sampling_proportion = factors[ttype][1] theta = factors[ttype][2] # Start from a small rotation start = regtransforms[('ROTATION', dim)] nrot = start.get_number_of_parameters() starting_affine = start.param_to_matrix(0.25 * np.random.randn(nrot)) # Get data (pair of images related to each other by an known transform) static, moving, static_g2w, moving_g2w, smask, mmask, M = \ setup_random_transform(transform, factor, nslices, 2.0) # Prepare a MutualInformationMetric instance mi_metric = imaffine.MutualInformationMetric(32, sampling_proportion) mi_metric.setup( transform, static, moving, starting_affine=starting_affine) # Compute the gradient with the implementation under test actual = mi_metric.gradient(theta) # Compute the gradient using finite-diferences n = transform.get_number_of_parameters() expected = np.empty(n, dtype=np.float64) val0 = mi_metric.distance(theta) for i in range(n): dtheta = theta.copy() dtheta[i] += h val1 = mi_metric.distance(dtheta) expected[i] = (val1 - val0) / h dp = expected.dot(actual) enorm = npl.norm(expected) anorm = npl.norm(actual) nprod = dp / (enorm * anorm) assert(nprod >= 0.99)
def _compute_morph_sdr(mri_from, mri_to, niter_affine, niter_sdr, zooms): """Get a matrix that morphs data from one subject to another.""" 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...') # reslice mri_from mri_from_res, mri_from_res_affine = reslice( _get_img_fdata(mri_from), 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( _get_img_fdata(mri_to), 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 = _get_img_fdata(mri_to) # to ndarray mri_to /= mri_to.max() mri_from_affine = mri_from.affine # get mri_from to world transform mri_from = _get_img_fdata(mri_from) # 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, 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 logger.info('Optimizing translation:') with wrapped_stdout(indent=' '): 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) logger.info('Optimizing rigid-body:') with wrapped_stdout(indent=' '): rigid = affreg.optimize( mri_to, mri_from, transforms.RigidTransform3D(), None, affine, mri_from_affine, starting_affine=translation.affine) # affine transform (translation + rotation + scaling) logger.info('Optimizing full affine:') with wrapped_stdout(indent=' '): 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)) logger.info('Optimizing SDR:') with wrapped_stdout(indent=' '): sdr_morph = sdr.optimize(mri_to, pre_affine.transform(mri_from)) shape = tuple(sdr_morph.domain_shape) # should be tuple of int return shape, zooms, affine, pre_affine, sdr_morph
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 test_affreg_all_transforms(): # Test affine registration using all transforms with typical settings # Make sure dictionary entries are processed in the same order regardless # of the platform. Otherwise any random numbers drawn within the loop would # make the test non-deterministic even if we fix the seed before the loop. # Right now, this test does not draw any samples, but we still sort the # entries to prevent future related failures. for ttype in sorted(factors): dim = ttype[1] if dim == 2: nslices = 1 else: nslices = 45 factor = factors[ttype][0] sampling_pc = factors[ttype][1] trans = regtransforms[ttype] # Shorthand: srt = setup_random_transform static, moving, static_g2w, moving_g2w, smask, mmask, T = srt( trans, factor, nslices, 1.0) # Sum of absolute differences start_sad = np.abs(static - moving).sum() metric = imaffine.MutualInformationMetric(32, sampling_pc) affreg = imaffine.AffineRegistration(metric, [1000, 100, 50], [3, 1, 0], [4, 2, 1], 'L-BFGS-B', None, options=None) x0 = trans.get_identity_parameters() # test warning for using masks (even if all ones) with sparse sampling if sampling_pc not in [1.0, None]: affine_map = assert_warns(UserWarning, affreg.optimize, static, moving, trans, x0, static_g2w, moving_g2w, None, None, smask, mmask) else: affine_map = affreg.optimize(static, moving, trans, x0, static_g2w, moving_g2w, None, None, smask, mmask) transformed = affine_map.transform(moving) # Sum of absolute differences end_sad = np.abs(static - transformed).sum() reduction = 1 - end_sad / start_sad print("%s>>%f" % (ttype, reduction)) assert(reduction > 0.9) # Verify that exception is raised if level_iters is empty metric = imaffine.MutualInformationMetric(32) assert_raises(ValueError, imaffine.AffineRegistration, metric, []) # Verify that exception is raised if masks are all zeros affine_map = assert_warns(UserWarning, affreg.optimize, static, moving, trans, x0, static_g2w, moving_g2w, None, None, np.zeros_like(smask), np.zeros_like(mmask))
def compute_morph_map(img_m, img_s=None, niter_affine=(100, 100, 10), niter_sdr=(5, 5, 3)): # get Static to world transform img_s_grid2world = img_s.affine # output Static as ndarray img_s = img_s.dataobj[:, :, :] # normalize values img_s = img_s.astype('float') / img_s.max() # get Moving to world transform img_m_grid2world = img_m.affine # output Moving as ndarray img_m = img_m.dataobj[:, :, :] # normalize values img_m = img_m.astype('float') / img_m.max() # compute center of mass c_of_mass = imaffine.transform_centers_of_mass(img_s, img_s_grid2world, img_m, img_m_grid2world) nbins = 32 # set up Affine Registration affreg = imaffine.AffineRegistration( metric=imaffine.MutualInformationMetric(nbins, None), level_iters=list(niter_affine), sigmas=[3.0, 1.0, 0.0], factors=[4, 2, 1]) # translation translation = affreg.optimize(img_s, img_m, transforms.TranslationTransform3D(), None, img_s_grid2world, img_m_grid2world, starting_affine=c_of_mass.affine) # rigid body transform (translation + rotation) rigid = affreg.optimize(img_s, img_m, transforms.RigidTransform3D(), None, img_s_grid2world, img_m_grid2world, starting_affine=translation.affine) # affine transform (translation + rotation + scaling) affine = affreg.optimize(img_s, img_m, transforms.AffineTransform3D(), None, img_s_grid2world, img_m_grid2world, starting_affine=rigid.affine) # apply affine transformation img_m_affine = affine.transform(img_m) # set up Symmetric Diffeomorphic Registration (metric, iterations) sdr = imwarp.SymmetricDiffeomorphicRegistration( metrics.CCMetric(3), list(niter_sdr)) # compute mapping mapping = sdr.optimize(img_s, img_m_affine) return mapping, affine