123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 |
- from helper_functions import files_in_dir, make_dirs, add_slash_to_path, flip_volume_lr, robust_avg_volumes,\
- files_ind_dir_wo_string, avg_template
- import sys
- import getopt
- import os
- import shutil
- from nipype.interfaces import ants
- # Help message.
- tab = ' '
- usage_message = '\nCOMMAND:\n' + tab + sys.argv[0] + \
- '\n\nOPTIONS:\n' + \
- tab + '-h, help menu\n' + \
- tab + '-i, --images, <list of input images> or path to directory with only .nii images.\n' + \
- tab + '-o, --output, <path to output directory>\n' + \
- tab + '-s, --symmetric, [bool] use symmetric modelling. Default: False. Currently only works for 3d images.\n' + \
- tab + '-t, --template, <path to template> can include template. Will not be included in final average. \n' + \
- tab + '-w, --weight, [Double] specifies the weight a given template will have in averages. From 0 to 1. Default: 1/(number of images + 1)\n' + \
- tab + '-l, --log, [bool]>\n'
- # Registration
- def registration(fixed, moving, result, reg_type, sigma, shrink, param, dim, initial_trans='', inverse_result=''):
- """
- Registration function. Registeres the moving image to the fixed with given parameters. If initial transform is not
- given then the images are aligned by center of mass. Outputs inversely transformed result if given.
- :param fixed: Path to fixed image.
- :param moving: Path to moving image.
- :param result: Path to result image.
- :param reg_type: Registration type. List containing, Rigid, Affine, and/or SyN.
- :param sigma: List of sigma parameters. Ordered according to the reg_type parameter.
- :param shrink: List of shrink parameters. Ordered according to the reg_type parameter.
- :param param: List of transform parameters. Ordered according to the reg_type parameter.
- :param dim: Dimension of images. Typically 2 or 3.
- :param initial_trans: Optional path to initial moving transform. If not given, the images will be matched initially
- by aligning the center of mass.
- :param inverse_result: Optional path to the inversely transformed fixed image.
- :return: Returns nothing.
- """
- # Extract number of registrations.
- steps = len(reg_type)
- # Add 1000 iterations for each step.
- if steps == 1:
- iterations = [[1000] * len(sigma[0])]
- else:
- iterations = []
- for i, reg in enumerate(reg_type):
- iteration = [1000] * len(sigma[i])
- iterations.append(iteration)
- # Create registration instance.
- reg_instance = ants.Registration(dimension=dim,
- transforms=reg_type,
- transform_parameters=param,
- metric=['MI']*steps,
- interpolation='BSpline',
- fixed_image=[fixed],
- moving_image=[moving],
- metric_weight=[1]*steps,
- radius_or_number_of_bins=[32]*steps,
- number_of_iterations=iterations,
- smoothing_sigmas=sigma,
- shrink_factors=shrink,
- convergence_threshold=[1.e-7],
- sampling_strategy=['Regular']*steps,
- use_histogram_matching=True,
- winsorize_lower_quantile=0.05,
- winsorize_upper_quantile=0.95,
- output_warped_image=result,
- write_composite_transform=True,
- output_transform_prefix=result.split('.')[0] + '-Transformation',
- num_threads=12)
- # Add initial moving transform if given, else match by center of mass.
- if not initial_trans == '':
- reg_instance.inputs.initial_moving_transform = initial_trans
- else:
- reg_instance.inputs.initial_moving_transform_com = 1
- # Output reverse results if path is given.
- if not inverse_result == '':
- reg_instance.inputs.output_inverse_warped_image = inverse_result
- # Run registration.
- reg_instance.run()
- def create_template_from_images(images_input, results_dir, symmetric=False, template='', template_weight=1,
- r=3, a=2, nl=3, print_log=False):
- """
- Population based template creation from input images. If input template is given this will be part of the averaging
- with weight template_weight. Will perform r rigid, a rigid and affine, and nl rigid, affine, and non-linear
- iterations. Will flip all input images in the left-right plane if symmetric is set to true.
- :param images_input: List of paths to images.
- :param results_dir: Working directory.
- :param symmetric: Boolean [Default: False]. Will flip all input images in the left-right plane if symmetric is set
- to true.
- :param template: str [Default: '']. Will include template in averaging if path is specified.
- :param template_weight: float [Default: 1]. Will weight the template with given weight if set to different from 1.
- Can be in the range of 0 < template_weight < 1.
- :param r: Int [Default: 3]. Number of rigid registrations.
- :param a: Int [Default: 2]. Number of rigid and affine registrations.
- :param nl: Int [Default: 3]. Number of rigid, affine, and non-linear registrations.
- :param print_log: Boolean [Default: False]. Will print log if true.
- :return: Returns nothing.
- """
- out_dir = add_slash_to_path(results_dir)
- make_dirs(out_dir)
- template_present = not template == ''
- if print_log:
- print('Determining images-variable format and defining input images.')
- if isinstance(images_input, list):
- images = images_input
- elif isinstance(images_input, str):
- images_input = add_slash_to_path(images_input)
- images = files_in_dir(images_input, '.nii')
- all_images = images
- if symmetric:
- flipped_path = out_dir + 'raw_flipped/'
- flipped_images = []
- make_dirs(flipped_path)
- if print_log:
- print('Creating flipped images.')
- for image in images:
- flipped_image = flipped_path + image.split('/')[-1].split('.')[0] + '_flipped.nii'
- if not os.path.exists(flipped_image):
- flip_volume_lr(image, flipped_image)
- else:
- if print_log:
- print('Flipped image', flipped_image, 'already present.')
- flipped_images.append(flipped_image)
- all_images.extend(flipped_images)
- if print_log:
- print('Defining iterations.')
- reg_types = ['Rigid'] * r + ['Affine'] * a + ['SyN'] * nl
- if print_log:
- print(reg_types)
- for i, iteration in enumerate(reg_types):
- iteration_nr = str(i).zfill(2)
- cur_it_dir = out_dir + iteration_nr + '/'
- make_dirs(cur_it_dir)
- if i == 0:
- robust_avg_volumes(all_images, out_dir + '00-average.nii')
- if template_present:
- avg_template(out_dir + '00-average.nii',
- template,
- template_weight,
- out_dir + '00-average-template.nii')
- else:
- shutil.rmtree(out_dir + str(i-1).zfill(2))
- average = out_dir + iteration_nr + '-average-template.nii' if template_present else out_dir + iteration_nr + '-average.nii'
- # Iteration specific registration parameters.
- if iteration == 'Rigid':
- reg = ['Rigid']
- params = [(0.25,)]
- sigma = [[4, 4, 2, 2]]
- shrink = [[32, 16, 8, 4]]
- if i == 0:
- sigma = [[4, 4, 4]]
- shrink = [[32, 16, 8]]
- elif iteration == 'Affine':
- reg = ['Rigid', 'Affine']
- params = [(0.25,), (0.25,), ]
- sigma = [[4, 4, 2, 2], [4, 4, 2, 2]]
- shrink = [[32, 16, 8, 4], [32, 16, 8, 4]]
- elif iteration == 'SyN':
- reg = ['Rigid', 'Affine', 'SyN']
- params = [(0.25,), (0.25,), (0.15, 3, 0.5)]
- sigma = [[4, 4, 2, 2], [4, 4, 2, 2], [4, 4, 4, 2]]
- shrink = [[32, 16, 8, 4], [32, 16, 8, 4], [64, 32, 16, 8]]
- if i == len(reg_types) - 1:
- sigma = [[4, 4, 2, 2], [4, 4, 2, 2], [4, 4, 4, 2, 1]]
- shrink = [[32, 16, 8, 4], [32, 16, 8, 4], [64, 32, 16, 8, 4]]
- else:
- sys.exit('The registration type "' + str(iteration) + '" does not exist. Reconstruction stopped.')
- if template_present:
- all_images.extend([template])
- for image in all_images:
- reg_output = cur_it_dir + image.split('/')[-1]
- registration(average, image, reg_output, reg, sigma, shrink, params, dim=3)
- registered_images = files_ind_dir_wo_string(cur_it_dir, '-Transformation')
- registered_images_wo_allen = []
- for reg_image in registered_images:
- if 'allen' in reg_image:
- registered_allen = reg_image
- else:
- registered_images_wo_allen.append(reg_image)
- robust_avg_volumes(registered_images_wo_allen, out_dir + str(i+1).zfill(2) + '-average.nii')
- if template_present:
- avg_template(out_dir + str(i+1).zfill(2) + '-average.nii',
- registered_allen,
- template_weight,
- out_dir + str(i + 1).zfill(2) + '-average-template.nii')
- if __name__ == '__main__':
- arguments = sys.argv
- input_symmetric = False
- input_robust = True
- input_template = ''
- input_weight = 1
- show_log = False
- if len(arguments) == 1:
- print(usage_message)
- else:
- try:
- opts, args = getopt.getopt(arguments[1:], "hi:o:s:t:w:l:", ["images=", "output=", "symmetric=",
- "template=", "weight=", "log="])
- except getopt.GetoptError:
- print('\nSomething is not right in your syntax. Tak a look at your possibilities:\n', usage_message)
- sys.exit(2)
- for opt, arg in opts:
- if opt == "-h":
- print(usage_message)
- sys.exit()
- elif opt in ("-i", "--images"):
- input_images = arg
- elif opt in ("-o", "--output"):
- output_directory = arg
- elif opt in ("-s", "--symmetric"):
- if arg == 'True' or arg == 'true':
- input_symmetric = True
- elif arg == 'False' or arg == 'false':
- input_symmetric = False
- else:
- print('\nSomething is not right in your syntax. Tak a look at your possibilities:\n', usage_message)
- elif opt in ("-t", "--template"):
- input_template = arg
- elif opt in ("-w", "--weight"):
- input_weight = arg
- elif opt in ("-l", "--log"):
- if arg == 'True' or arg == 'true':
- show_log = True
- elif arg == 'False' or arg == 'false':
- show_log = False
- else:
- print('\nSomething is not right in your syntax. Tak a look at your possibilities:\n', usage_message)
- sys.exit(2)
- try:
- create_template_from_images(input_images,
- output_directory,
- symmetric=input_symmetric,
- template=input_template,
- template_weight=input_weight,
- print_log=show_log)
- except NameError:
- print('\nYou are not (properly) defining all the input variables. Tak a look at what is needed:\n',
- usage_message)
|