def nonlinear_alignment_iteration(iternum=0, gradient_step=0.2): """ Takes a template image and a set of input images, does a linear alignment to the template and updates it with the inverse of the average affine transform to the new template Returns a workflow """ iteration_wf = Workflow(name="nl_iterative_alignment_%03d" % iternum) input_node_fields = ["image_paths", "template_image", "iteration_num"] inputnode = pe.Node( niu.IdentityInterface(fields=input_node_fields), name='inputnode') inputnode.inputs.iteration_num = iternum outputnode = pe.Node( niu.IdentityInterface(fields=["registered_image_paths", "affine_transforms", "warp_transforms", "composite_transforms", "updated_template"]), name='outputnode') ants_settings = pkgrf("qsiprep", "data/intramodal_nonlinear.json") reg = ants.Registration(from_file=ants_settings) iter_reg = pe.MapNode( reg, name="nlreg_%03d" % iternum, iterfield=["moving_image"]) # Average the images averaged_images = pe.Node( ants.AverageImages(normalize=True, dimension=3), name="averaged_images") # Make an automask mask_average = pe.Node(afni.Automask(), name='mask_average') # Shape update to template: # Average the affines so that the inverse can be applied to the template affines_to_list = pe.Node(niu.Merge(1), name="affines_to_list") warps_to_list = pe.Node(niu.Merge(1), name="warps_to_list") avg_affines = pe.Node( ants.AverageAffineTransform(dimension=3, output_affine_transform="AveragedAffines.mat"), name="avg_affines") # Average the warps: average_warps = pe.Node( ants.AverageImages(dimension=3, normalize=False), name="average_warps") # Scale by the gradient step scale_warp = pe.Node( ants.MultiplyImages(dimension=3, second_input=gradient_step, output_product_image="scaled_warp.nii.gz"), name="scale_warp") # Align the warps to the template image align_warp = pe.Node( ants.ApplyTransforms( input_image_type=1, invert_transform_flags=[True]), name="align_warp") # transform the template for the shape update shape_update_template = pe.Node( ants.ApplyTransforms(interpolation="LanczosWindowedSinc", invert_transform_flags=[True, False, False, False, False]), name="shape_update_template") shape_update_merge = pe.Node(niu.Merge(5), name="shape_update_merge") # Run the images through antsRegistration def get_first(input_pairs): return [input_pair[0] for input_pair in input_pairs] def get_second(input_pairs): return [input_pair[1] for input_pair in input_pairs] iteration_wf.connect([ (inputnode, iter_reg, [ ('image_paths', 'moving_image'), ('template_image', 'fixed_image')]), (iter_reg, affines_to_list, [(('forward_transforms', get_first), 'in1')]), (affines_to_list, avg_affines, [('out', 'transforms')]), (iter_reg, warps_to_list, [(('forward_transforms', get_second), 'in1')]), (iter_reg, averaged_images, [('warped_image', 'images')]), # Average the warps, scale them, and transform to be aligned with the template (warps_to_list, average_warps, [('out', 'images')]), (average_warps, scale_warp, [('output_average_image', 'first_input')]), (scale_warp, align_warp, [ ('output_product_image', 'input_image')]), (avg_affines, align_warp, [('affine_transform', 'transforms')]), (inputnode, align_warp, [('template_image', 'reference_image')]), (avg_affines, shape_update_merge, [('affine_transform', 'in1')]), (align_warp, shape_update_merge, [ ('output_image', 'in2'), ('output_image', 'in3'), ('output_image', 'in4'), ('output_image', 'in5')]), (shape_update_merge, shape_update_template, [('out', 'transforms')]), (averaged_images, shape_update_template, [ ('output_average_image', 'input_image'), ('output_average_image', 'reference_image')]), (shape_update_template, outputnode, [('output_image', 'updated_template')]), (iter_reg, outputnode, [ ('forward_transforms', 'affine_transforms'), ('warped_image', 'registered_image_paths')]) ]) return iteration_wf
def linear_alignment_workflow(transform="Rigid", metric="Mattes", iternum=0, precision="precise"): """ Takes a template image and a set of input images, does a linear alignment to the template and updates it with the inverse of the average affine transform to the new template Returns a workflow """ iteration_wf = Workflow(name="iterative_alignment_%03d" % iternum) input_node_fields = ["image_paths", "template_image", "iteration_num"] inputnode = pe.Node(niu.IdentityInterface(fields=input_node_fields), name='inputnode') inputnode.inputs.iteration_num = iternum outputnode = pe.Node(niu.IdentityInterface(fields=[ "registered_image_paths", "affine_transforms", "updated_template" ]), name='outputnode') ants_settings = pkgrf( "qsiprep", "data/shoreline_{precision}_{transform}.json".format( precision=precision, transform=transform)) reg = ants.Registration(from_file=ants_settings) iter_reg = pe.MapNode(reg, name="reg_%03d" % iternum, iterfield=["moving_image"]) # Run the images through antsRegistration iteration_wf.connect(inputnode, "image_paths", iter_reg, "moving_image") iteration_wf.connect(inputnode, "template_image", iter_reg, "fixed_image") # Average the images averaged_images = pe.Node(ants.AverageImages(normalize=True, dimension=3), name="averaged_images") iteration_wf.connect(iter_reg, "warped_image", averaged_images, "images") # Apply the inverse to the average image transforms_to_list = pe.Node(niu.Merge(1), name="transforms_to_list") transforms_to_list.inputs.ravel_inputs = True iteration_wf.connect(iter_reg, "forward_transforms", transforms_to_list, "in1") avg_affines = pe.Node(ants.AverageAffineTransform(), name="avg_affine") avg_affines.inputs.dimension = 3 avg_affines.inputs.output_affine_transform = "AveragedAffines.mat" iteration_wf.connect(transforms_to_list, "out", avg_affines, "transforms") invert_average = pe.Node(ants.ApplyTransforms(), name="invert_average") invert_average.inputs.interpolation = "HammingWindowedSinc" invert_average.inputs.invert_transform_flags = [True] avg_to_list = pe.Node(niu.Merge(1), name="to_list") iteration_wf.connect(avg_affines, "affine_transform", avg_to_list, "in1") iteration_wf.connect(avg_to_list, "out", invert_average, "transforms") iteration_wf.connect(averaged_images, "output_average_image", invert_average, "input_image") iteration_wf.connect(averaged_images, "output_average_image", invert_average, "reference_image") iteration_wf.connect(invert_average, "output_image", outputnode, "updated_template") iteration_wf.connect(iter_reg, "forward_transforms", outputnode, "affine_transforms") iteration_wf.connect(iter_reg, "warped_image", outputnode, "registered_image_paths") return iteration_wf