def rigid(moving, static, static_grid2world, moving_grid2world, reg, starting_affine, params0=None): transform = RigidTransform3D() rigid = reg.optimize(static, moving, transform, params0, static_grid2world, moving_grid2world, starting_affine=starting_affine) return rigid.transform(moving), rigid.affine, rigid
def estimate_rigid3d(self, fixed, moving, tx_tr=None): assert len(moving.shape) == len(fixed.shape) trans = RigidTransform3D() if self.update_map: self.metric = MutualInformationMetric(self.nbins, self.sampling_prop) self.affmap = AffineRegistration( metric=self.metric, level_iters=self.level_iters, sigmas=self.sigmas, factors=self.factors, method=self.method, ss_sigma_factor=self.ss_sigma_factor, options=self.options, verbosity=self.verbosity) if tx_tr is None: tmp = self.estimate_rigid2d(fixed.mean(axis=0), moving.mean(axis=0)) tmp = tmp.affine tx_tr = np.eye(4) tx_tr[1:, 1:] = tmp if isinstance(tx_tr, AffineMap): tx_tr = tx_tr.affine return self.affmap.optimize(fixed, moving, trans, self.params0, starting_affine=tx_tr)
def register_image(static, static_grid2world, moving, moving_grid2world, transformation_type='affine', dwi=None): if transformation_type not in ['rigid', 'affine']: raise ValueError('Transformation type not available in Dipy') # Set all parameters for registration nbins = 32 params0 = None sampling_prop = None level_iters = [50, 25, 5] sigmas = [8.0, 4.0, 2.0] factors = [8, 4, 2] metric = MutualInformationMetric(nbins, sampling_prop) reg_obj = AffineRegistration(metric=metric, level_iters=level_iters, sigmas=sigmas, factors=factors, verbosity=0) # First, align the center of mass of both volume c_of_mass = transform_centers_of_mass(static, static_grid2world, moving, moving_grid2world) # Then, rigid transformation (translation + rotation) transform = RigidTransform3D() rigid = reg_obj.optimize(static, moving, transform, params0, static_grid2world, moving_grid2world, starting_affine=c_of_mass.affine) if transformation_type == 'affine': # Finally, affine transformation (translation + rotation + scaling) transform = AffineTransform3D() affine = reg_obj.optimize(static, moving, transform, params0, static_grid2world, moving_grid2world, starting_affine=rigid.affine) mapper = affine transformation = affine.affine else: mapper = rigid transformation = rigid.affine if dwi is not None: trans_dwi = transform_dwi(mapper, static, dwi) return trans_dwi, transformation else: return mapper.transform(moving), transformation
def rigid_registration(fixed, moving, metric=MutualInformationMetric(), **kwargs): affreg = AffineRegistration(metric=metric, **kwargs) rigid = affreg.optimize(fixed.get_data(), moving.get_data(), RigidTransform3D(), None, fixed.affine, moving.affine) transformed = rigid.transform(moving.get_data()) # convert transformed to full nibabel image, just data now # TODO: get affine for transformed from rigid.affine? transformed = new_img_like(moving, transformed) return transformed
def rigid(moving, static, static_affine=None, moving_affine=None, starting_affine=None, reg=None): """ Implements a rigid transform Parameters ---------- moving : array, nifti image or str Containing the data for the moving object, or full path to a nifti file with the moving data. moving_affine : 4x4 array, optional An affine transformation associated with the moving object. Required if data is provided as an array. If provided together with nifti/path, will over-ride the affine that is in the nifti. static : array, nifti image or str Containing the data for the static object, or full path to a nifti file with the moving data. static_affine : 4x4 array, optional An affine transformation associated with the static object. Required if data is provided as an array. If provided together with nifti/path, will over-ride the affine that is in the nifti. starting_affine: 4x4 array, optional Initial guess for the transformation between the spaces. reg : AffineRegistration class instance. Returns ------- transformed, transform.affine : array with moving data resampled to the static space after computing the rigid transformation and the affine 4x4 associated with the transformation. """ static, static_affine, moving, moving_affine, starting_affine = \ _handle_pipeline_inputs(moving, static, moving_affine=moving_affine, static_affine=static_affine, starting_affine=starting_affine) transform = RigidTransform3D() rigid = reg.optimize(static, moving, transform, None, static_affine, moving_affine, starting_affine=starting_affine) return rigid.affine
def rigid(self, static, static_grid2world, moving, moving_grid2world, affreg, params0, progressive): """ Function for rigid body based image registration. Parameters ---------- static : 2D or 3D array the image to be used as reference during optimization. static_grid2world : array, shape (dim+1, dim+1), optional the voxel-to-space transformation associated with the static image. The default is None, implying the transform is the identity. moving : 2D or 3D array the image to be used as "moving" during optimization. It is necessary to pre-align the moving image to ensure its domain lies inside the domain of the deformation fields. This is assumed to be accomplished by "pre-aligning" the moving image towards the static using an affine transformation given by the 'starting_affine' matrix. moving_grid2world : array, shape (dim+1, dim+1), optional the voxel-to-space transformation associated with the moving image. The default is None, implying the transform is the identity. affreg : An object of the image registration class. params0 : array, shape (n,) parameters from which to start the optimization. If None, the optimization will start at the identity transform. n is the number of parameters of the specified transformation. progressive : boolean Flag to enable or disable the progressive registration. (defa ult True) """ if progressive: _, affine, xopt, fopt = self.translate(static, static_grid2world, moving, moving_grid2world, affreg, params0) else: _, affine = self.center_of_mass(static, static_grid2world, moving, moving_grid2world) transform = RigidTransform3D() return self.perform_transformation(static, static_grid2world, moving, moving_grid2world, affreg, params0, transform, affine)
def register_affine(t_masked, m_masked, affreg=None, final_iters=(10000, 1000, 100)): """ Run affine registration between images `t_masked`, `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. affreg : None or AffineRegistration instance, optional AffineRegistration with which to register `m_masked` to `t_masked`. If None, we make an instance with default parameters. final_iters : tuple, optional Length 3 tuple of level iterations to use on final affine pass of the registration. Returns ------- affine : shape (4, 4) ndarray Final affine mapping from voxels in `t_masked` to voxels in `m_masked`. """ if affreg is None: metric = MutualInformationMetric(nbins=32, sampling_proportion=None) affreg = AffineRegistration(metric=metric) t_data = t_masked.get_data().astype(float) m_data = m_masked.get_data().astype(float) t_aff = t_masked.affine m_aff = m_masked.affine translation = affreg.optimize(t_data, m_data, TranslationTransform3D(), None, t_aff, m_aff) rigid = affreg.optimize(t_data, m_data, RigidTransform3D(), None, t_aff, m_aff, starting_affine=translation.affine) # Maybe bump up iterations for last step if final_iters is not None: affreg.level_iters = list(final_iters) affine = affreg.optimize(t_data, m_data, AffineTransform3D(), None, t_aff, m_aff, starting_affine=rigid.affine) return affine.affine
def _rigid_body_registration(static, static_grid2world, moving, moving_grid2world, translation, affreg): transform = RigidTransform3D() params0 = None starting_affine = translation.affine rigid = affreg.optimize(static, moving, transform, params0, static_grid2world, moving_grid2world, starting_affine=starting_affine) return rigid
def align_xmap_np(static, moving, static_grid2world=np.eye(4), moving_grid2world=np.eye(4)): 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, verbosity=0) transform = RigidTransform3D() params0 = None # starting_affine = transform_centers_of_mass(static, # static_grid2world, # moving, # moving_grid2world, # ).affine # print("\tCOM affine transform is: {}".format(starting_affine)) starting_affine = np.eye(4) rigid = affreg.optimize( static, moving, transform, params0, static_grid2world, moving_grid2world, starting_affine=starting_affine, # verbosity=0, ) # Transform transformed = rigid.transform(moving) # print("\tThe transform is: {}".format(rigid.affine)) return transformed
def registration(ref, moving, ref_mask=None, moving_mask=None): ref_mask_data, mov_mask_data = None, None ref_data = ref.get_fdata() if ref_mask: ref_mask_data = ref_mask.get_fdata() > 0.5 mov_data = moving.get_fdata() if moving_mask: mov_mask_data = moving_mask.get_fdata() > 0.5 metric = MutualInformationMetric(nbins=32, sampling_proportion=None) transform = RigidTransform3D() affreg = AffineRegistration( metric=metric, level_iters=[10000, 1000, 0], factors=[6, 4, 2], sigmas=[4, 2, 0] ) rigid = affreg.optimize( ref_data, mov_data, transform, None, ref.affine, moving.affine, starting_affine="mass", static_mask=ref_mask_data, moving_mask=mov_mask_data, ) affreg = AffineRegistration( metric=metric, level_iters=[10000, 1000, 0], factors=[4, 2, 2], sigmas=[4, 2, 0] ) transform = RigidScalingTransform3D() # transform = AffineTransform3D() return affreg.optimize( ref_data, mov_data, transform, None, ref.affine, moving.affine, starting_affine=rigid.affine, static_mask=ref_mask_data, moving_mask=mov_mask_data, )
def rigid_transform(static, moving, static_grid2world, moving_grid2world, nbins, sampling_prop, metric, level_iters, sigmas, factors, starting_affine): transform = RigidTransform3D() params0 = None affreg = AffineRegistration(metric=metric, level_iters=level_iters, sigmas=sigmas, factors=factors) rigid = affreg.optimize(static, moving, transform, params0, static_grid2world, moving_grid2world, starting_affine=starting_affine) return rigid
def test_affine_map_rigid_snapshot(): assert AFFINE_MAP_SNAPSHOT_PATH_INPUT.exists() assert AFFINE_MAP_RIGID_SNAPSHOT_PATH_OUTPUT.exists() with open(AFFINE_MAP_SNAPSHOT_PATH_INPUT, "rb") as input_file: input_snapshot = pickle.load(input_file) with open(AFFINE_MAP_RIGID_SNAPSHOT_PATH_OUTPUT, "rb") as input_file: output_snapshot = pickle.load(input_file) aff_reg = get_affine_registration([100, 20, 10]) transformed, curr_affine = apply_transform( RigidTransform3D(), input_snapshot["template_data"], input_snapshot["moving_data"], input_snapshot["template_affine"], input_snapshot["moving_affine"], input_snapshot["curr_affine"], aff_reg, ) # TODO remove this, this is how "snapshot" pickles were produced: # with open(AFFINE_MAP_RIGID_SNAPSHOT_PATH_OUTPUT, 'wb') as snap_out: # outputs = { # 'transformed': transformed, # 'affine': curr_affine # } # pickle.dump(outputs, snap_out) logger.info(f"Output registration affine: {curr_affine}") logger.info(f"Target registration affine: {output_snapshot['affine']}") assert np.all( np.equal(curr_affine.affine, output_snapshot["affine"].affine) ), "Expected registration affine to match target registration affine generated on macOs" assert np.all( np.equal(transformed, output_snapshot["transformed"]) ), "Expected transformed image to match target transformed image generated on macOs"
def main(): parser = _build_arg_parser() args = parser.parse_args() if args.load_transfo and args.in_native_fa is None: parser.error('When loading a transformation, the final reference is ' 'needed, use --in_native_fa.') assert_inputs_exist(parser, [args.in_dsi_tractogram, args.in_dsi_fa], optional=args.in_native_fa) assert_outputs_exist(parser, args, args.out_tractogram) sft = load_tractogram(args.in_dsi_tractogram, 'same', bbox_valid_check=False) # LPS -> RAS convention in voxel space sft.to_vox() flip_axis = ['x', 'y'] sft_fix = StatefulTractogram(sft.streamlines, args.in_dsi_fa, Space.VOXMM) sft_fix.to_vox() sft_fix.streamlines._data -= get_axis_shift_vector(flip_axis) sft_flip = flip_sft(sft_fix, flip_axis) sft_flip.to_rasmm() sft_flip.streamlines._data -= [0.5, 0.5, -0.5] if not args.in_native_fa: if args.cut_invalid: sft_flip, _ = cut_invalid_streamlines(sft_flip) elif args.remove_invalid: sft_flip.remove_invalid_streamlines() save_tractogram(sft_flip, args.out_tractogram, bbox_valid_check=not args.keep_invalid) else: static_img = nib.load(args.in_native_fa) static_data = static_img.get_fdata() moving_img = nib.load(args.in_dsi_fa) moving_data = moving_img.get_fdata() # DSI-Studio flips the volume without changing the affine (I think) # So this has to be reversed (not the same problem as above) vox_order = get_reference_info(moving_img)[3] flip_axis = [] if vox_order[0] == 'L': moving_data = moving_data[::-1, :, :] flip_axis.append('x') if vox_order[1] == 'P': moving_data = moving_data[:, ::-1, :] flip_axis.append('y') if vox_order[2] == 'I': moving_data = moving_data[:, :, ::-1] flip_axis.append('z') sft_flip_back = flip_sft(sft_flip, flip_axis) if args.load_transfo: transfo = np.loadtxt(args.load_transfo) else: # Sometimes DSI studio has quite a lot of skull left # Dipy Median Otsu does not work with FA/GFA if args.auto_crop: moving_data = cube_crop_data(moving_data) static_data = cube_crop_data(static_data) # Since DSI Studio register to AC/PC and does not save the # transformation We must estimate the transformation, since it's # rigid it is 'easy' c_of_mass = transform_centers_of_mass(static_data, static_img.affine, moving_data, moving_img.affine) nbins = 32 sampling_prop = None level_iters = [1000, 100, 10] sigmas = [3.0, 2.0, 1.0] factors = [3, 2, 1] metric = MutualInformationMetric(nbins, sampling_prop) affreg = AffineRegistration(metric=metric, level_iters=level_iters, sigmas=sigmas, factors=factors) transform = RigidTransform3D() rigid = affreg.optimize(static_data, moving_data, transform, None, static_img.affine, moving_img.affine, starting_affine=c_of_mass.affine) transfo = rigid.affine if args.save_transfo: np.savetxt(args.save_transfo, transfo) new_sft = transform_warp_sft(sft_flip_back, transfo, static_img, inverse=True, remove_invalid=args.remove_invalid, cut_invalid=args.cut_invalid) if args.cut_invalid: new_sft, _ = cut_invalid_streamlines(new_sft) elif args.remove_invalid: new_sft.remove_invalid_streamlines() save_tractogram(new_sft, args.out_tractogram, bbox_valid_check=not args.keep_invalid)
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 affine_reg(static_path, moving_path): """ :param static_path: :param moving_path: :return: """ t0_time = time.time() print('-->Applying affine reg over', basename(moving_path), 'based on', basename(static_path)) static_img = nib.load(static_path) static = static_img.get_data() static_grid2world = static_img.affine moving_img = nib.load(moving_path) moving = np.array(moving_img.get_data()) moving_grid2world = moving_img.affine print('---> I. Translation of the moving image towards the static image') print( '---> Resembling the moving image on a grid of the same dimensions as the static image' ) identity = np.eye(4) affine_map = AffineMap(identity, static.shape, static_grid2world, moving.shape, moving_grid2world) resampled = affine_map.transform(moving) regtools.overlay_slices(static, resampled, None, 0, "Static", "Moving", "resampled_0.png") regtools.overlay_slices(static, resampled, None, 1, "Static", "Moving", "resampled_1.png") regtools.overlay_slices(static, resampled, None, 2, "Static", "Moving", "resampled_2.png") print('---> Aligning the centers of mass of the two images') c_of_mass = transform_centers_of_mass(static, static_grid2world, moving, moving_grid2world) print( '---> We can now transform the moving image and draw it on top of the static image' ) transformed = c_of_mass.transform(moving) regtools.overlay_slices(static, transformed, None, 0, "Static", "Transformed", "transformed_com_0.png") regtools.overlay_slices(static, transformed, None, 1, "Static", "Transformed", "transformed_com_1.png") regtools.overlay_slices(static, transformed, None, 2, "Static", "Transformed", "transformed_com_2.png") print('---> II. Refine by looking for an affine transform') 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] """ Now we go ahead and instantiate the registration class with the configuration we just prepared """ print('---> Computing Affine Registration (non-convex optimization)') 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, moving, transform, params0, static_grid2world, moving_grid2world, starting_affine=starting_affine) transformed = translation.transform(moving) regtools.overlay_slices(static, transformed, None, 0, "Static", "Transformed", "transformed_trans_0.png") regtools.overlay_slices(static, transformed, None, 1, "Static", "Transformed", "transformed_trans_1.png") regtools.overlay_slices(static, transformed, None, 2, "Static", "Transformed", "transformed_trans_2.png") print('--->III. Refining with a rigid transform') transform = RigidTransform3D() params0 = None starting_affine = translation.affine rigid = affreg.optimize(static, moving, transform, params0, static_grid2world, moving_grid2world, starting_affine=starting_affine) transformed = rigid.transform(moving) regtools.overlay_slices(static, transformed, None, 0, "Static", "Transformed", "transformed_rigid_0.png") regtools.overlay_slices(static, transformed, None, 1, "Static", "Transformed", "transformed_rigid_1.png") regtools.overlay_slices(static, transformed, None, 2, "Static", "Transformed", "transformed_rigid_2.png") print( '--->IV. Refining with a full afine transform (translation, rotation, scale and shear)' ) transform = AffineTransform3D() params0 = None starting_affine = rigid.affine affine = affreg.optimize(static, moving, transform, params0, static_grid2world, moving_grid2world, starting_affine=starting_affine) print('---> Results in a slight shear and scale') transformed = affine.transform(moving) regtools.overlay_slices(static, transformed, None, 0, "Static", "Transformed", "transformed_affine_0.png") regtools.overlay_slices(static, transformed, None, 1, "Static", "Transformed", "transformed_affine_1.png") regtools.overlay_slices(static, transformed, None, 2, "Static", "Transformed", "transformed_affine_2.png") name = os.path.splitext(basename(moving_path))[0] + '_affine_reg' nib.save(nib.Nifti1Image(transformed, np.eye(4)), name) t1_time = time.time() total_time = t1_time - t0_time print('Total time:' + str(total_time)) return print('Successfully affine registration applied')
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 gm_network(mr_filename, gm_filename, at_filename, template_mr): new_gmfilename = os.path.abspath(gm_filename).replace(".nii", "_mni.nii") new_atfilename = os.path.abspath(at_filename).replace(".nii", "_mni.nii") networks = 0 if not ((os.path.isfile(new_gmfilename)) or (os.path.islink(new_gmfilename))): print('file {} does not exist'.format(new_gmfilename)) print('performing registration to MNI ... ', end='') start = time.process_time() # see if we can maybe find a transform tf_filename = os.path.abspath(gm_filename).split( '.nii')[0] + "_reg.npz" if not ((os.path.isfile(tf_filename)) or (os.path.islink(tf_filename))): # see https://dipy.org/documentation/1.2.0./examples_built/ .. # .. affine_registration_3d/#example-affine-registration-3d static, static_affine = load_nifti(template_mr) moving, moving_affine = load_nifti(mr_filename) grey, grey_affine = load_nifti(gm_filename) atl, atl_affine = load_nifti(at_filename) # first initialise by putting centres of mass on top of each other c_of_mass = transform_centers_of_mass(static, static_affine, moving, moving_affine) # initialise transform parameters (e.g. the mutual information criterion) # these parameters won' need to be changed between the different stages nbins = 64 sampling_prop = None metric = MutualInformationMetric(nbins, sampling_prop) level_iters = [25, 15, 5] sigmas = [2, 1, 0] factors = [4, 2, 1] affreg = AffineRegistration(metric=metric, level_iters=level_iters, sigmas=sigmas, factors=factors) # give slightly more degrees of freedom, by allowing translation of centre of gravity print('\nTranslation only:') transform = TranslationTransform3D() params0 = None translation = affreg.optimize(static, moving, transform, params0, static_affine, moving_affine, starting_affine=c_of_mass.affine) # refine further by allowing all rigid transforms (rotations/translations around the centre of gravity) print('Rigid transform:') transform = RigidTransform3D() params0 = None rigid = affreg.optimize(static, moving, transform, params0, static_affine, moving_affine, starting_affine=translation.affine) full_affine = False # the GM networks method is based on keeping the cortical shape intact if (full_affine): # refine to a full affine transform by adding scaling and shearing print('Affine transform:') transform = AffineTransform3D() params0 = None affine = affreg.optimize(static, moving, transform, params0, static_affine, moving_affine, starting_affine=rigid.affine) final = affine else: final = rigid np.savez(tf_filename, final) else: with np.load(tf_filename, allow_pickle=True) as npzfile: final = npzfile['arr_0'] # transform the grey matter data instead of the MRI itself resampled = final.transform(grey) save_nifti(new_gmfilename, resampled, static_affine) resampled = final.transform(atl) save_nifti(new_atfilename, resampled, static_affine) print('finished in {:.2f}s'.format(time.process_time() - start)) if ((os.path.isfile(new_gmfilename)) or (os.path.islink(new_gmfilename))): # only cube size implemented so far cubesize = 3 # load the grey matter map and the template to which it was registered gm_img = nib.load(new_gmfilename) template_data = np.asarray(nib.load(template_mr).dataobj) gm_data = np.asarray(gm_img.dataobj) # find the best cube grid position (with the most nonzero cubes) cube_nonzeros, cube_offsets, gm_incubes = cube_grid_position( gm_data, template_data, cubesize) gm_shape = gm_incubes.shape # write out the cube map, where each voxel in a cube is labelled with its cube index # be aware of the @ operator, this is a true matrix product A[n*m] x B[m*p] = C [n*p] cubes_data = np.zeros(template_data.shape).flatten() cubes_data[cube_offsets] = np.ones( cubesize**3)[:, np.newaxis] @ np.arange(cube_nonzeros).reshape( 1, cube_nonzeros) cubes_data = cubes_data.reshape(template_data.shape) cubes_file = os.path.abspath(gm_filename).replace( ".nii", "_cubes.nii") cubes_map = nib.Nifti1Image(cubes_data, gm_img.affine) cubes_map.to_filename(cubes_file) # make a randomised version of the grey matter densities in the cubes # 1: exchange between and inside cubes (could be too many degrees of freedom!) gm_random = gm_incubes.flatten() gm_random = gm_random[np.random.permutation( len(gm_random)).reshape(gm_shape)] # 2: exchange cubes only ( this won't change the values in the correlation matrix, only positions ) # gm_random = gm_incubes [ :, np.random.permutation ( gm_shape [1] ) ]; # 3: exchange cubes and shuffle inside cubes # gm_random = gm_incubes [ np.random.permutation ( gm_shape [0] ), np.random.permutation ( gm_shape [1] )[ :, np.newaxis ] ]; add_diag = True # name of the NIfTI file with networks networks_file = os.path.abspath(gm_filename).replace( ".nii", "_gmnet.nii") if not ((os.path.isfile(networks_file)) or (os.path.islink(networks_file))): # compute the cross correlation for observed and randomised cubes networks = cube_cross_correlation(gm_incubes, gm_random, cubesize, add_diag) # save the networks to a file networks_map = nib.Nifti1Image(networks, np.eye(4)) networks_map.to_filename(networks_file) else: print("loading already existing file") networks = np.asarray(nib.load(networks_file).dataobj) return networks, networks_file
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
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
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
sigmas=[3.0, 1.0, 0.0], factors=[4, 2, 1]) # translation translation = affreg.optimize(t1_s, t1_m, TranslationTransform3D(), None, t1_s_grid2world, t1_m_grid2world, starting_affine=c_of_mass.affine) # rigid body transform (translation + rotation) rigid = affreg.optimize(t1_s, t1_m, RigidTransform3D(), None, t1_s_grid2world, t1_m_grid2world, starting_affine=translation.affine) # affine transform (translation + rotation + scaling) affine = affreg.optimize(t1_s, t1_m, AffineTransform3D(), None, t1_s_grid2world, t1_m_grid2world, starting_affine=rigid.affine) # apply affine transformation
def affine_registration(moving, static, moving_affine=None, static_affine=None, pipeline=None, starting_affine=None, metric='MI', level_iters=None, sigmas=None, factors=None, ret_metric=False, **metric_kwargs): """ Find the affine transformation between two 3D images. Alternatively, find the combination of several linear transformations. Parameters ---------- moving : array, nifti image or str Containing the data for the moving object, or full path to a nifti file with the moving data. static : array, nifti image or str Containing the data for the static object, or full path to a nifti file with the moving data. moving_affine : 4x4 array, optional An affine transformation associated with the moving object. Required if data is provided as an array. If provided together with nifti/path, will over-ride the affine that is in the nifti. static_affine : 4x4 array, optional An affine transformation associated with the static object. Required if data is provided as an array. If provided together with nifti/path, will over-ride the affine that is in the nifti. pipeline : list of str, optional Sequence of transforms to use in the gradual fitting. Default: gradual fit of the full affine (executed from left to right): `["center_of_mass", "translation", "rigid", "affine"]` Alternatively, any other combination of the following registration methods might be used: center_of_mass, translation, rigid, rigid_isoscaling, rigid_scaling and affine. starting_affine: 4x4 array, optional Initial guess for the transformation between the spaces. Default: identity. metric : str, optional. Currently only supports 'MI' for MutualInformationMetric. level_iters : sequence, optional AffineRegistration key-word argument: the number of iterations at each scale of the scale space. `level_iters[0]` corresponds to the coarsest scale, `level_iters[-1]` the finest, where n is the length of the sequence. By default, a 3-level scale space with iterations sequence equal to [10000, 1000, 100] will be used. sigmas : sequence of floats, optional AffineRegistration key-word argument: custom smoothing parameter to build the scale space (one parameter for each scale). By default, the sequence of sigmas will be [3, 1, 0]. factors : sequence of floats, optional AffineRegistration key-word argument: custom scale factors to build the scale space (one factor for each scale). By default, the sequence of factors will be [4, 2, 1]. ret_metric : boolean, optional Set it to True to return the value of the optimized coefficients and the optimization quality metric. nbins : int, optional MutualInformationMetric key-word argument: the number of bins to be used for computing the intensity histograms. The default is 32. sampling_proportion : None or float in interval (0, 1], optional MutualInformationMetric key-word argument: There are two types of sampling: dense and sparse. Dense sampling uses all voxels for estimating the (joint and marginal) intensity histograms, while sparse sampling uses a subset of them. If `sampling_proportion` is None, then dense sampling is used. If `sampling_proportion` is a floating point value in (0,1] then sparse sampling is used, where `sampling_proportion` specifies the proportion of voxels to be used. The default is None (dense sampling). Returns ------- transformed : array with moving data resampled to the static space after computing the affine transformation affine : the affine 4x4 associated with the transformation. xopt : the value of the optimized coefficients. fopt : the value of the optimization quality metric. Notes ----- Performs a gradual registration between the two inputs, using a pipeline that gradually approximates the final registration. If the final default step (`affine`) is ommitted, the resulting affine may not have all 12 degrees of freedom adjusted. """ pipeline = pipeline or ["center_of_mass", "translation", "rigid", "affine"] level_iters = level_iters or [10000, 1000, 100] sigmas = sigmas or [3, 1, 0.0] factors = factors or [4, 2, 1] static, static_affine, moving, moving_affine, starting_affine = \ _handle_pipeline_inputs(moving, static, moving_affine=moving_affine, static_affine=static_affine, starting_affine=starting_affine) # Define the Affine registration object we'll use with the chosen metric. # For now, there is only one metric (mutual information) use_metric = affine_metric_dict[metric](**metric_kwargs) affreg = AffineRegistration(metric=use_metric, level_iters=level_iters, sigmas=sigmas, factors=factors) if pipeline == ["center_of_mass"] and ret_metric: raise ValueError("center of mass registration cannot return any " "quality metric.") # Go through the selected transformation: for func in pipeline: if func == "center_of_mass": transform = transform_centers_of_mass(static, static_affine, moving, moving_affine) starting_affine = transform.affine else: if func == "translation": transform = TranslationTransform3D() elif func == "rigid": transform = RigidTransform3D() elif func == "rigid_isoscaling": transform = RigidIsoScalingTransform3D() elif func == "rigid_scaling": transform = RigidScalingTransform3D() elif func == "affine": transform = AffineTransform3D() else: raise ValueError("Not supported registration method") xform, xopt, fopt \ = affreg.optimize(static, moving, transform, None, static_affine, moving_affine, starting_affine=starting_affine, ret_metric=True) starting_affine = xform.affine # After doing all that, resample once at the end: affine_map = AffineMap(starting_affine, static.shape, static_affine, moving.shape, moving_affine) resampled = affine_map.transform(moving) # Return the optimization metric only if requested if ret_metric: return resampled, starting_affine, xopt, fopt return resampled, starting_affine
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 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 main(): # reads the tractography data in trk format # extracts streamlines and the file header. Streamlines should be in the same coordinate system as the FA map (used later). # input example: '/home/Example_data/tracts.trk' tractography_file = input( "Please, specify the file with tracts that you would like to analyse. File should be in the trk format. " ) streams, hdr = load_trk(tractography_file) # for old DIPY version # sft = load_trk(tractography_file, tractography_file) # streams = sft.streamlines streams_array = np.asarray(streams) print('imported tractography data:' + tractography_file) # load T1fs_conform image that operates in the same coordinates as simnibs except for the fact the center of mesh # is located at the image center # T1fs_conform image should be generated in advance during the head meshing procedure # input example: fname_T1='/home/Example_data/T1fs_conform.nii.gz' fname_T1 = input( "Please, specify the T1fs_conform image that has been generated during head meshing procedure. " ) data_T1, affine_T1 = load_nifti(fname_T1) # load FA image in the same coordinates as tracts # input example:fname_FA='/home/Example_data/DTI_FA.nii' fname_FA = input("Please, specify the FA image. ") data_FA, affine_FA = load_nifti(fname_FA) print('loaded T1fs_conform.nii and FA images') # specify the head mesh file that is used later in simnibs to simulate induced electric field # input example:'/home/Example_data/SUBJECT_MESH.msh' global mesh_path mesh_path = input("Please, specify the head mesh file. ") last_slach = max([i for i, ltr in enumerate(mesh_path) if ltr == '/']) + 1 global subject_name subject_name = mesh_path[last_slach:-4] # specify the directory where you would like to save your simulation results # input example:'/home/Example_data/Output' global out_dir out_dir = input( "Please, specify the directory where you would like to save your simulation results. " ) out_dir = out_dir + '/simulation_at_pos_' # Co-registration of T1fs_conform and FA images. Performed in 4 steps. # Step 1. Calculation of the center of mass transform. Used later as starting transform. c_of_mass = transform_centers_of_mass(data_T1, affine_T1, data_FA, affine_FA) print('calculated c_of_mass transformation') # Step 2. Calculation of a 3D translation transform. Used in the next step as starting transform. 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(data_T1, data_FA, transform, params0, affine_T1, affine_FA, starting_affine=starting_affine) print('calculated 3D translation transform') # Step 3. Calculation of a Rigid 3D transform. Used in the next step as starting transform transform = RigidTransform3D() params0 = None starting_affine = translation.affine rigid = affreg.optimize(data_T1, data_FA, transform, params0, affine_T1, affine_FA, starting_affine=starting_affine) print('calculated Rigid 3D transform') # Step 4. Calculation of an affine transform. Used for co-registration of T1 and FA images. transform = AffineTransform3D() params0 = None starting_affine = rigid.affine affine = affreg.optimize(data_T1, data_FA, transform, params0, affine_T1, affine_FA, starting_affine=starting_affine) print('calculated Affine 3D transform') identity = np.eye(4) inv_affine_FA = np.linalg.inv(affine_FA) inv_affine_T1 = np.linalg.inv(affine_T1) inv_affine = np.linalg.inv(affine.affine) # transforming streamlines to FA space new_streams_FA = streamline.transform_streamlines(streams, inv_affine_FA) new_streams_FA_array = np.asarray(new_streams_FA) T1_to_FA = np.dot(inv_affine_FA, np.dot(affine.affine, affine_T1)) FA_to_T1 = np.linalg.inv(T1_to_FA) # transforming streamlines from FA to T1 space new_streams_T1 = streamline.transform_streamlines(new_streams_FA, FA_to_T1) global new_streams_T1_array new_streams_T1_array = np.asarray(new_streams_T1) # calculating amline derivatives along the streamlines to get the local orientation of the streamlines global streams_array_derivative streams_array_derivative = copy.deepcopy(new_streams_T1_array) print('calculating amline derivatives') for stream in range(len(new_streams_T1_array)): my_steam = new_streams_T1_array[stream] for t in range(len(my_steam[:, 0])): streams_array_derivative[stream][t, 0] = my_deriv(t, my_steam[:, 0]) streams_array_derivative[stream][t, 1] = my_deriv(t, my_steam[:, 1]) streams_array_derivative[stream][t, 2] = my_deriv(t, my_steam[:, 2]) deriv_norm = np.linalg.norm(streams_array_derivative[stream][t, :]) streams_array_derivative[stream][ t, :] = streams_array_derivative[stream][t, :] / deriv_norm # to create a torus representing a coil in an interactive window torus = vtk.vtkParametricTorus() torus.SetRingRadius(5) torus.SetCrossSectionRadius(2) torusSource = vtk.vtkParametricFunctionSource() torusSource.SetParametricFunction(torus) torusSource.SetScalarModeToPhase() torusMapper = vtk.vtkPolyDataMapper() torusMapper.SetInputConnection(torusSource.GetOutputPort()) torusMapper.SetScalarRange(0, 360) torusActor = vtk.vtkActor() torusActor.SetMapper(torusMapper) torus_pos_x = 100 torus_pos_y = 129 torus_pos_z = 211 torusActor.SetPosition(torus_pos_x, torus_pos_y, torus_pos_z) list_streams_T1 = list(new_streams_T1) # adding one fictive bundle of length 1 with coordinates [0,0,0] to avoid some bugs with actor.line during visualization list_streams_T1.append(np.array([0, 0, 0])) global bundle_native bundle_native = list_streams_T1 # generating a list of colors to visualize later the stimualtion effects effect_max = 0.100 effect_min = -0.100 global colors colors = [ np.random.rand(*current_streamline.shape) for current_streamline in bundle_native ] for my_streamline in range(len(bundle_native) - 1): my_stream = copy.deepcopy(bundle_native[my_streamline]) for point in range(len(my_stream)): colors[my_streamline][point] = vtkplotter.colors.colorMap( (effect_min + effect_max) / 2, name='jet', vmin=effect_min, vmax=effect_max) colors[my_streamline + 1] = vtkplotter.colors.colorMap(effect_min, name='jet', vmin=effect_min, vmax=effect_max) # Vizualization of fibers over T1 # i_coord = 0 # j_coord = 0 # k_coord = 0 # global number_of_stimulations number_of_stimulations = 0 actor_line_list = [] scene = window.Scene() scene.clear() scene.background((0.5, 0.5, 0.5)) world_coords = False shape = data_T1.shape lut = actor.colormap_lookup_table(scale_range=(effect_min, effect_max), hue_range=(0.4, 1.), saturation_range=(1, 1.)) # # the lines below is for a non-interactive demonstration run only. # # they should remain commented unless you set "interactive" to False # lut, colors = change_TMS_effects(torus_pos_x, torus_pos_y, torus_pos_z) # bar = actor.scalar_bar(lut) # bar.SetTitle("TMS effect") # bar.SetHeight(0.3) # bar.SetWidth(0.10) # bar.SetPosition(0.85, 0.3) # scene.add(bar) actor_line_list.append( actor.line(bundle_native, colors, linewidth=5, fake_tube=True, lookup_colormap=lut)) if not world_coords: image_actor_z = actor.slicer(data_T1, identity) else: image_actor_z = actor.slicer(data_T1, identity) slicer_opacity = 0.6 image_actor_z.opacity(slicer_opacity) image_actor_x = image_actor_z.copy() x_midpoint = int(np.round(shape[0] / 2)) image_actor_x.display_extent(x_midpoint, x_midpoint, 0, shape[1] - 1, 0, shape[2] - 1) image_actor_y = image_actor_z.copy() y_midpoint = int(np.round(shape[1] / 2)) image_actor_y.display_extent(0, shape[0] - 1, y_midpoint, y_midpoint, 0, shape[2] - 1) """ Connect the actors with the scene. """ scene.add(actor_line_list[0]) scene.add(image_actor_z) scene.add(image_actor_x) scene.add(image_actor_y) show_m = window.ShowManager(scene, size=(1200, 900)) show_m.initialize() """ Create sliders to move the slices and change their opacity. """ line_slider_z = ui.LineSlider2D(min_value=0, max_value=shape[2] - 1, initial_value=shape[2] / 2, text_template="{value:.0f}", length=140) line_slider_x = ui.LineSlider2D(min_value=0, max_value=shape[0] - 1, initial_value=shape[0] / 2, text_template="{value:.0f}", length=140) line_slider_y = ui.LineSlider2D(min_value=0, max_value=shape[1] - 1, initial_value=shape[1] / 2, text_template="{value:.0f}", length=140) opacity_slider = ui.LineSlider2D(min_value=0.0, max_value=1.0, initial_value=slicer_opacity, length=140) """ Сallbacks for the sliders. """ def change_slice_z(slider): z = int(np.round(slider.value)) image_actor_z.display_extent(0, shape[0] - 1, 0, shape[1] - 1, z, z) def change_slice_x(slider): x = int(np.round(slider.value)) image_actor_x.display_extent(x, x, 0, shape[1] - 1, 0, shape[2] - 1) def change_slice_y(slider): y = int(np.round(slider.value)) image_actor_y.display_extent(0, shape[0] - 1, y, y, 0, shape[2] - 1) def change_opacity(slider): slicer_opacity = slider.value image_actor_z.opacity(slicer_opacity) image_actor_x.opacity(slicer_opacity) image_actor_y.opacity(slicer_opacity) line_slider_z.on_change = change_slice_z line_slider_x.on_change = change_slice_x line_slider_y.on_change = change_slice_y opacity_slider.on_change = change_opacity """ Сreate text labels to identify the sliders. """ def build_label(text): label = ui.TextBlock2D() label.message = text label.font_size = 18 label.font_family = 'Arial' label.justification = 'left' label.bold = False label.italic = False label.shadow = False label.background = (0, 0, 0) label.color = (1, 1, 1) return label line_slider_label_z = build_label(text="Z Slice") line_slider_label_x = build_label(text="X Slice") line_slider_label_y = build_label(text="Y Slice") opacity_slider_label = build_label(text="Opacity") """ Create a ``panel`` to contain the sliders and labels. """ panel = ui.Panel2D(size=(300, 200), color=(1, 1, 1), opacity=0.1, align="right") panel.center = (1030, 120) panel.add_element(line_slider_label_x, (0.1, 0.75)) panel.add_element(line_slider_x, (0.38, 0.75)) panel.add_element(line_slider_label_y, (0.1, 0.55)) panel.add_element(line_slider_y, (0.38, 0.55)) panel.add_element(line_slider_label_z, (0.1, 0.35)) panel.add_element(line_slider_z, (0.38, 0.35)) panel.add_element(opacity_slider_label, (0.1, 0.15)) panel.add_element(opacity_slider, (0.38, 0.15)) scene.add(panel) """ Create a ``panel`` to show the value of a picked voxel. """ label_position = ui.TextBlock2D(text='Position:') label_value = ui.TextBlock2D(text='Value:') result_position = ui.TextBlock2D(text='') result_value = ui.TextBlock2D(text='') text2 = ui.TextBlock2D(text='Calculate') panel_picking = ui.Panel2D(size=(250, 125), color=(1, 1, 1), opacity=0.1, align="left") panel_picking.center = (200, 120) panel_picking.add_element(label_position, (0.1, 0.75)) panel_picking.add_element(label_value, (0.1, 0.45)) panel_picking.add_element(result_position, (0.45, 0.75)) panel_picking.add_element(result_value, (0.45, 0.45)) panel_picking.add_element(text2, (0.1, 0.15)) icon_files = [] icon_files.append(('left', read_viz_icons(fname='circle-left.png'))) button_example = ui.Button2D(icon_fnames=icon_files, size=(100, 30)) panel_picking.add_element(button_example, (0.5, 0.1)) def change_text_callback(i_ren, obj, button): text2.message = str(i_coord) + ' ' + str(j_coord) + ' ' + str(k_coord) torusActor.SetPosition(i_coord, j_coord, k_coord) print(i_coord, j_coord, k_coord) lut, colors = change_TMS_effects(i_coord, j_coord, k_coord) scene.rm(actor_line_list[0]) actor_line_list.append( actor.line(bundle_native, colors, linewidth=5, fake_tube=True, lookup_colormap=lut)) scene.add(actor_line_list[1]) nonlocal number_of_stimulations global bar if number_of_stimulations > 0: scene.rm(bar) else: number_of_stimulations = number_of_stimulations + 1 bar = actor.scalar_bar(lut) bar.SetTitle("TMS effect") bar.SetHeight(0.3) bar.SetWidth(0.10) # the width is set first bar.SetPosition(0.85, 0.3) scene.add(bar) actor_line_list.pop(0) i_ren.force_render() button_example.on_left_mouse_button_clicked = change_text_callback scene.add(panel_picking) scene.add(torusActor) def left_click_callback(obj, ev): """Get the value of the clicked voxel and show it in the panel.""" event_pos = show_m.iren.GetEventPosition() obj.picker.Pick(event_pos[0], event_pos[1], 0, scene) global i_coord, j_coord, k_coord i_coord, j_coord, k_coord = obj.picker.GetPointIJK() print(i_coord, j_coord, k_coord) result_position.message = '({}, {}, {})'.format( str(i_coord), str(j_coord), str(k_coord)) result_value.message = '%.8f' % data_T1[i_coord, j_coord, k_coord] torusActor.SetPosition(i_coord, j_coord, k_coord) image_actor_z.AddObserver('LeftButtonPressEvent', left_click_callback, 1.0) global size size = scene.GetSize() def win_callback(obj, event): global size if size != obj.GetSize(): size_old = size size = obj.GetSize() size_change = [size[0] - size_old[0], 0] panel.re_align(size_change) show_m.initialize() """ Set the following variable to ``True`` to interact with the datasets in 3D. """ interactive = True scene.zoom(2.0) scene.reset_clipping_range() scene.set_camera(position=(-642.07, 495.40, 148.49), focal_point=(127.50, 127.50, 127.50), view_up=(0.02, -0.01, 1.00)) if interactive: show_m.add_window_callback(win_callback) show_m.render() show_m.start() else: window.record(scene, out_path=out_dir + '/bundles_and_effects.png', size=(1200, 900), reset_camera=True)
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:: transformed_trans_0.png :align: center .. figure:: transformed_trans_1.png :align: center .. figure:: transformed_trans_2.png :align: center Registration result by translating the moving image, using Mutual Information. """ """ Now lets refine with a rigid transform (this may even modify our previously found optimal translation) """ transform = RigidTransform3D() params0 = None starting_affine = translation.affine rigid = affreg.optimize(static, moving, transform, params0, static_grid2world, moving_grid2world, starting_affine=starting_affine) """ This produces a slight rotation, and the images are now better aligned """ transformed = rigid.transform(moving) regtools.overlay_slices(static, transformed, None, 0, "Static", "Transformed",
def registration_proxy(in_file, static, out_file): """ http://nipy.org/dipy/examples_built/affine_registration_3d.html in_file --> moving static and moving = path """ import time import numpy as np import nibabel as nb import matplotlib.pyplot as plt from dipy.viz import regtools from dipy.align.imaffine import (transform_centers_of_mass, AffineMap, MutualInformationMetric, AffineRegistration) from dipy.align.transforms import (TranslationTransform3D, RigidTransform3D, AffineTransform3D) t0_time = time.time() print('---> I. Translation of the moving image towards the static image') #condition if we have a path or a nifti file static_img = nb.load(static) static = static_img.get_data() static_grid2world = static_img.affine moving_img = nb.load(in_file) moving = np.array(moving_img.get_data())[..., 0] moving_grid2world = moving_img.affine # resample for have the same number of voxels print( '---> Resembling the moving image on a grid of the same dimensions as the static image' ) identity = np.eye(4) affine_map = AffineMap(identity, static.shape, static_grid2world, moving.shape, moving_grid2world) resampled = affine_map.transform(moving) regtools.overlay_slices(static, resampled, None, 0, "Static", "Moving", "resampled_0.png") regtools.overlay_slices(static, resampled, None, 1, "Static", "Moving", "resampled_1.png") regtools.overlay_slices(static, resampled, None, 2, "Static", "Moving", "resampled_2.png") plt.show() #centers of mass registration print('---> Aligning the centers of mass of the two images') c_of_mass = transform_centers_of_mass(static, static_grid2world, moving, moving_grid2world) transformed = c_of_mass.transform(moving) regtools.overlay_slices(static, transformed, None, 0, "Static", "Transformed", "transformed_com_0.png") regtools.overlay_slices(static, transformed, None, 1, "Static", "Transformed", "transformed_com_1.png") regtools.overlay_slices(static, transformed, None, 2, "Static", "Transformed", "transformed_com_2.png") plt.show() print('---> II. Refine by looking for an affine transform') #affine transform #parameters?? 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] print('---> Computing Affine Registration (non-convex optimization)') 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, moving, transform, params0, static_grid2world, moving_grid2world, starting_affine=starting_affine) transformed = translation.transform(moving) regtools.overlay_slices(static, transformed, None, 0, "Static", "Transformed", "transformed_trans_0.png") regtools.overlay_slices(static, transformed, None, 1, "Static", "Transformed", "transformed_trans_1.png") regtools.overlay_slices(static, transformed, None, 2, "Static", "Transformed", "transformed_trans_2.png") plt.show() print('--->III. Refining with a rigid transform') #rigid transform transform = RigidTransform3D() params0 = None starting_affine = translation.affine rigid = affreg.optimize(static, moving, transform, params0, static_grid2world, moving_grid2world, starting_affine=starting_affine) transformed = rigid.transform(moving) regtools.overlay_slices(static, transformed, None, 0, "Static", "Transformed", "transformed_rigid_0.png") regtools.overlay_slices(static, transformed, None, 1, "Static", "Transformed", "transformed_rigid_1.png") regtools.overlay_slices(static, transformed, None, 2, "Static", "Transformed", "transformed_rigid_2.png") plt.show() print( '--->IV. Refining with a full afine transform (translation, rotation, scale and shear)' ) #full affine transform transform = AffineTransform3D() params0 = None starting_affine = rigid.affine affine = affreg.optimize(static, moving, transform, params0, static_grid2world, moving_grid2world, starting_affine=starting_affine) transformed = affine.transform(moving) regtools.overlay_slices(static, transformed, None, 0, "Static", "Transformed", "transformed_affine_0.png") regtools.overlay_slices(static, transformed, None, 1, "Static", "Transformed", "transformed_affine_1.png") regtools.overlay_slices(static, transformed, None, 2, "Static", "Transformed", "transformed_affine_2.png") plt.show() # Save the new data in a new NIfTI image nb.Nifti1Image(transformed, static_img.affine).to_filename(out_file) #name = os.path.splitext(basename(moving_path))[0] + '_affine_reg' #nib.save(nib.Nifti1Image(transformed, np.eye(4)), name) t1_time = time.time() total_time = t1_time - t0_time print('Total time:' + str(total_time)) print('Translated file now is here: %s' % out_file) return print('Successfully affine registration applied')