def alignImage(static, moving, level_iters): """The Symmetric Normalization algorithm uses a multi-resolution approach by building a Gaussian Pyramid. The static image is used a reference; a transformation that transforms the moving image into the static image is found and applied to the static image. Returns overlay images, error image, and transformation matrix. Uses CrossCorrelation metric which makes sense for aligning AFM topography. INPUT: static and moving are both 2d arrays of the same dimension. Level_iters is a list (typically 4 entries) defines the number of iterations a user wants at each level of the pyramid, with the 0th entry referring to the finest resolution. OUTPUT: overlayimages: an image with the static, moving, and overlay images errorimage: the difference between the warped_moving image and the static reference. THe flatter the better. transformmatrix: the matrix corresponding to the forward transformation of a matrix.""" from dipy.align.imwarp import SymmetricDiffeomorphicRegistration from dipy.align.metrics import SSDMetric, CCMetric, EMMetric from dipy.viz import regtools dim = static.ndim metric = CCMetric(dim) sdr = SymmetricDiffeomorphicRegistration(metric, level_iters, inv_iter = 50) mapping = sdr.optimize(static, moving) warped_moving = mapping.transform(moving, 'linear') overlayimages = regtools.overlay_images(static, warped_moving, 'Static','Overlay','Warped moving', 'direct_warp_result.png') errorimage = plt.matshow(warped_moving-static, cmap='viridis') transformmatrix=mapping.forward return overlayimages, errorimage, transformmatrix
def register_diffeo(t_masked, m_masked, start_affine, registration=None): """ Run non-linear registration between `t_masked` and `m_masked` Parameters ---------- t_masked : image Template image object, with image data masked to set out-of-brain voxels to zero. m_masked : image Moving (individual) image object, with image data masked to set out-of-brain voxels to zero. start_affine : shape (4, 4) ndarray Affine mapping from voxels in `t_masked` to voxels in `m_masked`. registration : None or SymmetricDiffeoMorphicRegistration instance Registration instance we will use to register `t_masked` and `m_masked`. If None, make a default registration object. Returns ------- mapping : mapping instance Instance giving affine + non-linear mapping between voxels in `t_masked` and voxels in `m_masked`. """ if registration is None: registration = SymmetricDiffeomorphicRegistration( metric=CCMetric(3), level_iters=[10, 10, 5]) return registration.optimize(t_masked.get_data().astype(float), m_masked.get_data().astype(float), t_masked.affine, m_masked.affine, start_affine)
def syn_registration(static_data, static_affine, moving_data, moving_affine): # Terminology for comments: # 1. Static image = Reference image # 2. Moving image = Image that will be registered to the static image # Prealignment has been done using FLIRT, so the identity matrix is used since # no further transformation is necessary pre_align = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) # We want to find an invertible map that transforms the moving image into the # static image. We will use the Cross Correlation metric. metric = CCMetric(3) # Now we define an instance of the registration class. The SyN algorithm uses # a multi-resolution approach by building a Gaussian Pyramid. We instruct the # registration object to perform at most [n_0, n_1, ..., n_k] iterations at # each level of the pyramid. The 0-th level corresponds to the finest resolution. level_iters = [10, 10, 5] sdr = SymmetricDiffeomorphicRegistration(metric, level_iters) # Execute the optimization, which returns a DiffeomorphicMap object, # that can be used to register images back and forth between the static and # moving domains. We provide the pre-aligning matrix that brings the moving # image closer to the static image mapping = sdr.optimize(static_data, moving_data, static_affine, moving_affine, pre_align) # Warp the moving image and see if it gets similar to the static image warped_moving = mapping.transform(moving_data) return warped_moving, mapping
def test_plot_2d_diffeomorphic_map(): # Test the regtools plotting interface (lightly). mv_shape = (11, 12) moving = np.random.rand(*mv_shape) st_shape = (13, 14) static = np.random.rand(*st_shape) dim = static.ndim metric = SSDMetric(dim) level_iters = [200, 100, 50, 25] sdr = SymmetricDiffeomorphicRegistration(metric, level_iters, inv_iter=50) mapping = sdr.optimize(static, moving) # Smoke testing of plots ff = regtools.plot_2d_diffeomorphic_map(mapping, 10) # Defualt shape is static shape, moving shape npt.assert_equal(ff[0].shape, st_shape) npt.assert_equal(ff[1].shape, mv_shape) # Can specify shape ff = regtools.plot_2d_diffeomorphic_map(mapping, delta = 10, direct_grid_shape=(7, 8), inverse_grid_shape=(9, 10)) npt.assert_equal(ff[0].shape, (7, 8)) npt.assert_equal(ff[1].shape, (9, 10))
def syn_registration(moving, static, moving_affine=None, static_affine=None, step_length=0.25, metric='CC', dim=3, level_iters=[10, 10, 5], sigma_diff=2.0, prealign=None): """Register a source image (moving) to a target image (static). Parameters ---------- moving : ndarray The source image data to be registered moving_affine : array, shape (4,4) The affine matrix associated with the moving (source) data. static : ndarray The target image data for registration static_affine : array, shape (4,4) The affine matrix associated with the static (target) data metric : string, optional The metric to be optimized. One of `CC`, `EM`, `SSD`, Default: CCMetric. dim: int (either 2 or 3), optional The dimensions of the image domain. Default: 3 level_iters : list of int, optional the number of iterations at each level of the Gaussian Pyramid (the length of the list defines the number of pyramid levels to be used). Returns ------- warped_moving : ndarray The data in `moving`, warped towards the `static` data. forward : ndarray (..., 3) The vector field describing the forward warping from the source to the target. backward : ndarray (..., 3) The vector field describing the backward warping from the target to the source. """ use_metric = syn_metric_dict[metric](dim, sigma_diff=sigma_diff) sdr = SymmetricDiffeomorphicRegistration(use_metric, level_iters, step_length=step_length) mapping = sdr.optimize(static, moving, static_grid2world=static_affine, moving_grid2world=moving_affine, prealign=prealign) warped_moving = mapping.transform(moving) return warped_moving, mapping
def exampleDipy(): # example obtained from: http://nipy.org/dipy/examples_built/syn_registration_2d.html import ssl if hasattr(ssl, '_create_unverified_context'): ssl._create_default_https_context = ssl._create_unverified_context from dipy.data import fetch_stanford_hardi, read_stanford_hardi fetch_stanford_hardi() nib_stanford, gtab_stanford = read_stanford_hardi() stanford_b0 = np.squeeze(nib_stanford.get_data())[..., 0] from dipy.data.fetcher import fetch_syn_data, read_syn_data fetch_syn_data() nib_syn_t1, nib_syn_b0 = read_syn_data() syn_b0 = np.array(nib_syn_b0.get_data()) from dipy.segment.mask import median_otsu stanford_b0_masked, stanford_b0_mask = median_otsu(stanford_b0, 4, 4) syn_b0_masked, syn_b0_mask = median_otsu(syn_b0, 4, 4) static = stanford_b0_masked static_affine = nib_stanford.affine moving = syn_b0_masked moving_affine = nib_syn_b0.affine pre_align = np.array( [[1.02783543e+00, -4.83019053e-02, -6.07735639e-02, -2.57654118e+00], [4.34051706e-03, 9.41918267e-01, -2.66525861e-01, 3.23579799e+01], [5.34288908e-02, 2.90262026e-01, 9.80820307e-01, -1.46216651e+01], [0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 1.00000000e+00]]) from dipy.align.imaffine import AffineMap affine_map = AffineMap(pre_align, static.shape, static_affine, moving.shape, moving_affine) resampled = affine_map.transform(moving) metric = CCMetric(3) level_iters = [10, 10, 5] sdr = SymmetricDiffeomorphicRegistration(metric, level_iters) mapping = sdr.optimize(static, moving, static_affine, moving_affine, pre_align) warped_moving = mapping.transform(moving) for slice in range(41 - 12, 41 + 13): regtools.overlay_slices(static, resampled, slice, 1, 'Static', 'Pre Moving', 'GIFexample1/' + str(slice) + 'T1pre.png') regtools.overlay_slices(static, warped_moving, slice, 1, 'Static', 'Post moving', 'GIFexample1/' + str(slice) + 'T1post.png')
def dipy_work(self, uncorrected, worker_progress_signal): radius = 4 sigma_diff = 3.0 metric = CCMetric(2, sigma_diff, radius) level_iters = [25] sdr = SymmetricDiffeomorphicRegistration(metric, level_iters) corrected = np.zeros_like(uncorrected) corrected[0] = uncorrected[0] for i in range(1, len(uncorrected)): mapping = sdr.optimize(corrected[0], uncorrected[i]) corrected[i] = mapping.transform(uncorrected[i]) worker_progress_signal.emit(i) return {'corrected': corrected}
def get_params(self): level_iters = [ np.random.randint(i, j) for i, j in zip(self.iter_limits[0], self.iter_limits[1]) ] sdr = SymmetricDiffeomorphicRegistration(self.metric, level_iters, inv_iter=50) return {"sdr": sdr}
def abstractExample(): numBlobs = 4 shape = np.array([81, 106, 76]) static = np.zeros(shape) resampled = np.zeros(shape) size_blob = 3 for blob in range(numBlobs): jitter = np.random.randint(5) randIndX = 41 + 2 * blob randIndY = np.random.randint(shape[1] - 2 * size_blob) randIndZ = np.random.randint(shape[2] - 2 * size_blob) static[randIndX - size_blob:randIndX + size_blob, randIndY - size_blob:randIndY + size_blob, randIndZ - size_blob:randIndZ + size_blob] = 1 randIndY = randIndY + jitter randIndZ = randIndZ + jitter + np.random.randint(-1, 2) resampled[randIndX - size_blob:randIndX + size_blob, randIndY - size_blob:randIndY + size_blob, randIndZ - size_blob:randIndZ + size_blob] = 1 metric = CCMetric(3) level_iters = [10, 10, 5] sdr = SymmetricDiffeomorphicRegistration(metric, level_iters) mapping = sdr.optimize(static, resampled) warped_moving = mapping.transform(resampled) for slice in range(41 - 3 * size_blob, 41 + 3 * size_blob + 1): regtools.overlay_slices(static, resampled, slice, 0, 'Static', 'Pre Moving', 'GIFexample1/' + str(slice) + 'preMov.png') regtools.overlay_slices(static, warped_moving, slice, 0, 'Static', 'Post moving', 'GIFexample1/' + str(slice) + 'postMov.png')
def get_elastic_transform(subject_fa, atlas_fa, subject_path=".."): ''' :param subject_fa: the FA (nibabel img) of a static image of a subject (static) :param atlas_fa: the FA (nibabel img) of an atlas (Atlas will be warped onto subject) (moving) :return: elastic transformation map ''' if isfile(subject_path + "/FAReg_elastic_transform.pklz"): logging.debug("Load existing elastic transform...") return Utils.load_pkl_compressed(subject_path + "/FAReg_elastic_transform.pklz") static_img = subject_fa static = static_img.get_data() moving_img = atlas_fa moving = moving_img.get_data() # Optional (affine transformation of moving image to static coordinate system) -> needed if on very different ones! affine_map = AffineMap(np.eye(4), static.shape, static_img.get_affine(), moving.shape, moving_img.get_affine()) moving = affine_map.transform(moving) start_time = time.time() metric = CCMetric(3) level_iters = [10, 10, 5] # better # level_iters = [2, 2, 2] #fast -> not much sdr = SymmetricDiffeomorphicRegistration(metric, level_iters) mapping = sdr.optimize(static, moving) # mapping = sdr.optimize(static, moving, Utils.invert_x_and_y(static_img.get_affine()), Utils.invert_x_and_y(moving_img.get_affine())) #not needed logging.debug("elastic transform took {0:.2f}s".format(time.time() - start_time)) logging.debug("write elastic transform...") Utils.save_pkl_compressed( subject_path + "/FAReg_elastic_transform.pklz", mapping) return mapping
affine = affreg.optimize(t1_s, t1_m, AffineTransform3D(), None, t1_s_grid2world, t1_m_grid2world, starting_affine=rigid.affine) # apply affine transformation t1_m_affine = affine.transform(t1_m) ############################################################################### # Compute Symmetric Diffeomorphic Registration # set up Symmetric Diffeomorphic Registration (metric, iterations per level) sdr = SymmetricDiffeomorphicRegistration(CCMetric(3), niter_sdr) # compute mapping mapping = sdr.optimize(t1_s, t1_m_affine) ############################################################################### # Apply transformations and plot # morph img data img_sdr_affine = mapping.transform(affine.transform(img)) # make transformed ndarray a nifti img_vol_sdr_affine = nib.Nifti1Image(img_sdr_affine, affine=t1_s_grid2world) # save morphed grid nib.save(img_vol_sdr_affine, 'lcmv_inverse_fsavg.nii.gz')
hardi_affine = ni.get_affine() b0 = hardi_data[..., gtab.b0s_mask] mean_b0 = np.mean(b0, -1) ni_b0 = nib.Nifti1Image(mean_b0, hardi_affine) ni_b0.to_filename('mean_b0.nii') plt.matshow(mean_b0[:,:,mean_b0.shape[-1]//2], cmap=cm.bone) MNI_T2 = dpd.read_mni_template() MNI_T2_data = MNI_T2.get_data() MNI_T2_affine = MNI_T2.get_affine() level_iters = [10, 10, 5] dim = 3 metric = CCMetric(dim) sdr = SymmetricDiffeomorphicRegistration(metric, level_iters, step_length=0.25) sdr.verbosity = VerbosityLevels.DIAGNOSE mapping = sdr.optimize(MNI_T2_data, mean_b0, MNI_T2_affine, hardi_affine) warped_b0 = mapping.transform(mean_b0) plt.matshow(warped_b0[:,:,warped_b0.shape[-1]//2], cmap=cm.bone) plt.matshow(MNI_T2_data[:, :, MNI_T2_data.shape[-1]//2], cmap=cm.bone) new_ni = nib.Nifti1Image(warped_b0, MNI_T2_affine) new_ni.to_filename('./warped_b0.nii.gz') afqpath = 'D:/opt/AFQ/' LOCC_ni = nib.load(os.path.join(afqpath,'templates/callosum2/L_Occipital.nii.gz')) ROCC_ni = nib.load(os.path.join(afqpath,'templates/callosum2/R_Occipital.nii.gz')) midsag_ni = nib.load(os.path.join(afqpath,'templates/callosum2/Callosum_midsag.nii.gz')) LOCC_data = LOCC_ni.get_data() ROCC_data = ROCC_ni.get_data()
def img_reg(moving_img, target_img, reg='non-lin'): m_img = nib.load(moving_img) t_img = nib.load(target_img) m_img_data = m_img.get_data() t_img_data = t_img.get_data() m_img_affine = m_img.affine t_img_affine = t_img.affine identity = np.eye(4) affine_map = AffineMap(identity, t_img_data.shape, t_img_affine, m_img_data.shape, m_img_affine) m_img_resampled = affine_map.transform(m_img_data) c_of_mass = transform_centers_of_mass(t_img_data, t_img_affine, m_img_data, m_img_affine) tf_m_img_c_mass = c_of_mass.transform(m_img_data) nbins = 32 sampling_prop = None metric = MutualInformationMetric(nbins, sampling_prop) level_iters = [10, 10, 5] 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(t_img_data, m_img_data, transform, params0, t_img_affine, m_img_affine, starting_affine=starting_affine) tf_m_img_translat = translation.transform(m_img_data) transform = RigidTransform3D() params0 = None starting_affine = translation.affine rigid = affreg.optimize(t_img_data, m_img_data, transform, params0, t_img_affine, m_img_affine, starting_affine=starting_affine) tf_m_img_rigid = rigid.transform(m_img_data) transform = AffineTransform3D() affreg.level_iters = [10, 10, 10] affine = affreg.optimize(t_img_data, m_img_data, transform, params0, t_img_affine, m_img_affine, starting_affine=rigid.affine) if reg is None or reg == 'non-lin': metric = CCMetric(3) level_iters = [10, 10, 5] sdr = SymmetricDiffeomorphicRegistration(metric, level_iters) mapping = sdr.optimize(t_img_data, m_img_data, t_img_affine, m_img_affine, affine.affine) tf_m_img = mapping.transform(m_img_data) elif reg == 'affine': tf_m_img_aff = affine.transform(m_img_data) return tf_m_img metric = CCMetric(3) level_iters = [10, 10, 5] sdr = SymmetricDiffeomorphicRegistration(metric, level_iters) mapping = sdr.optimize(t_img_data, m_img_data, t_img_affine, m_img_affine, starting_affine=affine.affine) tf_m_img = mapping.transform(m_img_data)
.. figure:: input.png :align: center Input images before alignment. """ """ Let's the use the general Registration function with some naive parameters, such as set `step_length` as 1 assuming maximal step 1 pixel and reasonable small number of iteration since the deformation with already aligned images should be minimal. """ sdr = SymmetricDiffeomorphicRegistration(metric=SSDMetric(img_ref.ndim), step_length=1.0, level_iters=[50, 100], inv_iter=50, ss_sigma_factor=0.1, opt_tol=1.e-3) """ Perform the registration with equal images. """ mapping = sdr.optimize(img_ref.astype(float), img_ref.astype(float)) img_warp = mapping.transform(img_ref, 'linear') show_images(img_ref, img_warp, 'output-0') regtools.plot_2d_diffeomorphic_map(mapping, 5, 'map-0.png') """ .. figure:: output-0.png :align: center
of Squared Differences (SSD) is a good choice. """ dim = static.ndim metric = SSDMetric(dim) """ Now we define an instance of the registration class. The SyN algorithm uses a multi-resolution approach by building a Gaussian Pyramid. We instruct the registration instance to perform at most $[n_0, n_1, ..., n_k]$ iterations at each level of the pyramid. The 0-th level corresponds to the finest resolution. """ level_iters = [200, 100, 50, 25] sdr = SymmetricDiffeomorphicRegistration(metric, level_iters, inv_iter = 50) """ Now we execute the optimization, which returns a DiffeomorphicMap object, that can be used to register images back and forth between the static and moving domains """ mapping = sdr.optimize(static, moving) """ It is a good idea to visualize the resulting deformation map to make sure the result is reasonable (at least, visually) """ regtools.plot_2d_diffeomorphic_map(mapping, 10, 'diffeomorphic_map.png')
'allen_annotation_invsynned_to_' + subject + '_adjusted.nii.gz') # Load images reference_image = nib.load(reference_image_path) reference = reference_image.get_fdata() annotation_image = nib.load(annotation_image_path) annotation = annotation_image.get_fdata() input_image = nib.load(input_image_path) input = input_image.get_fdata() # syn metric = CCMetric(3) level_iters = [10, 10, 5, 5, 5] print(iSubject) print(datetime.datetime.now()) sdr = SymmetricDiffeomorphicRegistration(metric, level_iters) mapping = sdr.optimize(static=reference, moving=input, static_grid2world=reference_image.get_qform(), moving_grid2world=input_image.get_qform()) warped_image = mapping.transform(input) warped_reference = mapping.transform_inverse(reference) warped_annotation = mapping.transform_inverse(annotation, interpolation='nearest') # save warps input_invwarped_image = nib.Nifti1Image(warped_image, np.eye(4))
def affine_registration(reference, reference_grid2world, scan, scan_grid2world): #get first b0 volumes for both scans reference_b0 = reference[:, :, :, 0] scan_b0 = scan[:, :, :, 0] #In this function we use multiple stages to register the 2 scans #providng previous results as initialisation to the next stage, #the reason we do this is because registration is a non-convex #problem thus it is important to initialise as close to the #optiaml value as possible #Stage1: we obtain a very rough (and fast) registration by just aligning #the centers of mass of the two images center_of_mass = transform_centers_of_mass(reference_b0, reference_grid2world, scan_b0, scan_grid2world) #create the similarity metric (Mutual Information) to be used: nbins = 32 sampling_prop = None #use all voxels to perform registration metric = MutualInformationMetric(nbins, sampling_prop) #We use a multi-resolution stratergy to accelerate convergence and avoid #getting stuck at local optimas (below are the parameters) level_iters = [10000, 1000, 100] sigmas = [3.0, 1.0, 0.0 ] #parameters for gaussian kernel smoothing at each resolution factors = [4, 2, 1] #subsampling factor #optimisation algorithm used is L-BFGS-B affreg = AffineRegistration(metric=metric, level_iters=level_iters, sigmas=sigmas, factors=factors) #Stage2: Perform a basic translation transform transform = TranslationTransform3D() translation = affreg.optimize(reference_b0, scan_b0, transform, None, reference_grid2world, scan_grid2world, starting_affine=center_of_mass.affine) #Stage3 : optimize previous result with a rigid transform #(Includes translation, rotation) transform = RigidTransform3D() rigid = affreg.optimize(reference_b0, scan_b0, transform, None, reference_grid2world, scan_grid2world, starting_affine=translation.affine) #Stage4 : optimize previous result with a affine transform #(Includes translation, rotation, scale, shear) transform = AffineTransform3D() affine = affreg.optimize(reference_b0, scan_b0, transform, None, reference_grid2world, scan_grid2world, starting_affine=rigid.affine) if params.reg_type == "SDR": #Stage 5 : Symmetric Diffeomorphic Registration metric = CCMetric(3) level_iters = [400, 200, 100] sdr = SymmetricDiffeomorphicRegistration(metric, level_iters) mapping = sdr.optimize(reference_b0, scan_b0, reference_grid2world, scan_grid2world, affine.affine) else: mapping = affine #Once this is completed we can perform the affine transformation on each #volume of scan2 for volume in range(0, scan.shape[3]): #note affine is an AffineMap object, #The transform method transforms the input image from co-domain to domain space #By default, the transformed image is sampled at a grid defined by the shape of the domain #The sampling is performed using linear interpolation (refer to comp vision lab on homographies) scan[:, :, :, volume] = mapping.transform(scan[:, :, :, volume]) return scan
""" We want to find an invertible map that transforms the moving image into the static image. We will use the Cross Correlation metric """ metric = CCMetric(3) """ Now we define an instance of the registration class. The SyN algorithm uses a multi-resolution approach by building a Gaussian Pyramid. We instruct the registration object to perform at most [n_0, n_1, ..., n_k] iterations at each level of the pyramid. The 0-th level corresponds to the finest resolution. """ level_iters = [10, 10, 5] sdr = SymmetricDiffeomorphicRegistration(metric, level_iters) """ Execute the optimization, which returns a DiffeomorphicMap object, that can be used to register images back and forth between the static and moving domains. We provide the pre-aligning matrix that brings the moving image closer to the static image """ mapping = sdr.optimize(static, moving, static_affine, moving_affine, pre_align) """ Now let's warp the moving image and see if it gets similar to the static image """ warped_moving = mapping.transform(moving)
if os.path.isfile(config_fname): with open(config_fname,'r') as f: options = [tuple(line.strip().split()) for line in f.readlines()] options = {opt[0]:opt[1] for opt in options} else: options = {} step_length = float(options.get('step_length', '0.25')) inv_tol = float(options.get('inv_tol', '1e-3')) inv_iter = int(options.get('inv_iter', '20')) experiment_name = options.get('experiment_name') level_iters = [400, 200, 100, 50, 25] dim = 3 metric = SSDMetric(dim, smooth=3) sdr = SymmetricDiffeomorphicRegistration(metric, level_iters, inv_iter=inv_iter, inv_tol=inv_tol, opt_tol=1e-6, step_length=step_length, ss_sigma_factor=1.0) sdr.verbosity = VerbosityLevels.DIAGNOSE start = time.time() mapping = sdr.optimize(cup, sphere) end = time.time() elapsed = end - start print('Elapsed: %e'%(elapsed,)) fwd = np.array(mapping.forward) bwd = np.array(mapping.backward) # Get deformed mid slices z0 = fwd.shape[2]//2 whlines, wvlines = get_deformed_grid(fwd, [z0]) fwd_fname = 'fwd_lines_%s.p'%(experiment_name,)
def wm_syn(template_path, fa_path, working_dir): """ A function to perform ANTS SyN registration Parameters ---------- template_path : str File path to the template reference image. fa_path : str File path to the FA moving image. working_dir : str Path to the working directory to perform SyN and save outputs. """ import uuid from time import strftime from dipy.align.imaffine import MutualInformationMetric, AffineRegistration, transform_origins from dipy.align.transforms import TranslationTransform3D, RigidTransform3D, AffineTransform3D from dipy.align.imwarp import SymmetricDiffeomorphicRegistration from dipy.align.metrics import CCMetric from dipy.viz import regtools fa_img = nib.load(fa_path) template_img = nib.load(template_path) static = np.asarray(template_img.dataobj) static_affine = template_img.affine moving = np.asarray(fa_img.dataobj).astype(np.float32) moving_affine = fa_img.affine affine_map = transform_origins(static, static_affine, moving, moving_affine) nbins = 32 sampling_prop = None metric = MutualInformationMetric(nbins, sampling_prop) level_iters = [10, 10, 5] sigmas = [3.0, 1.0, 0.0] factors = [4, 2, 1] affine_reg = AffineRegistration(metric=metric, level_iters=level_iters, sigmas=sigmas, factors=factors) transform = TranslationTransform3D() params0 = None translation = affine_reg.optimize(static, moving, transform, params0, static_affine, moving_affine) transform = RigidTransform3D() rigid_map = affine_reg.optimize(static, moving, transform, params0, static_affine, moving_affine, starting_affine=translation.affine) transform = AffineTransform3D() # We bump up the iterations to get a more exact fit: affine_reg.level_iters = [1000, 1000, 100] affine_opt = affine_reg.optimize(static, moving, transform, params0, static_affine, moving_affine, starting_affine=rigid_map.affine) # We now perform the non-rigid deformation using the Symmetric Diffeomorphic Registration(SyN) Algorithm: metric = CCMetric(3) level_iters = [10, 10, 5] sdr = SymmetricDiffeomorphicRegistration(metric, level_iters) mapping = sdr.optimize(static, moving, static_affine, moving_affine, affine_opt.affine) warped_moving = mapping.transform(moving) # Save warped FA image run_uuid = '%s_%s' % (strftime('%Y%m%d_%H%M%S'), uuid.uuid4()) warped_fa = '{}/warped_fa_{}.nii.gz'.format(working_dir, run_uuid) nib.save(nib.Nifti1Image(warped_moving, affine=static_affine), warped_fa) # We show the registration result with: regtools.overlay_slices( static, warped_moving, None, 0, "Static", "Moving", "%s%s%s%s" % (working_dir, "/transformed_sagittal_", run_uuid, ".png")) regtools.overlay_slices( static, warped_moving, None, 1, "Static", "Moving", "%s%s%s%s" % (working_dir, "/transformed_coronal_", run_uuid, ".png")) regtools.overlay_slices( static, warped_moving, None, 2, "Static", "Moving", "%s%s%s%s" % (working_dir, "/transformed_axial_", run_uuid, ".png")) return mapping, affine_map, warped_fa
def generate_warp_field(self, static, moving, static_axis_units, moving_axis_units): from numpy import eye from dipy.align.imaffine import AffineRegistration from dipy.align.transforms import ( TranslationTransform3D, RigidTransform3D, AffineTransform3D, ) from dipy.align.imwarp import SymmetricDiffeomorphicRegistration as SDR static_g2w = eye(1 + static.ndim) moving_g2w = static_g2w.copy() params0 = None static_g2w[range(static.ndim), range(static.ndim)] = static_axis_units moving_g2w[range(moving.ndim), range(moving.ndim)] = moving_axis_units self.affreg = AffineRegistration( metric=self.metric_lin, level_iters=self.level_iters_lin, sigmas=self.sigmas, factors=self.factors, verbosity=self.verbosity, ss_sigma_factor=self.ss_sigma_factor, ) self.sdreg = SDR( metric=self.metric_syn, level_iters=self.level_iters_syn, ss_sigma_factor=self.ss_sigma_factor, ) self.translation_tx = self.affreg.optimize( static, moving, TranslationTransform3D(), params0, static_g2w, moving_g2w, starting_affine="mass", ) self.rigid_tx = self.affreg.optimize( static, moving, RigidTransform3D(), params0, static_g2w, moving_g2w, starting_affine=self.translation_tx.affine, ) self.affine_tx = self.affreg.optimize( static, moving, AffineTransform3D(), params0, static_g2w, moving_g2w, starting_affine=self.rigid_tx.affine, ) self.sdr_tx = self.sdreg.optimize(static, moving, static_g2w, moving_g2w, self.affine_tx.affine)
class SYNreg(object): """ Wrap full linear + nonlinear(syn) registration, with the assumption that affine params and warp field are estimated from spatially downsampled data. """ def __init__( self, level_iters_lin, sigmas, factors, level_iters_syn, metric_lin=None, metric_syn=None, ss_sigma_factor=1.0, verbosity=0, ): from dipy.align.metrics import CCMetric from dipy.align.imaffine import MutualInformationMetric self.level_iters_lin = level_iters_lin self.sigmas = sigmas self.factors = factors self.level_iters_syn = level_iters_syn self.ss_sigma_factor = ss_sigma_factor self.verbosity = verbosity if metric_lin is None: nbins = 32 self.metric_lin = MutualInformationMetric(nbins, None) if metric_syn is None: self.metric_syn = CCMetric(3) self.affreg = None self.sdreg = None self.translation_tx = None self.rigid_tx = None self.affine_tx = None self.sdr_tx = None def generate_warp_field(self, static, moving, static_axis_units, moving_axis_units): from numpy import eye from dipy.align.imaffine import AffineRegistration from dipy.align.transforms import ( TranslationTransform3D, RigidTransform3D, AffineTransform3D, ) from dipy.align.imwarp import SymmetricDiffeomorphicRegistration as SDR static_g2w = eye(1 + static.ndim) moving_g2w = static_g2w.copy() params0 = None static_g2w[range(static.ndim), range(static.ndim)] = static_axis_units moving_g2w[range(moving.ndim), range(moving.ndim)] = moving_axis_units self.affreg = AffineRegistration( metric=self.metric_lin, level_iters=self.level_iters_lin, sigmas=self.sigmas, factors=self.factors, verbosity=self.verbosity, ss_sigma_factor=self.ss_sigma_factor, ) self.sdreg = SDR( metric=self.metric_syn, level_iters=self.level_iters_syn, ss_sigma_factor=self.ss_sigma_factor, ) self.translation_tx = self.affreg.optimize( static, moving, TranslationTransform3D(), params0, static_g2w, moving_g2w, starting_affine="mass", ) self.rigid_tx = self.affreg.optimize( static, moving, RigidTransform3D(), params0, static_g2w, moving_g2w, starting_affine=self.translation_tx.affine, ) self.affine_tx = self.affreg.optimize( static, moving, AffineTransform3D(), params0, static_g2w, moving_g2w, starting_affine=self.rigid_tx.affine, ) self.sdr_tx = self.sdreg.optimize(static, moving, static_g2w, moving_g2w, self.affine_tx.affine) def apply_transform(self, moving, moving_axis_units, desired_transform): from numpy import eye from numpy.linalg import inv moving_g2w = eye(1 + moving.ndim) moving_g2w[range(moving.ndim), range(moving.ndim)] = moving_axis_units txs = dict(affine=self.affine_tx, sdr=self.sdr_tx) tx = txs[desired_transform] if desired_transform == "sdr": result = tx.transform( moving, image_world2grid=inv(moving_g2w), out_shape=moving.shape, out_grid2world=moving_g2w, ) else: result = tx.transform( moving, image_grid2world=moving_g2w, sampling_grid_shape=moving.shape, sampling_grid2world=moving_g2w, ) return result
import nibabel as nib from dipy.align.imwarp import SymmetricDiffeomorphicRegistration from dipy.align.metrics import CCMetric f_t1 = '/home/eleftherios/Data/reg/t1_fa.nii.gz' f_fa = '/home/eleftherios/Data/reg/fa.nii.gz' t1 = nib.load(f_t1).get_data() img = nib.load(f_fa) fa = img.get_data() fa_aff = img.get_affine() cc = CCMetric(3) sdr = SymmetricDiffeomorphicRegistration(metric=cc) sdr.verbosity = 2 sdm = sdr.optimize(static=fa, moving=t1) t1_warped = sdm.transform(t1) f_t1_warped = '/home/eleftherios/Data/reg/t1_fa_warped.nii.gz' nib.save(nib.Nifti1Image(t1_warped, fa_aff), f_t1_warped)
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
def wm_syn(template_path, fa_path, working_dir): """A function to perform ANTS SyN registration using dipy functions Parameters ---------- template_path : str File path to the template reference FA image. fa_path : str File path to the FA moving image (image to be fitted to reference) working_dir : str Path to the working directory to perform SyN and save outputs. Returns ------- DiffeomorphicMap An object that can be used to register images back and forth between static (template) and moving (FA) domains AffineMap An object used to transform the moving (FA) image towards the static image (template) """ fa_img = nib.load(fa_path) template_img = nib.load(template_path) static = template_img.get_data() static_affine = template_img.affine moving = fa_img.get_data().astype(np.float32) moving_affine = fa_img.affine affine_map = transform_origins(static, static_affine, moving, moving_affine) nbins = 32 sampling_prop = None metric = MutualInformationMetric(nbins, sampling_prop) level_iters = [10, 10, 5] sigmas = [3.0, 1.0, 0.0] factors = [4, 2, 1] affine_reg = AffineRegistration(metric=metric, level_iters=level_iters, sigmas=sigmas, factors=factors) transform = TranslationTransform3D() params0 = None translation = affine_reg.optimize(static, moving, transform, params0, static_affine, moving_affine) transform = RigidTransform3D() rigid_map = affine_reg.optimize( static, moving, transform, params0, static_affine, moving_affine, starting_affine=translation.affine, ) transform = AffineTransform3D() # We bump up the iterations to get a more exact fit: affine_reg.level_iters = [1000, 1000, 100] affine_opt = affine_reg.optimize( static, moving, transform, params0, static_affine, moving_affine, starting_affine=rigid_map.affine, ) # We now perform the non-rigid deformation using the Symmetric Diffeomorphic Registration(SyN) Algorithm: metric = CCMetric(3) level_iters = [10, 10, 5] sdr = SymmetricDiffeomorphicRegistration(metric, level_iters) mapping = sdr.optimize(static, moving, static_affine, moving_affine, affine_opt.affine) warped_moving = mapping.transform(moving) # We show the registration result with: regtools.overlay_slices( static, warped_moving, None, 0, "Static", "Moving", f"{working_dir}/transformed_sagittal.png", ) regtools.overlay_slices( static, warped_moving, None, 1, "Static", "Moving", f"{working_dir}/transformed_coronal.png", ) regtools.overlay_slices( static, warped_moving, None, 2, "Static", "Moving", f"{working_dir}/transformed_axial.png", ) return mapping, affine_map
def ROI_registration(datapath, template, t1, b0, roi): t1_path = datapath + '/' + t1 b0_path = datapath + '/' + b0 roi_path = datapath + '/' + roi template_path = datapath + '/' + template template_img, template_affine = load_nifti(template_path) t1_img, t1_affine = load_nifti(t1_path) b0_img, b0_affine = load_nifti(b0_path) roi_img, roi_affine = load_nifti(roi_path) #diff2struct affine registartion moving = b0_img moving_grid2world = b0_affine static = t1_img static_grid2world = t1_affine affine_path = datapath + '/' + 'diff2struct_affine.mat' nbins = 32 sampling_prop = None metric = MutualInformationMetric(nbins, sampling_prop) sigmas = [3.0, 1.0, 0.0] level_iters = [10000, 1000, 100] factors = [4, 2, 1] affreg_diff2struct = AffineRegistration(metric=metric, level_iters=level_iters, sigmas=sigmas, factors=factors) transform = AffineTransform3D() params0 = None affine_diff2struct = affreg_diff2struct.optimize(static, moving, transform, params0, static_grid2world, moving_grid2world, starting_affine=None) saveAffineMat(affine_diff2struct, affine_path) # struct2standard affine registartion moving = t1_img moving_grid2world = t1_affine static = template_img static_grid2world = template_affine nbins = 32 sampling_prop = None metric = MutualInformationMetric(nbins, sampling_prop) sigmas = [3.0, 1.0, 0.0] level_iters = [10000, 1000, 100] factors = [4, 2, 1] affreg_struct2standard = AffineRegistration(metric=metric, level_iters=level_iters, sigmas=sigmas, factors=factors) transform = AffineTransform3D() params0 = None affine_struct2standard = affreg_struct2standard.optimize( static, moving, transform, params0, static_grid2world, moving_grid2world, starting_affine=None) # struct2standard SyN registartion pre_align = affine_struct2standard.get_affine() metric = CCMetric(3) level_iters = [10, 10, 5] sdr = SymmetricDiffeomorphicRegistration(metric, level_iters) mapping = sdr.optimize(static, moving, static_grid2world, moving_grid2world, pre_align) warped = mapping.transform_inverse(template_img) warped = affine_diff2struct.transform_inverse(warped) template_diff_path = datapath + '/' + 'MNI152_diff' save_nifti(template_diff_path, warped, b0_affine) warped_roi = mapping.transform_inverse(roi_img) warped_roi = affine_diff2struct.transform_inverse(warped_roi) roi_diff_path = datapath + '/' + roi + '_diff.nii.gz' save_nifti(roi_diff_path, warped_roi, b0_affine) print(" Done! ")
def wm_syn(t1w_brain, ap_path, working_dir, fa_path=None, template_fa_path=None): """ A function to perform SyN registration Parameters ---------- t1w_brain : str File path to the skull-stripped T1w brain Nifti1Image. ap_path : str File path to the AP moving image. working_dir : str Path to the working directory to perform SyN and save outputs. fa_path : str File path to the FA moving image. template_fa_path : str File path to the T1w-connformed template FA reference image. """ import uuid from time import strftime from dipy.align.imaffine import ( MutualInformationMetric, AffineRegistration, transform_origins, ) from dipy.align.transforms import ( TranslationTransform3D, RigidTransform3D, AffineTransform3D, ) from dipy.align.imwarp import SymmetricDiffeomorphicRegistration from dipy.align.metrics import CCMetric # from dipy.viz import regtools # from nilearn.image import resample_to_img ap_img = nib.load(ap_path) t1w_brain_img = nib.load(t1w_brain) static = np.asarray(t1w_brain_img.dataobj, dtype=np.float32) static_affine = t1w_brain_img.affine moving = np.asarray(ap_img.dataobj, dtype=np.float32) moving_affine = ap_img.affine affine_map = transform_origins(static, static_affine, moving, moving_affine) nbins = 32 sampling_prop = None metric = MutualInformationMetric(nbins, sampling_prop) level_iters = [10, 10, 5] sigmas = [3.0, 1.0, 0.0] factors = [4, 2, 1] affine_reg = AffineRegistration(metric=metric, level_iters=level_iters, sigmas=sigmas, factors=factors) transform = TranslationTransform3D() params0 = None translation = affine_reg.optimize(static, moving, transform, params0, static_affine, moving_affine) transform = RigidTransform3D() rigid_map = affine_reg.optimize( static, moving, transform, params0, static_affine, moving_affine, starting_affine=translation.affine, ) transform = AffineTransform3D() # We bump up the iterations to get a more exact fit: affine_reg.level_iters = [1000, 1000, 100] affine_opt = affine_reg.optimize( static, moving, transform, params0, static_affine, moving_affine, starting_affine=rigid_map.affine, ) # We now perform the non-rigid deformation using the Symmetric # Diffeomorphic Registration(SyN) Algorithm: metric = CCMetric(3) level_iters = [10, 10, 5] # Refine fit if template_fa_path is not None: from nilearn.image import resample_to_img fa_img = nib.load(fa_path) template_img = nib.load(template_fa_path) template_img_res = resample_to_img(template_img, t1w_brain_img) static = np.asarray(template_img_res.dataobj, dtype=np.float32) static_affine = template_img_res.affine moving = np.asarray(fa_img.dataobj, dtype=np.float32) moving_affine = fa_img.affine else: static = np.asarray(t1w_brain_img.dataobj, dtype=np.float32) static_affine = t1w_brain_img.affine moving = np.asarray(ap_img.dataobj, dtype=np.float32) moving_affine = ap_img.affine sdr = SymmetricDiffeomorphicRegistration(metric, level_iters) mapping = sdr.optimize(static, moving, static_affine, moving_affine, affine_opt.affine) warped_moving = mapping.transform(moving) # Save warped FA image run_uuid = f"{strftime('%Y%m%d_%H%M%S')}_{uuid.uuid4()}" warped_fa = f"{working_dir}/warped_fa_{run_uuid}.nii.gz" nib.save(nib.Nifti1Image(warped_moving, affine=static_affine), warped_fa) # # We show the registration result with: # regtools.overlay_slices(static, warped_moving, None, 0, # "Static", "Moving", # "%s%s%s%s" % (working_dir, # "/transformed_sagittal_", run_uuid, ".png")) # regtools.overlay_slices(static, warped_moving, None, # 1, "Static", "Moving", # "%s%s%s%s" % (working_dir, # "/transformed_coronal_", run_uuid, ".png")) # regtools.overlay_slices(static, warped_moving, # None, 2, "Static", "Moving", # "%s%s%s%s" % (working_dir, # "/transformed_axial_", run_uuid, ".png")) return mapping, affine_map, warped_fa
img = nib.load(ffa) fa = img.get_data() ffa_template = '/usr/share/data/fsl-mni152-templates/FMRIB58_FA_1mm.nii.gz' img = nib.load(ffa_template) fa_template = img.get_data() fa = np.interp(fa, [fa.min(), fa.max()], [fa_template.min(), fa_template.max()]) from dipy.align.imwarp import SymmetricDiffeomorphicRegistration from dipy.align.metrics import CCMetric cc = CCMetric(3) sdr = SymmetricDiffeomorphicRegistration(metric=cc) sdr.verbosity = 2 sdm = sdr.optimize(static=fa_template, moving=fa) fa_warped = sdm.transform(fa) ffa_warped = '/home/eleftherios/Data/reg/fa_to_template_warped.nii.gz' nib.save(nib.Nifti1Image(fa_warped, img.get_affine()), ffa_warped)
hardi_affine = ni.get_affine() b0 = hardi_data[..., gtab.b0s_mask] mean_b0 = np.mean(b0, -1) ni_b0 = nib.Nifti1Image(mean_b0, hardi_affine) ni_b0.to_filename('mean_b0.nii') plt.matshow(mean_b0[:, :, mean_b0.shape[-1] // 2], cmap=cm.bone) MNI_T2 = dpd.read_mni_template() MNI_T2_data = MNI_T2.get_data() MNI_T2_affine = MNI_T2.get_affine() level_iters = [10, 10, 5] dim = 3 metric = CCMetric(dim) sdr = SymmetricDiffeomorphicRegistration(metric, level_iters, step_length=0.25) sdr.verbosity = VerbosityLevels.DIAGNOSE mapping = sdr.optimize(MNI_T2_data, mean_b0, MNI_T2_affine, hardi_affine) warped_b0 = mapping.transform(mean_b0) plt.matshow(warped_b0[:, :, warped_b0.shape[-1] // 2], cmap=cm.bone) plt.matshow(MNI_T2_data[:, :, MNI_T2_data.shape[-1] // 2], cmap=cm.bone) new_ni = nib.Nifti1Image(warped_b0, MNI_T2_affine) new_ni.to_filename('./warped_b0.nii.gz') afqpath = 'D:/opt/AFQ/' LOCC_ni = nib.load( os.path.join(afqpath, 'templates/callosum2/L_Occipital.nii.gz')) ROCC_ni = nib.load( os.path.join(afqpath, 'templates/callosum2/R_Occipital.nii.gz')) midsag_ni = nib.load(
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) # Start diffeomorphic registration diff_name = "ibsr1_to_brainweb_diff.p" if os.path.isfile(diff_name): ibsr_bw_diffmap = pickle.load(open(diff_name, "r")) else: metric = CCMetric(3) level_iters = [50, 10] sdr = SymmetricDiffeomorphicRegistration(metric, level_iters) sdr.verbosity = VerbosityLevels.DEBUG ibsr_bw_diffmap = sdr.optimize(ibsr1, brainweb, ibsr1_affine, brainweb_affine, ibsr_bw_affmap.affine) pickle.dump(ibsr_bw_diffmap, open(diff_name, "w")) bw_warped_ibsr1 = ibsr_bw_diffmap.transform(brainweb) rt.overlay_slices(ibsr1, bw_warped_ibsr1, slice_type=0) # warped (sagital view) rt.overlay_slices(ibsr1, bw_warped_ibsr1, slice_type=1) # warped (axial view) rt.overlay_slices(ibsr1, bw_warped_ibsr1, slice_type=2) # warped (coronal view) # Now the initial segmentation bw_mask_ibsr1 = ibsr_bw_diffmap.transform(brainweb_mask) bw_mask_ibsr1 = bw_mask_ibsr1 > 0 # Dilate structure = np.ones((5, 5, 5))
def run(self, static_image_files, moving_image_files, prealign_file='', inv_static=False, level_iters=[10, 10, 5], metric="cc", mopt_sigma_diff=2.0, mopt_radius=4, mopt_smooth=0.0, mopt_inner_iter=0.0, mopt_q_levels=256, mopt_double_gradient=True, mopt_step_type='', step_length=0.25, ss_sigma_factor=0.2, opt_tol=1e-5, inv_iter=20, inv_tol=1e-3, out_dir='', out_warped='warped_moved.nii.gz', out_inv_static='inc_static.nii.gz', out_field='displacement_field.nii.gz'): """ Parameters ---------- static_image_files : string Path of the static image file. moving_image_files : string Path to the moving image file. prealign_file : string, optional The text file containing pre alignment information via an affine matrix. inv_static : boolean, optional Apply the inverse mapping to the static image (default 'False'). level_iters : variable int, optional The number of iterations at each level of the gaussian pyramid. By default, a 3-level scale space with iterations sequence equal to [10, 10, 5] will be used. The 0-th level corresponds to the finest resolution. metric : string, optional The metric to be used (Default cc, 'Cross Correlation metric'). metric available: cc (Cross Correlation), ssd (Sum Squared Difference), em (Expectation-Maximization). mopt_sigma_diff : float, optional Metric option applied on Cross correlation (CC). The standard deviation of the Gaussian smoothing kernel to be applied to the update field at each iteration (default 2.0) mopt_radius : int, optional Metric option applied on Cross correlation (CC). the radius of the squared (cubic) neighborhood at each voxel to be considered to compute the cross correlation. (default 4) mopt_smooth : float, optional Metric option applied on Sum Squared Difference (SSD) and Expectation Maximization (EM). Smoothness parameter, the larger the value the smoother the deformation field. (default 1.0 for EM, 4.0 for SSD) mopt_inner_iter : int, optional Metric option applied on Sum Squared Difference (SSD) and Expectation Maximization (EM). This is number of iterations to be performed at each level of the multi-resolution Gauss-Seidel optimization algorithm (this is not the number of steps per Gaussian Pyramid level, that parameter must be set for the optimizer, not the metric). Default 5 for EM, 10 for SSD. mopt_q_levels : int, optional Metric option applied on Expectation Maximization (EM). Number of quantization levels (Default: 256 for EM) mopt_double_gradient : bool, optional Metric option applied on Expectation Maximization (EM). if True, the gradient of the expected static image under the moving modality will be added to the gradient of the moving image, similarly, the gradient of the expected moving image under the static modality will be added to the gradient of the static image. mopt_step_type : string, optional Metric option applied on Sum Squared Difference (SSD) and Expectation Maximization (EM). The optimization schedule to be used in the multi-resolution Gauss-Seidel optimization algorithm (not used if Demons Step is selected). Possible value: ('gauss_newton', 'demons'). default: 'gauss_newton' for EM, 'demons' for SSD. step_length : float, optional the length of the maximum displacement vector of the update displacement field at each iteration. ss_sigma_factor : float, optional parameter of the scale-space smoothing kernel. For example, the std. dev. of the kernel will be factor*(2^i) in the isotropic case where i = 0, 1, ..., n_scales is the scale. opt_tol : float, optional the optimization will stop when the estimated derivative of the energy profile w.r.t. time falls below this threshold. inv_iter : int, optional the number of iterations to be performed by the displacement field inversion algorithm. inv_tol : float, optional the displacement field inversion algorithm will stop iterating when the inversion error falls below this threshold. out_dir : string, optional Directory to save the transformed files (default ''). out_warped : string, optional Name of the warped file. (default 'warped_moved.nii.gz'). out_inv_static : string, optional Name of the file to save the static image after applying the inverse mapping (default 'inv_static.nii.gz'). out_field : string, optional Name of the file to save the diffeomorphic map. (default 'displacement_field.nii.gz') """ io_it = self.get_io_iterator() metric = metric.lower() if metric not in ['ssd', 'cc', 'em']: raise ValueError("Invalid similarity metric: Please" " provide a valid metric like 'ssd', 'cc', 'em'") logging.info("Starting Diffeormorphic Registration") logging.info('Using {0} Metric'.format(metric.upper())) # Init parameter if they are not setup init_param = {'ssd': {'mopt_smooth': 4.0, 'mopt_inner_iter': 10, 'mopt_step_type': 'demons' }, 'em': {'mopt_smooth': 1.0, 'mopt_inner_iter': 5, 'mopt_step_type': 'gauss_newton' } } mopt_smooth = mopt_smooth or init_param[metric]['mopt_smooth'] mopt_inner_iter = mopt_inner_iter or \ init_param[metric]['mopt_inner_iter'] mopt_step_type = mopt_step_type or \ init_param[metric]['mopt_step_type'] for (static_file, moving_file, owarped_file, oinv_static_file, omap_file) in io_it: logging.info('Loading static file {0}'.format(static_file)) logging.info('Loading moving file {0}'.format(moving_file)) # Loading the image data from the input files into object. static_image, static_grid2world = load_nifti(static_file) moving_image, moving_grid2world = load_nifti(moving_file) # Sanity check for the input image dimensions. check_dimensions(static_image, moving_image) # Loading the affine matrix. prealign = np.loadtxt(prealign_file) if prealign_file else None l_metric = {"ssd": SSDMetric(static_image.ndim, smooth=mopt_smooth, inner_iter=mopt_inner_iter, step_type=mopt_step_type ), "cc": CCMetric(static_image.ndim, sigma_diff=mopt_sigma_diff, radius=mopt_radius), "em": EMMetric(static_image.ndim, smooth=mopt_smooth, inner_iter=mopt_inner_iter, step_type=mopt_step_type, q_levels=mopt_q_levels, double_gradient=mopt_double_gradient) } current_metric = l_metric.get(metric.lower()) sdr = SymmetricDiffeomorphicRegistration( metric=current_metric, level_iters=level_iters, step_length=step_length, ss_sigma_factor=ss_sigma_factor, opt_tol=opt_tol, inv_iter=inv_iter, inv_tol=inv_tol ) mapping = sdr.optimize(static_image, moving_image, static_grid2world, moving_grid2world, prealign) mapping_data = np.array([mapping.forward.T, mapping.backward.T]).T warped_moving = mapping.transform(moving_image) # Saving logging.info('Saving warped {0}'.format(owarped_file)) save_nifti(owarped_file, warped_moving, static_grid2world) logging.info('Saving Diffeormorphic map {0}'.format(omap_file)) save_nifti(omap_file, mapping_data, mapping.codomain_world2grid)
def register_save(inputpathdir, target_path, subject, outputpath, figspath, params, registration_types, applydirs, verbose): anat_path = get_anat(inputpathdir, subject) #myanat = load_nifti(anat_path) myanat = nib.load(anat_path) anat_data = np.squeeze(myanat.get_data()[..., 0]) anat_affine = myanat.affine anat_hdr = myanat.header vox_size = myanat.header.get_zooms()[0] #mynifti = load_nifti("/Volumes/Data/Badea/Lab/19abb14/N57437_nii4D.nii") #anat_data = np.squeeze(myanat[0])[..., 0] #anat_affine = myanat[1] #hdr = myanat.header mytarget = nib.load(target_path) target_data = np.squeeze(mytarget.get_data()[..., 0]) target_affine = mytarget.affine identity = np.eye(4) affine_map = AffineMap(identity, target_data.shape, target_affine, anat_data.shape, anat_affine) resampled = affine_map.transform(anat_data) """ regtools.overlay_slices(target_data, resampled, None, 0, "target_data", "anat_data", figspath + "resampled_0.png") regtools.overlay_slices(target_data, resampled, None, 1, "target_data", "anat_data", figspath + "resampled_1.png") regtools.overlay_slices(target_data, resampled, None, 2, "target_data", "anat_data", figspath + "resampled_2.png") """ c_of_mass = transform_centers_of_mass(target_data, target_affine, anat_data, anat_affine) apply_niftis = [] apply_trks = [] if inputpathdir in applydirs: applyfiles = [anat_path] else: applyfiles = [] for applydir in applydirs: apply_niftis.extend(get_niftis(applydir, subject)) apply_trks.extend(get_trks(applydir, subject)) if "center_mass" in registration_types: if apply_trks: metric = CCMetric(3) level_iters = [10, 10, 5] sdr = SymmetricDiffeomorphicRegistration(metric, level_iters) mapping = sdr.optimize(target_data, anat_data, target_affine, anat_affine, c_of_mass.affine) for apply_nifti in apply_niftis: fname = os.path.basename(apply_nifti).split(".")[0] fpath = outputpath + fname + "_centermass.nii" applynii = nib.load(apply_nifti) apply_data = applynii.get_data() apply_affine = applynii.affine apply_hdr = myanat.header if len(np.shape(apply_data)) == 4: transformed_all = c_of_mass.transform(apply_data, apply4D=True) transformed = transformed_all[:, :, :, 0] else: transformed_all = c_of_mass.transform(apply_data) transformed = transformed_all save_nifti(fpath, transformed_all, apply_affine, hdr=apply_hdr) if figspath is not None: regtools.overlay_slices(target_data, transformed, None, 0, "target_data", "Transformed", figspath + fname + "_centermass_1.png") regtools.overlay_slices(target_data, transformed, None, 1, "target_data", "Transformed", figspath + fname + "_centermass_2.png") regtools.overlay_slices(target_data, transformed, None, 2, "target_data", "Transformed", figspath + fname + "_centermass_3.png") if verbose: print("Saved the file at " + fpath) #mapping = sdr.optimize(target_data, anat_data, target_affine, anat_affine, # c_of_mass.affine) #warped_moving = mapping.transform(anat_data) for apply_trk in apply_trks: fname = os.path.basename(apply_trk).split(".")[0] fpath = outputpath + fname + "_centermass.trk" sft = load_tractogram(apply_trk, 'same') target_isocenter = np.diag( np.array([-vox_size, vox_size, vox_size, 1])) origin_affine = affine_map.affine.copy() origin_affine[0][3] = -origin_affine[0][3] origin_affine[1][3] = -origin_affine[1][3] origin_affine[2][3] = origin_affine[2][3] / vox_size origin_affine[1][3] = origin_affine[1][3] / vox_size**2 # Apply the deformation and correct for the extents mni_streamlines = deform_streamlines( sft.streamlines, deform_field=mapping.get_forward_field(), stream_to_current_grid=target_isocenter, current_grid_to_world=origin_affine, stream_to_ref_grid=target_isocenter, ref_grid_to_world=np.eye(4)) if has_fury: show_template_bundles(mni_streamlines, anat_data, show=False, fname=figspath + fname + '_streamlines_centermass.png') sft = StatefulTractogram(mni_streamlines, myanat, Space.RASMM) save_tractogram(sft, fpath, bbox_valid_check=False) if verbose: print("Saved the file at " + fpath) metric = MutualInformationMetric(params.nbins, params.sampling_prop) if "AffineRegistration" in registration_types: affreg = AffineRegistration(metric=metric, level_iters=params.level_iters, sigmas=params.sigmas, factors=params.factors) transform = TranslationTransform3D() params0 = None starting_affine = c_of_mass.affine translation = affreg.optimize(target_data, anat_data, transform, params0, target_affine, anat_affine, starting_affine=starting_affine) if apply_trks: metric = CCMetric(3) level_iters = [10, 10, 5] sdr = SymmetricDiffeomorphicRegistration(metric, level_iters) mapping = sdr.optimize(target_data, anat_data, target_affine, anat_affine, translation.affine) for apply_nifti in apply_niftis: fname = os.path.basename(apply_nifti).split(".")[0] fpath = outputpath + fname + "_affinereg.nii" applynii = nib.load(apply_nifti) apply_data = applynii.get_data() apply_affine = applynii.affine apply_hdr = myanat.header if len(np.shape(apply_data)) == 4: transformed_all = translation.transform(apply_data, apply4D=True) transformed = transformed_all[:, :, :, 0] else: transformed_all = translation.transform(apply_data) transformed = transformed_all save_nifti(fpath, transformed_all, anat_affine, hdr=anat_hdr) if figspath is not None: regtools.overlay_slices(target_data, transformed, None, 0, "target_data", "Transformed", figspath + fname + "_affinereg_1.png") regtools.overlay_slices(target_data, transformed, None, 1, "target_data", "Transformed", figspath + fname + "_affinereg_2.png") regtools.overlay_slices(target_data, transformed, None, 2, "target_data", "Transformed", figspath + fname + "_affinereg_3.png") if verbose: print("Saved the file at " + fpath) for apply_trk in apply_trks: fname = os.path.basename(apply_trk).split(".")[0] fpath = outputpath + fname + "_affinereg.trk" sft = load_tractogram(apply_trk, 'same') target_isocenter = np.diag( np.array([-vox_size, vox_size, vox_size, 1])) origin_affine = affine_map.affine.copy() origin_affine[0][3] = -origin_affine[0][3] origin_affine[1][3] = -origin_affine[1][3] origin_affine[2][3] = origin_affine[2][3] / vox_size origin_affine[1][3] = origin_affine[1][3] / vox_size**2 # Apply the deformation and correct for the extents mni_streamlines = deform_streamlines( sft.streamlines, deform_field=mapping.get_forward_field(), stream_to_current_grid=target_isocenter, current_grid_to_world=origin_affine, stream_to_ref_grid=target_isocenter, ref_grid_to_world=np.eye(4)) if has_fury: show_template_bundles(mni_streamlines, anat_data, show=False, fname=figspath + fname + '_streamlines_affinereg.png') sft = StatefulTractogram(mni_streamlines, myanat, Space.RASMM) save_tractogram(sft, fpath, bbox_valid_check=False) if verbose: print("Saved the file at " + fpath) if "RigidTransform3D" in registration_types: transform = RigidTransform3D() params0 = None if 'translation' not in locals(): affreg = AffineRegistration(metric=metric, level_iters=params.level_iters, sigmas=params.sigmas, factors=params.factors) translation = affreg.optimize(target_data, anat_data, transform, params0, target_affine, anat_affine, starting_affine=c_of_mass.affine) starting_affine = translation.affine rigid = affreg.optimize(target_data, anat_data, transform, params0, target_affine, anat_affine, starting_affine=starting_affine) transformed = rigid.transform(anat_data) if apply_trks: metric = CCMetric(3) level_iters = [10, 10, 5] sdr = SymmetricDiffeomorphicRegistration(metric, level_iters) mapping = sdr.optimize(target_data, anat_data, target_affine, anat_affine, rigid.affine) for apply_nifti in apply_niftis: fname = os.path.basename(apply_nifti).split(".")[0] fpath = outputpath + fname + "_rigidtransf3d.nii" applynii = nib.load(apply_nifti) apply_data = applynii.get_data() apply_affine = applynii.affine apply_hdr = myanat.header if len(np.shape(apply_data)) == 4: transformed_all = rigid.transform(apply_data, apply4D=True) transformed = transformed_all[:, :, :, 0] else: transformed_all = rigid.transform(apply_data) transformed = transformed_all save_nifti(fpath, transformed_all, anat_affine, hdr=anat_hdr) if figspath is not None: regtools.overlay_slices( target_data, transformed, None, 0, "target_data", "Transformed", figspath + fname + "_rigidtransf3d_1.png") regtools.overlay_slices( target_data, transformed, None, 1, "target_data", "Transformed", figspath + fname + "_rigidtransf3d_2.png") regtools.overlay_slices( target_data, transformed, None, 2, "target_data", "Transformed", figspath + fname + "_rigidtransf3d_3.png") if verbose: print("Saved the file at " + fpath) for apply_trk in apply_trks: fname = os.path.basename(apply_trk).split(".")[0] fpath = outputpath + fname + "_rigidtransf3d.trk" sft = load_tractogram(apply_trk, 'same') target_isocenter = np.diag( np.array([-vox_size, vox_size, vox_size, 1])) origin_affine = affine_map.affine.copy() origin_affine[0][3] = -origin_affine[0][3] origin_affine[1][3] = -origin_affine[1][3] origin_affine[2][3] = origin_affine[2][3] / vox_size origin_affine[1][3] = origin_affine[1][3] / vox_size**2 # Apply the deformation and correct for the extents mni_streamlines = deform_streamlines( sft.streamlines, deform_field=mapping.get_forward_field(), stream_to_current_grid=target_isocenter, current_grid_to_world=origin_affine, stream_to_ref_grid=target_isocenter, ref_grid_to_world=np.eye(4)) if has_fury: show_template_bundles(mni_streamlines, anat_data, show=False, fname=figspath + fname + '_rigidtransf3d.png') sft = StatefulTractogram(mni_streamlines, myanat, Space.RASMM) save_tractogram(sft, fpath, bbox_valid_check=False) if verbose: print("Saved the file at " + fpath) if "AffineTransform3D" in registration_types: transform = AffineTransform3D() params0 = None starting_affine = rigid.affine affine = affreg.optimize(target_data, anat_data, transform, params0, target_affine, anat_affine, starting_affine=starting_affine) transformed = affine.transform(anat_data) if apply_trks: metric = CCMetric(3) level_iters = [10, 10, 5] sdr = SymmetricDiffeomorphicRegistration(metric, level_iters) mapping = sdr.optimize(target_data, anat_data, target_affine, anat_affine, affine.affine) for apply_nifti in apply_niftis: fname = os.path.basename(apply_nifti).split(".")[0] fpath = outputpath + fname + "_affinetransf3d.nii" applynii = nib.load(apply_nifti) apply_data = applynii.get_data() apply_affine = applynii.affine apply_hdr = myanat.header if len(np.shape(apply_data)) == 4: transformed_all = affine.transform(apply_data, apply4D=True) transformed = transformed_all[:, :, :, 0] else: transformed_all = affine.transform(apply_data) transformed = transformed_all save_nifti(fpath, transformed_all, anat_affine, hdr=anat_hdr) if figspath is not None: regtools.overlay_slices( target_data, transformed, None, 0, "target_data", "Transformed", figspath + fname + "_affinetransf3d_1.png") regtools.overlay_slices( target_data, transformed, None, 1, "target_data", "Transformed", figspath + fname + "_affinetransf3d_2.png") regtools.overlay_slices( target_data, transformed, None, 2, "target_data", "Transformed", figspath + fname + "_affinetransf3d_3.png") if verbose: print("Saved the file at " + fpath) for apply_trk in apply_trks: fname = os.path.basename(apply_trk).split(".")[0] fpath = outputpath + fname + "_affinetransf3d.trk" sft = load_tractogram(apply_trk, 'same') target_isocenter = np.diag( np.array([-vox_size, vox_size, vox_size, 1])) origin_affine = affine_map.affine.copy() origin_affine[0][3] = -origin_affine[0][3] origin_affine[1][3] = -origin_affine[1][3] origin_affine[2][3] = origin_affine[2][3] / vox_size origin_affine[1][3] = origin_affine[1][3] / vox_size**2 # Apply the deformation and correct for the extents mni_streamlines = deform_streamlines( sft.streamlines, deform_field=mapping.get_forward_field(), stream_to_current_grid=target_isocenter, current_grid_to_world=origin_affine, stream_to_ref_grid=target_isocenter, ref_grid_to_world=np.eye(4)) if has_fury: show_template_bundles(mni_streamlines, anat_data, show=False, fname=figspath + fname + '_streamlines_affinetransf3d.png') sft = StatefulTractogram(mni_streamlines, myanat, Space.RASMM) save_tractogram(sft, fpath, bbox_valid_check=False) if verbose: print("Saved the file at " + fpath)
def run(self, static_image_files, moving_image_files, prealign_file='', inv_static=False, level_iters=[10, 10, 5], metric="cc", mopt_sigma_diff=2.0, mopt_radius=4, mopt_smooth=0.0, mopt_inner_iter=0.0, mopt_q_levels=256, mopt_double_gradient=True, mopt_step_type='', step_length=0.25, ss_sigma_factor=0.2, opt_tol=1e-5, inv_iter=20, inv_tol=1e-3, out_dir='', out_warped='warped_moved.nii.gz', out_inv_static='inc_static.nii.gz', out_field='displacement_field.nii.gz'): """ Parameters ---------- static_image_files : string Path of the static image file. moving_image_files : string Path to the moving image file. prealign_file : string, optional The text file containing pre alignment information via an affine matrix. inv_static : boolean, optional Apply the inverse mapping to the static image (default 'False'). level_iters : variable int, optional The number of iterations at each level of the gaussian pyramid. By default, a 3-level scale space with iterations sequence equal to [10, 10, 5] will be used. The 0-th level corresponds to the finest resolution. metric : string, optional The metric to be used (Default cc, 'Cross Correlation metric'). metric available: cc (Cross Correlation), ssd (Sum Squared Difference), em (Expectation-Maximization). mopt_sigma_diff : float, optional Metric option applied on Cross correlation (CC). The standard deviation of the Gaussian smoothing kernel to be applied to the update field at each iteration (default 2.0) mopt_radius : int, optional Metric option applied on Cross correlation (CC). the radius of the squared (cubic) neighborhood at each voxel to be considered to compute the cross correlation. (default 4) mopt_smooth : float, optional Metric option applied on Sum Squared Difference (SSD) and Expectation Maximization (EM). Smoothness parameter, the larger the value the smoother the deformation field. (default 1.0 for EM, 4.0 for SSD) mopt_inner_iter : int, optional Metric option applied on Sum Squared Difference (SSD) and Expectation Maximization (EM). This is number of iterations to be performed at each level of the multi-resolution Gauss-Seidel optimization algorithm (this is not the number of steps per Gaussian Pyramid level, that parameter must be set for the optimizer, not the metric). Default 5 for EM, 10 for SSD. mopt_q_levels : int, optional Metric option applied on Expectation Maximization (EM). Number of quantization levels (Default: 256 for EM) mopt_double_gradient : bool, optional Metric option applied on Expectation Maximization (EM). if True, the gradient of the expected static image under the moving modality will be added to the gradient of the moving image, similarly, the gradient of the expected moving image under the static modality will be added to the gradient of the static image. mopt_step_type : string, optional Metric option applied on Sum Squared Difference (SSD) and Expectation Maximization (EM). The optimization schedule to be used in the multi-resolution Gauss-Seidel optimization algorithm (not used if Demons Step is selected). Possible value: ('gauss_newton', 'demons'). default: 'gauss_newton' for EM, 'demons' for SSD. step_length : float, optional the length of the maximum displacement vector of the update displacement field at each iteration. ss_sigma_factor : float, optional parameter of the scale-space smoothing kernel. For example, the std. dev. of the kernel will be factor*(2^i) in the isotropic case where i = 0, 1, ..., n_scales is the scale. opt_tol : float, optional the optimization will stop when the estimated derivative of the energy profile w.r.t. time falls below this threshold. inv_iter : int, optional the number of iterations to be performed by the displacement field inversion algorithm. inv_tol : float, optional the displacement field inversion algorithm will stop iterating when the inversion error falls below this threshold. out_dir : string, optional Directory to save the transformed files (default ''). out_warped : string, optional Name of the warped file. (default 'warped_moved.nii.gz'). out_inv_static : string, optional Name of the file to save the static image after applying the inverse mapping (default 'inv_static.nii.gz'). out_field : string, optional Name of the file to save the diffeomorphic map. (default 'displacement_field.nii.gz') """ io_it = self.get_io_iterator() metric = metric.lower() if metric not in ['ssd', 'cc', 'em']: raise ValueError("Invalid similarity metric: Please" " provide a valid metric like 'ssd', 'cc', 'em'") logging.info("Starting Diffeomorphic Registration") logging.info('Using {0} Metric'.format(metric.upper())) # Init parameter if they are not setup init_param = { 'ssd': { 'mopt_smooth': 4.0, 'mopt_inner_iter': 10, 'mopt_step_type': 'demons' }, 'em': { 'mopt_smooth': 1.0, 'mopt_inner_iter': 5, 'mopt_step_type': 'gauss_newton' } } mopt_smooth = mopt_smooth or init_param[metric]['mopt_smooth'] mopt_inner_iter = mopt_inner_iter or \ init_param[metric]['mopt_inner_iter'] mopt_step_type = mopt_step_type or \ init_param[metric]['mopt_step_type'] for (static_file, moving_file, owarped_file, oinv_static_file, omap_file) in io_it: logging.info('Loading static file {0}'.format(static_file)) logging.info('Loading moving file {0}'.format(moving_file)) # Loading the image data from the input files into object. static_image, static_grid2world = load_nifti(static_file) moving_image, moving_grid2world = load_nifti(moving_file) # Sanity check for the input image dimensions. check_dimensions(static_image, moving_image) # Loading the affine matrix. prealign = np.loadtxt(prealign_file) if prealign_file else None l_metric = { "ssd": SSDMetric(static_image.ndim, smooth=mopt_smooth, inner_iter=mopt_inner_iter, step_type=mopt_step_type), "cc": CCMetric(static_image.ndim, sigma_diff=mopt_sigma_diff, radius=mopt_radius), "em": EMMetric(static_image.ndim, smooth=mopt_smooth, inner_iter=mopt_inner_iter, step_type=mopt_step_type, q_levels=mopt_q_levels, double_gradient=mopt_double_gradient) } current_metric = l_metric.get(metric.lower()) sdr = SymmetricDiffeomorphicRegistration( metric=current_metric, level_iters=level_iters, step_length=step_length, ss_sigma_factor=ss_sigma_factor, opt_tol=opt_tol, inv_iter=inv_iter, inv_tol=inv_tol) mapping = sdr.optimize(static_image, moving_image, static_grid2world, moving_grid2world, prealign) mapping_data = np.array([mapping.forward.T, mapping.backward.T]).T warped_moving = mapping.transform(moving_image) # Saving logging.info('Saving warped {0}'.format(owarped_file)) save_nifti(owarped_file, warped_moving, static_grid2world) logging.info('Saving Diffeomorphic map {0}'.format(omap_file)) save_nifti(omap_file, mapping_data, mapping.codomain_world2grid)
-ref ' + template_path + ' \ -out ' + input_skull_flirted_path + ' \ -init ' + input_flirt_path + ' \ -verbose 0') input_skull_flirted_image = nib.load(input_skull_flirted_path) input_skull_flirted = input_skull_flirted_image.get_fdata() else: print('without skull processing') input_skull_flirted = input_flirted # SyN # metric = SSDMetric(3) # metric = EMMetric(3) metric = CCMetric(3) level_iters = [10, 10, 5, 5, 5] sdr = SymmetricDiffeomorphicRegistration(metric, level_iters) mapping = sdr.optimize( static=template, moving=input_skull_flirted, static_grid2world=template_image.get_qform(), moving_grid2world=input_flirted_image.get_qform()) with open(input_flirted_syn_path, 'wb') as f: dump([mapping, metric, level_iters, sdr], f, protocol=4, compression='gzip') forw_field = mapping.get_forward_field() back_field = mapping.get_backward_field() forw_SS = np.sum(np.power(forw_field, 2))
# allen template flirted cropping allen_template_flirted_cropped, crop_index = zeroPadImage( allen_template_flirted, allen_template_flirted, 0.1) allen_template_flirted_cropped_image = nib.Nifti1Image( allen_template_flirted_cropped, allen_template_flirted_image.affine) allen_template_flirted_cropped_path = allen_template_flirted_path.split( '.')[0] + '_cropped.nii.gz' print(allen_template_flirted_cropped_path) nib.save(allen_template_flirted_cropped_image, allen_template_flirted_cropped_path) # SyN flirted images to AMBMC print('SyN') metric = CCMetric(3) level_iters = [10, 10, 5, 5, 5] sdr = SymmetricDiffeomorphicRegistration(metric, level_iters) mapping = sdr.optimize( static=AMBMC_template_zeropadded, moving=allen_template_flirted, static_grid2world=AMBMC_template_zeropadded_image.get_qform(), moving_grid2world=allen_template_flirted_image.get_qform()) with open(allen_template_flirted_syn_path, 'wb') as f: dump([mapping, metric, level_iters, sdr], f, protocol=4, compression='gzip') # with open(allen_template_flirted_syn_path, 'rb') as f: # [mapping, metric, level_iters, sdr] = load(f, compression='gzip') forw_field = mapping.get_forward_field() back_field = mapping.get_backward_field()
def align_atlas(): neo_fname = get_neobrain('train', 1, 'T2') neo_nib = nib.load(neo_fname) neo = neo_nib.get_data() neo_affine = neo_nib.get_affine() # Load atlas (with skull) atlas_fname = get_neobrain('atlas', 'neo-withSkull', None) atlas_nib = nib.load(atlas_fname) atlas = atlas_nib.get_data() atlas_affine = atlas_nib.get_affine() # The first training volume dimensions are about 5cm x 5cm x 8cm # The atlas dimensions are about 7cm x 9cm x 11 cm # Assuming isotropic scale, the atlas is about 1.5 times larger than # the input image: iso_scale = (float(7*9*11)/float(5*5*8))**(1.0/3) print(iso_scale) #We can use this to constraint the transformation to rigid scale = np.eye(4) scale[:3,:3] *= iso_scale rigid_map_fname = 'atlas_towards_neo1_rigid.p' if os.path.isfile(rigid_map_fname): rigid_map = pickle.load(open(rigid_map_fname, 'r')) else: transforms = ['RIGID'] rigid_map = dipy_align(neo, neo_affine, atlas, atlas_affine, transforms=transforms, prealign=scale) pickle.dump(rigid_map, open(rigid_map_fname, 'w')) atlas_resampled = rigid_map.transform(atlas) # Compare anterior coronal slices rt.overlay_slices(neo, atlas_resampled, slice_type=2, slice_index=10, ltitle='Neo1', rtitle='Atlas'); # Compare middle coronal slices rt.overlay_slices(neo, atlas_resampled, slice_type=2, slice_index=25, ltitle='Neo1', rtitle='Atlas'); # Compare posterior coronal slices rt.overlay_slices(neo, atlas_resampled, slice_type=2, slice_index=40, ltitle='Neo1', rtitle='Atlas'); # Load the peeled atlas atlas_wcerebellum_fname = get_neobrain('atlas', 'neo-withCerebellum', None) atlas_wcerebellum_nib = nib.load(atlas_wcerebellum_fname) atlas_wcerebellum = atlas_wcerebellum_nib.get_data() atlas_wcerebellum_affine = atlas_wcerebellum_nib.get_affine() # Configure diffeomorphic registration diff_map_name = 'atlas_towards_neo1_diff.p' if os.path.isfile(diff_map_name): diff_map = pickle.load(open(diff_map_name, 'r')) else: metric = CCMetric(3) sdr = SymmetricDiffeomorphicRegistration(metric) # The atlases are not aligned in physical space!! use atlas_affine instead of atlas_wcerebellum_affine diff_map = sdr.optimize(neo, atlas_wcerebellum, neo_affine, atlas_affine, prealign=rigid_map.affine) pickle.dump(diff_map, open(diff_map_name, 'w')) atlas_wcerebellum_deformed = diff_map.transform(atlas_wcerebellum) # Before and after diffeomorphic registration rt.overlay_slices(neo, atlas_resampled, slice_type=2, slice_index=10, ltitle='Neo1', rtitle='Atlas'); rt.overlay_slices(neo, atlas_wcerebellum_deformed, slice_type=2, slice_index=10, ltitle='Neo1', rtitle='Atlas'); # Before and after diffeomorphic registration rt.overlay_slices(neo, atlas_resampled, slice_type=2, slice_index=25, ltitle='Neo1', rtitle='Atlas'); rt.overlay_slices(neo, atlas_wcerebellum_deformed, slice_type=2, slice_index=25, ltitle='Neo1', rtitle='Atlas'); # Before and after diffeomorphic registration rt.overlay_slices(neo, atlas_resampled, slice_type=2, slice_index=40, ltitle='Neo1', rtitle='Atlas'); rt.overlay_slices(neo, atlas_wcerebellum_deformed, slice_type=2, slice_index=40, ltitle='Neo1', rtitle='Atlas'); # Now all volumes atlas_fname = get_neobrain('atlas', 'neo-withSkull', None) atlas_nib = nib.load(atlas_fname) atlas = atlas_nib.get_data() atlas_affine = atlas_nib.get_affine() atlas_wcerebellum_fname = get_neobrain('atlas', 'neo-withCerebellum', None) atlas_wcerebellum_nib = nib.load(atlas_wcerebellum_fname) atlas_wcerebellum = atlas_wcerebellum_nib.get_data() atlas_wcerebellum_affine = atlas_wcerebellum_nib.get_affine() idx = 2 neoi_fname = get_neobrain('train', idx, 'T2') neoi_nib = nib.load(neoi_fname) neoi = neoi_nib.get_data() neoi_affine = neoi_nib.get_affine() iso_scale = (float(7*9*11)/float(5*5*8))**(1.0/3) print(iso_scale) #We can use this to constraint the transformation to rigid scale = np.eye(4) scale[:3,:3] *= iso_scale rigid_map_fname = 'atlas_towards_neo%d_affine.p'%(idx,) if os.path.isfile(rigid_map_fname): rigid_map = pickle.load(open(rigid_map_fname, 'r')) else: transforms = ['RIGID', 'AFFINE'] level_iters = [[10000, 1000, 100], [100]] rigid_map = dipy_align(neoi, neoi_affine, atlas, atlas_affine, transforms=transforms, level_iters=level_iters, prealign=scale) pickle.dump(rigid_map, open(rigid_map_fname, 'w')) atlas_resampled = rigid_map.transform(atlas) rt.overlay_slices(neoi, atlas_resampled, slice_type=2, slice_index = 6) rt.overlay_slices(neoi, atlas_resampled, slice_type=2, slice_index = 10) rt.overlay_slices(neoi, atlas_resampled, slice_type=2, slice_index = 25) rt.overlay_slices(neoi, atlas_resampled, slice_type=2, slice_index = 40) diff_map_name = 'atlas_towards_neo%d_diff.p'%(idx,) if os.path.isfile(diff_map_name): diff_map = pickle.load(open(diff_map_name, 'r')) else: metric = CCMetric(3) sdr = SymmetricDiffeomorphicRegistration(metric) # The atlases are not aligned in physical space!! use atlas_affine instead of atlas_wcerebellum_affine diff_map = sdr.optimize(neoi, atlas_wcerebellum, neoi_affine, atlas_affine, prealign=rigid_map.affine) pickle.dump(diff_map, open(diff_map_name, 'w')) atlas_wcerebellum_deformed = diff_map.transform(atlas_wcerebellum) # Before and after diffeomorphic registration rt.overlay_slices(neoi, atlas_resampled, slice_type=2, slice_index=6, ltitle='Neo%d'%(idx,), rtitle='Atlas'); rt.overlay_slices(neoi, atlas_wcerebellum_deformed, slice_type=2, slice_index=6, ltitle='Neo%d'%(idx,), rtitle='Atlas'); rt.overlay_slices(neoi, atlas_resampled, slice_type=2, slice_index=10, ltitle='Neo%d'%(idx,), rtitle='Atlas'); rt.overlay_slices(neoi, atlas_wcerebellum_deformed, slice_type=2, slice_index=10, ltitle='Neo%d'%(idx,), rtitle='Atlas'); # Before and after diffeomorphic registration rt.overlay_slices(neoi, atlas_resampled, slice_type=2, slice_index=25, ltitle='Neo%d'%(idx,), rtitle='Atlas'); rt.overlay_slices(neoi, atlas_wcerebellum_deformed, slice_type=2, slice_index=25, ltitle='Neo%d'%(idx,), rtitle='Atlas'); # Before and after diffeomorphic registration rt.overlay_slices(neoi, atlas_resampled, slice_type=2, slice_index=40, ltitle='Neo%d'%(idx,), rtitle='Atlas'); rt.overlay_slices(neoi, atlas_wcerebellum_deformed, slice_type=2, slice_index=40, ltitle='Neo%d'%(idx,), rtitle='Atlas');
moving_affine, starting_affine=rigid_map.affine) transformed = highres_map.transform(moving) """ We now perform the non-rigid deformation using the Symmetric Diffeomorphic Registration (SyN) Algorithm proposed by Avants et al. [Avants09]_ (also implemented in the ANTs software [Avants11]_): """ from dipy.align.imwarp import SymmetricDiffeomorphicRegistration from dipy.align.metrics import CCMetric metric = CCMetric(3) level_iters = [10, 10, 5] sdr = SymmetricDiffeomorphicRegistration(metric, level_iters) mapping = sdr.optimize(static, moving, static_affine, moving_affine, highres_map.affine) warped_moving = mapping.transform(moving) """ We show the registration result with: """ from dipy.viz import regtools regtools.overlay_slices(static, warped_moving, None, 0, 'Static', 'Moving', 'transformed_sagittal.png') regtools.overlay_slices(static, warped_moving, None, 1, 'Static', 'Moving', 'transformed_coronal.png')
""" .. figure:: input.png :align: center Input images before alignment. """ """ Let's use the general Registration function with some naive parameters, such as set `step_length` as 1 assuming maximal step 1 pixel and a reasonably small number of iterations since the deformation with already aligned images should be minimal. """ sdr = SymmetricDiffeomorphicRegistration(metric=SSDMetric(img_ref.ndim), step_length=1.0, level_iters=[50, 100], inv_iter=50, ss_sigma_factor=0.1, opt_tol=1.e-3) """ Perform the registration with equal images. """ mapping = sdr.optimize(img_ref.astype(float), img_ref.astype(float)) img_warp = mapping.transform(img_ref, 'linear') show_images(img_ref, img_warp, 'output-0') regtools.plot_2d_diffeomorphic_map(mapping, 5, 'map-0.png') """ .. figure:: output-0.png :align: center .. figure:: map-0.png :align: center
def syn_registration(moving, static, moving_affine=None, static_affine=None, step_length=0.25, metric='CC', dim=3, level_iters=None, prealign=None, **metric_kwargs): """Register a 2D/3D source image (moving) to a 2D/3D target image (static). Parameters ---------- moving, static : array or nib.Nifti1Image or str. Either as a 2D/3D array or as a nifti image object, or as a string containing the full path to a nifti file. moving_affine, static_affine : 4x4 array, optional. Must be provided for `data` provided as an array. If provided together with Nifti1Image or str `data`, this input will over-ride the affine that is stored in the `data` input. Default: use the affine stored in `data`. metric : string, optional The metric to be optimized. One of `CC`, `EM`, `SSD`, Default: 'CC' => CCMetric. dim: int (either 2 or 3), optional The dimensions of the image domain. Default: 3 level_iters : list of int, optional the number of iterations at each level of the Gaussian Pyramid (the length of the list defines the number of pyramid levels to be used). Default: [10, 10, 5]. metric_kwargs : dict, optional Parameters for initialization of the metric object. If not provided, uses the default settings of each metric. Returns ------- warped_moving : ndarray The data in `moving`, warped towards the `static` data. forward : ndarray (..., 3) The vector field describing the forward warping from the source to the target. backward : ndarray (..., 3) The vector field describing the backward warping from the target to the source. """ level_iters = level_iters or [10, 10, 5] static, static_affine, moving, moving_affine, _ = \ _handle_pipeline_inputs(moving, static, moving_affine=moving_affine, static_affine=static_affine, starting_affine=None) use_metric = syn_metric_dict[metric.upper()](dim, **metric_kwargs) sdr = SymmetricDiffeomorphicRegistration(use_metric, level_iters, step_length=step_length) mapping = sdr.optimize(static, moving, static_grid2world=static_affine, moving_grid2world=moving_affine, prealign=prealign) warped_moving = mapping.transform(moving) return warped_moving, mapping
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