def register(param, file_src, file_dest, file_mat, file_out): # initialization failed_transfo = 0 # by default, failed matrix is 0 (i.e., no failure) # get metric radius (if MeanSquares, CC) or nb bins (if MI) if param.param[3] == 'MI': metric_radius = '16' else: metric_radius = '4' # register file_src to file_dest if param.todo == 'estimate' or param.todo == 'estimate_and_apply': cmd = 'isct_antsSliceRegularizedRegistration' \ ' -p '+param.param[0]+ \ ' --transform Translation['+param.param[2]+']' \ ' --metric '+param.param[3]+'['+file_dest+'.nii, '+file_src+'.nii, 1, '+metric_radius+', Regular, 0.2]' \ ' --iterations 5' \ ' --shrinkFactors 1' \ ' --smoothingSigmas '+param.param[1]+ \ ' --output ['+file_mat+','+file_out+'.nii]' \ +sct.get_interpolation('isct_antsSliceRegularizedRegistration', param.interp) if not param.fname_mask == '': cmd += ' -x ' + param.fname_mask if param.todo == 'apply': cmd = 'sct_apply_transfo -i ' + file_src + '.nii -d ' + file_dest + '.nii -w ' + file_mat + 'Warp.nii.gz' + ' -o ' + file_out + '.nii' + ' -x ' + param.interp status, output = sct.run(cmd, param.verbose) # check if output file exists if not os.path.isfile(file_out + '.nii'): # sct.printv(output, verbose, 'error') sct.printv( 'WARNING in ' + os.path.basename(__file__) + ': Improper calculation of mutual information. Either the mask you provided is too small, or the subject moved a lot. If you see too many messages like this try with a bigger mask. Using previous transformation for this volume.', param.verbose, 'warning') failed_transfo = 1 # return status of failure return failed_transfo
def register(param, file_src, file_dest, file_mat, file_out): # initialization failed_transfo = 0 # by default, failed matrix is 0 (i.e., no failure) # get metric radius (if MeanSquares, CC) or nb bins (if MI) if param.param[3] == 'MI': metric_radius = '16' else: metric_radius = '4' # register file_src to file_dest if param.todo == 'estimate' or param.todo == 'estimate_and_apply': cmd = 'isct_antsSliceRegularizedRegistration' \ ' -p '+param.param[0]+ \ ' --transform Translation['+param.param[2]+']' \ ' --metric '+param.param[3]+'['+file_dest+'.nii, '+file_src+'.nii, 1, '+metric_radius+', Regular, 0.2]' \ ' --iterations 5' \ ' --shrinkFactors 1' \ ' --smoothingSigmas '+param.param[1]+ \ ' --output ['+file_mat+','+file_out+'.nii]' \ +sct.get_interpolation('isct_antsSliceRegularizedRegistration', param.interp) if not param.fname_mask == '': cmd += ' -x '+param.fname_mask if param.todo == 'apply': cmd = 'sct_apply_transfo -i '+file_src+'.nii -d '+file_dest+'.nii -w '+file_mat+'Warp.nii.gz'+' -o '+file_out+'.nii'+' -x '+param.interp status, output = sct.run(cmd, param.verbose) # check if output file exists if not os.path.isfile(file_out+'.nii'): # sct.printv(output, verbose, 'error') sct.printv('WARNING in '+os.path.basename(__file__)+': Improper calculation of mutual information. Either the mask you provided is too small, or the subject moved a lot. If you see too many messages like this try with a bigger mask. Using previous transformation for this volume.', param.verbose, 'warning') failed_transfo = 1 # return status of failure return failed_transfo
def register(param, file_src, file_dest, file_mat, file_out): # initialization failed_transfo = 0 # by default, failed matrix is 0 (i.e., no failure) # get metric radius (if MeanSquares, CC) or nb bins (if MI) if param.param[3] == "MI": metric_radius = "16" else: metric_radius = "4" # register file_src to file_dest if param.todo == "estimate" or param.todo == "estimate_and_apply": cmd = ( "isct_antsSliceRegularizedRegistration" " -p " + param.param[0] + " --transform Translation[" + param.param[2] + "]" " --metric " + param.param[3] + "[" + file_dest + ".nii, " + file_src + ".nii, 1, " + metric_radius + ", Regular, 0.2]" " --iterations 5" " --shrinkFactors 1" " --smoothingSigmas " + param.param[1] + " --output [" + file_mat + "," + file_out + ".nii]" + sct.get_interpolation("isct_antsSliceRegularizedRegistration", param.interp) ) if not param.fname_mask == "": cmd += " -x " + param.fname_mask if param.todo == "apply": cmd = ( "sct_apply_transfo -i " + file_src + ".nii -d " + file_dest + ".nii -w " + file_mat + "Warp.nii.gz" + " -o " + file_out + ".nii" + " -x " + param.interp ) status, output = sct.run(cmd, param.verbose) # check if output file exists if not os.path.isfile(file_out + ".nii"): # sct.printv(output, verbose, 'error') sct.printv( "WARNING in " + os.path.basename(__file__) + ": Improper calculation of mutual information. Either the mask you provided is too small, or the subject moved a lot. If you see too many messages like this try with a bigger mask. Using previous transformation for this volume.", param.verbose, "warning", ) failed_transfo = 1 # return status of failure return failed_transfo
def apply(self): # Initialization fname_src = self.input_filename # source image (moving) list_warp = self.list_warp # list of warping fields fname_out = self.output_filename # output fname_dest = self.fname_dest # destination image (fix) verbose = self.verbose remove_temp_files = self.remove_temp_files crop_reference = self.crop # if = 1, put 0 everywhere around warping field, if = 2, real crop interp = sct.get_interpolation('isct_antsApplyTransforms', self.interp) # Parse list of warping fields sct.printv('\nParse list of warping fields...', verbose) use_inverse = [] fname_warp_list_invert = [] # list_warp = list_warp.replace(' ', '') # remove spaces # list_warp = list_warp.split(",") # parse with comma for idx_warp, path_warp in enumerate(self.list_warp): # Check if this transformation should be inverted if path_warp in self.list_warpinv: use_inverse.append('-i') # list_warp[idx_warp] = path_warp[1:] # remove '-' fname_warp_list_invert += [[ use_inverse[idx_warp], list_warp[idx_warp] ]] else: use_inverse.append('') fname_warp_list_invert += [[path_warp]] path_warp = list_warp[idx_warp] if path_warp.endswith((".nii", ".nii.gz")) \ and msct_image.Image(list_warp[idx_warp]).header.get_intent()[0] != 'vector': raise ValueError("Displacement field in {} is invalid: should be encoded" \ " in a 5D file with vector intent code" \ " (see https://nifti.nimh.nih.gov/pub/dist/src/niftilib/nifti1.h" \ .format(path_warp)) # need to check if last warping field is an affine transfo isLastAffine = False path_fname, file_fname, ext_fname = sct.extract_fname( fname_warp_list_invert[-1][-1]) if ext_fname in ['.txt', '.mat']: isLastAffine = True # check if destination file is 3d if not sct.check_if_3d(fname_dest): sct.printv('ERROR: Destination data must be 3d') # N.B. Here we take the inverse of the warp list, because sct_WarpImageMultiTransform concatenates in the reverse order fname_warp_list_invert.reverse() fname_warp_list_invert = functools.reduce(lambda x, y: x + y, fname_warp_list_invert) # Extract path, file and extension path_src, file_src, ext_src = sct.extract_fname(fname_src) path_dest, file_dest, ext_dest = sct.extract_fname(fname_dest) # Get output folder and file name if fname_out == '': path_out = '' # output in user's current directory file_out = file_src + '_reg' ext_out = ext_src fname_out = os.path.join(path_out, file_out + ext_out) # Get dimensions of data sct.printv('\nGet dimensions of data...', verbose) img_src = msct_image.Image(fname_src) nx, ny, nz, nt, px, py, pz, pt = img_src.dim # nx, ny, nz, nt, px, py, pz, pt = sct.get_dimension(fname_src) sct.printv( ' ' + str(nx) + ' x ' + str(ny) + ' x ' + str(nz) + ' x ' + str(nt), verbose) # if 3d if nt == 1: # Apply transformation sct.printv('\nApply transformation...', verbose) if nz in [0, 1]: dim = '2' else: dim = '3' sct.run([ 'isct_antsApplyTransforms', '-d', dim, '-i', fname_src, '-o', fname_out, '-t' ] + fname_warp_list_invert + ['-r', fname_dest] + interp, verbose=verbose, is_sct_binary=True) # if 4d, loop across the T dimension else: path_tmp = sct.tmp_create(basename="apply_transfo", verbose=verbose) # convert to nifti into temp folder sct.printv( '\nCopying input data to tmp folder and convert to nii...', verbose) img_src.save(os.path.join(path_tmp, "data.nii")) sct.copy(fname_dest, os.path.join(path_tmp, file_dest + ext_dest)) fname_warp_list_tmp = [] for fname_warp in list_warp: path_warp, file_warp, ext_warp = sct.extract_fname(fname_warp) sct.copy(fname_warp, os.path.join(path_tmp, file_warp + ext_warp)) fname_warp_list_tmp.append(file_warp + ext_warp) fname_warp_list_invert_tmp = fname_warp_list_tmp[::-1] curdir = os.getcwd() os.chdir(path_tmp) # split along T dimension sct.printv('\nSplit along T dimension...', verbose) im_dat = msct_image.Image('data.nii') im_header = im_dat.hdr data_split_list = sct_image.split_data(im_dat, 3) for im in data_split_list: im.save() # apply transfo sct.printv('\nApply transformation to each 3D volume...', verbose) for it in range(nt): file_data_split = 'data_T' + str(it).zfill(4) + '.nii' file_data_split_reg = 'data_reg_T' + str(it).zfill(4) + '.nii' status, output = sct.run([ 'isct_antsApplyTransforms', '-d', '3', '-i', file_data_split, '-o', file_data_split_reg, '-t', ] + fname_warp_list_invert_tmp + [ '-r', file_dest + ext_dest, ] + interp, verbose, is_sct_binary=True) # Merge files back sct.printv('\nMerge file back...', verbose) import glob path_out, name_out, ext_out = sct.extract_fname(fname_out) # im_list = [Image(file_name) for file_name in glob.glob('data_reg_T*.nii')] # concat_data use to take a list of image in input, now takes a list of file names to open the files one by one (see issue #715) fname_list = glob.glob('data_reg_T*.nii') fname_list.sort() im_out = sct_image.concat_data(fname_list, 3, im_header['pixdim']) im_out.save(name_out + ext_out) os.chdir(curdir) sct.generate_output_file( os.path.join(path_tmp, name_out + ext_out), fname_out) # Delete temporary folder if specified if int(remove_temp_files): sct.printv('\nRemove temporary files...', verbose) sct.rmtree(path_tmp, verbose=verbose) # 2. crop the resulting image using dimensions from the warping field warping_field = fname_warp_list_invert[-1] # if last warping field is an affine transfo, we need to compute the space of the concatenate warping field: if isLastAffine: sct.printv( 'WARNING: the resulting image could have wrong apparent results. You should use an affine transformation as last transformation...', verbose, 'warning') elif crop_reference == 1: ImageCropper(input_file=fname_out, output_file=fname_out, ref=warping_field, background=0).crop() # sct.run('sct_crop_image -i '+fname_out+' -o '+fname_out+' -ref '+warping_field+' -b 0') elif crop_reference == 2: ImageCropper(input_file=fname_out, output_file=fname_out, ref=warping_field).crop() # sct.run('sct_crop_image -i '+fname_out+' -o '+fname_out+' -ref '+warping_field) sct.display_viewer_syntax([fname_dest, fname_out], verbose=verbose)
def main(): # Initialization fname_src = '' # source image (moving) fname_warp_list = '' # list of warping fields fname_dest = '' # destination image (fix) fname_src_reg = '' verbose = 1 fsloutput = 'export FSLOUTPUTTYPE=NIFTI; ' # for faster processing, all outputs are in NIFTI crop_reference = 0 # if = 1, put 0 everywhere around warping field, if = 2, real crop # Parameters for debug mode if param.debug: print '\n*** WARNING: DEBUG MODE ON ***\n' # get path of the testing data status, path_sct_data = commands.getstatusoutput('echo $SCT_TESTING_DATA_DIR') fname_src = path_sct_data+'/template/MNI-Poly-AMU_T2.nii.gz' fname_warp_list = path_sct_data+'/t2/warp_template2anat.nii.gz' fname_dest = path_sct_data+'/t2/t2.nii.gz' verbose = 1 else: # Check input parameters try: opts, args = getopt.getopt(sys.argv[1:], 'hi:d:o:v:w:x:c:') except getopt.GetoptError: usage() if not opts: usage() for opt, arg in opts: if opt == '-h': usage() elif opt in ('-i'): fname_src = arg elif opt in ('-d'): fname_dest = arg elif opt in ('-o'): fname_src_reg = arg elif opt in ('-x'): param.interp = arg elif opt in ('-v'): verbose = int(arg) elif opt in ('-w'): fname_warp_list = arg elif opt in ('-c'): crop_reference = int(arg) # display usage if a mandatory argument is not provided if fname_src == '' or fname_warp_list == '' or fname_dest == '': usage() # get the right interpolation field depending on method interp = sct.get_interpolation('isct_antsApplyTransforms', param.interp) # Parse list of warping fields sct.printv('\nParse list of warping fields...', verbose) use_inverse = [] fname_warp_list_invert = [] fname_warp_list = fname_warp_list.replace(' ', '') # remove spaces fname_warp_list = fname_warp_list.split(",") # parse with comma for i in range(len(fname_warp_list)): # Check if inverse matrix is specified with '-' at the beginning of file name if fname_warp_list[i].find('-') == 0: use_inverse.append('-i ') fname_warp_list[i] = fname_warp_list[i][1:] # remove '-' else: use_inverse.append('') sct.printv(' Transfo #'+str(i)+': '+use_inverse[i]+fname_warp_list[i], verbose) fname_warp_list_invert.append(use_inverse[i]+fname_warp_list[i]) # need to check if last warping field is an affine transfo isLastAffine = False path_fname, file_fname, ext_fname = sct.extract_fname(fname_warp_list_invert[-1]) if ext_fname in ['.txt','.mat']: isLastAffine = True # Check file existence sct.printv('\nCheck file existence...', verbose) sct.check_file_exist(fname_src) sct.check_file_exist(fname_dest) for i in range(len(fname_warp_list)): # check if file exist sct.check_file_exist(fname_warp_list[i]) for i in range(len(fname_warp_list_invert)): sct.check_file_exist(fname_warp_list_invert[i]) # check if destination file is 3d sct.check_if_3d(fname_dest) # N.B. Here we take the inverse of the warp list, because sct_WarpImageMultiTransform concatenates in the reverse order fname_warp_list_invert.reverse() # Extract path, file and extension # path_src, file_src, ext_src = sct.extract_fname(os.path.abspath(fname_src)) # fname_dest = os.path.abspath(fname_dest) path_src, file_src, ext_src = sct.extract_fname(fname_src) # fname_dest = os.path.abspath(fname_dest # Get output folder and file name if fname_src_reg == '': path_out = '' # output in user's current directory file_out = file_src+'_reg' ext_out = ext_src fname_out = path_out+file_out+ext_out else: # path_out, file_out, ext_out = sct.extract_fname(fname_src_reg) fname_out = fname_src_reg # Get dimensions of data sct.printv('\nGet dimensions of data...', verbose) nx, ny, nz, nt, px, py, pz, pt = sct.get_dimension(fname_src) sct.printv(' ' + str(nx) + ' x ' + str(ny) + ' x ' + str(nz)+ ' x ' + str(nt), verbose) # if 3d if nt == 1: # Apply transformation sct.printv('\nApply transformation...', verbose) sct.run('isct_antsApplyTransforms -d 3 -i '+fname_src+' -o '+fname_out+' -t '+' '.join(fname_warp_list_invert)+' -r '+fname_dest+interp, verbose) # if 4d, loop across the T dimension else: # create temporary folder sct.printv('\nCreate temporary folder...', verbose) path_tmp = sct.slash_at_the_end('tmp.'+time.strftime("%y%m%d%H%M%S"), 1) sct.run('mkdir '+path_tmp, verbose) # Copying input data to tmp folder # NB: cannot use c3d here because c3d cannot convert 4D data. sct.printv('\nCopying input data to tmp folder and convert to nii...', verbose) sct.run('cp '+fname_src+' '+path_tmp+'data'+ext_src, verbose) # go to tmp folder os.chdir(path_tmp) # convert to nii format sct.run('fslchfiletype NIFTI data', verbose) # split along T dimension sct.printv('\nSplit along T dimension...', verbose) sct.run(fsloutput+'fslsplit data data_T', verbose) # apply transfo sct.printv('\nApply transformation to each 3D volume...', verbose) for it in range(nt): file_data_split = 'data_T'+str(it).zfill(4)+'.nii' file_data_split_reg = 'data_reg_T'+str(it).zfill(4)+'.nii' sct.run('isct_antsApplyTransforms -d 3 -i '+file_data_split+' -o '+file_data_split_reg+' -t '+' '.join(fname_warp_list_invert)+' -r '+fname_dest+interp, verbose) # Merge files back sct.printv('\nMerge file back...', verbose) cmd = fsloutput+'fslmerge -t '+fname_out for it in range(nt): file_data_split_reg = 'data_reg_T'+str(it).zfill(4)+'.nii' cmd = cmd+' '+file_data_split_reg sct.run(cmd, param.verbose) # come back to parent folder os.chdir('..') # 2. crop the resulting image using dimensions from the warping field warping_field = fname_warp_list_invert[-1] # if last warping field is an affine transfo, we need to compute the space of the concatenate warping field: if isLastAffine: sct.printv('WARNING: the resulting image could have wrong apparent results. You should use an affine transformation as last transformation...',1,'warning') elif crop_reference == 1: sct.run('sct_crop_image -i '+fname_out+' -o '+fname_out+' -ref '+warping_field+' -b 0') elif crop_reference == 2: sct.run('sct_crop_image -i '+fname_out+' -o '+fname_out+' -ref '+warping_field) # display elapsed time sct.printv('\nDone! To view results, type:', verbose) sct.printv('fslview '+fname_dest+' '+fname_out+' &\n', verbose, 'info')
def register(param, file_src, file_dest, file_mat, file_out, im_mask=None): """ Register two images by estimating slice-wise Tx and Ty transformations, which are regularized along Z. This function uses ANTs' isct_antsSliceRegularizedRegistration. :param param: :param file_src: :param file_dest: :param file_mat: :param file_out: :param im_mask: Image of mask, could be 2D or 3D :return: """ # TODO: deal with mask # initialization failed_transfo = 0 # by default, failed matrix is 0 (i.e., no failure) do_registration = True # get metric radius (if MeanSquares, CC) or nb bins (if MI) if param.metric == 'MI': metric_radius = '16' else: metric_radius = '4' file_out_concat = file_out kw = dict() im_data = Image( file_src ) # TODO: pass argument to use antsReg instead of opening Image each time # register file_src to file_dest if param.todo == 'estimate' or param.todo == 'estimate_and_apply': # If orientation is sagittal, use antsRegistration in 2D mode # Note: the parameter --restrict-deformation is irrelevant with affine transfo if im_data.orientation[2] in 'LR': cmd = [ 'isct_antsRegistration', '-d', '2', '--transform', 'Affine[%s]' % param.gradStep, '--metric', param.metric + '[' + file_dest + ',' + file_src + ',1,' + metric_radius + ',Regular,' + param.sampling + ']', '--convergence', param.iter, '--shrink-factors', '1', '--smoothing-sigmas', param.smooth, '--verbose', '1', '--output', '[' + file_mat + ',' + file_out_concat + ']' ] cmd += sct.get_interpolation('isct_antsRegistration', param.interp) if im_mask is not None: # if user specified a mask, make sure there are non-null voxels in the image before running the registration if np.count_nonzero(im_mask.data): cmd += ['--masks', im_mask.absolutepath] else: # Mask only contains zeros. Copying the image instead of estimating registration. sct.copy(file_src, file_out_concat, verbose=0) do_registration = False # TODO: create affine mat file with identity, in case used by -g 2 # 3D mode else: cmd = [ 'isct_antsSliceRegularizedRegistration', '--polydegree', param.poly, '--transform', 'Translation[%s]' % param.gradStep, '--metric', param.metric + '[' + file_dest + ',' + file_src + ',1,' + metric_radius + ',Regular,' + param.sampling + ']', '--iterations', param.iter, '--shrinkFactors', '1', '--smoothingSigmas', param.smooth, '--verbose', '1', '--output', '[' + file_mat + ',' + file_out_concat + ']' ] cmd += sct.get_interpolation( 'isct_antsSliceRegularizedRegistration', param.interp) if im_mask is not None: cmd += ['--mask', im_mask.absolutepath] # run command if do_registration: kw.update(dict(is_sct_binary=True)) env = dict() env.update(os.environ) env = kw.get("env", env) # reducing the number of CPU used for moco (see issue #201) env["ITK_GLOBAL_DEFAULT_NUMBER_OF_THREADS"] = "1" status, output = sct.run(cmd, verbose=0, **kw) elif param.todo == 'apply': sct_apply_transfo.main(args=[ '-i', file_src, '-d', file_dest, '-w', file_mat + 'Warp.nii.gz', '-o', file_out_concat, '-x', param.interp, '-v', '0' ]) # check if output file exists if not os.path.isfile(file_out_concat): # sct.printv(output, verbose, 'error') sct.printv( 'WARNING in ' + os.path.basename(__file__) + ': No output. Maybe related to improper calculation of ' 'mutual information. Either the mask you provided is ' 'too small, or the subject moved a lot. If you see too ' 'many messages like this try with a bigger mask. ' 'Using previous transformation for this volume (if it' 'exists).', param.verbose, 'warning') failed_transfo = 1 # TODO: if sagittal, copy header (because ANTs screws it) and add singleton in 3rd dimension (for z-concatenation) if im_data.orientation[2] in 'LR' and do_registration: im_out = Image(file_out_concat) im_out.header = im_data.header im_out.data = np.expand_dims(im_out.data, 2) im_out.save(file_out, verbose=0) # return status of failure return failed_transfo
def apply(self): # Initialization fname_src = self.input_filename # source image (moving) fname_warp_list = self.warp_input # list of warping fields fname_dest = self.output_filename # destination image (fix) fname_src_reg = self.source_reg verbose = self.verbose remove_temp_files = self.remove_temp_files fsloutput = 'export FSLOUTPUTTYPE=NIFTI; ' # for faster processing, all outputs are in NIFTI crop_reference = self.crop # if = 1, put 0 everywhere around warping field, if = 2, real crop # Parameters for debug mode if self.debug: print '\n*** WARNING: DEBUG MODE ON ***\n' # get path of the testing data status, path_sct_data = commands.getstatusoutput('echo $SCT_TESTING_DATA_DIR') fname_src = path_sct_data+'/template/MNI-Poly-AMU_T2.nii.gz' fname_warp_list = path_sct_data+'/t2/warp_template2anat.nii.gz' fname_dest = path_sct_data+'/t2/t2.nii.gz' verbose = 1 interp = sct.get_interpolation('isct_antsApplyTransforms', self.interp) # Parse list of warping fields sct.printv('\nParse list of warping fields...', verbose) use_inverse = [] fname_warp_list_invert = [] # fname_warp_list = fname_warp_list.replace(' ', '') # remove spaces # fname_warp_list = fname_warp_list.split(",") # parse with comma for i in range(len(fname_warp_list)): # Check if inverse matrix is specified with '-' at the beginning of file name if fname_warp_list[i].find('-') == 0: use_inverse.append('-i ') fname_warp_list[i] = fname_warp_list[i][1:] # remove '-' else: use_inverse.append('') sct.printv(' Transfo #'+str(i)+': '+use_inverse[i]+fname_warp_list[i], verbose) fname_warp_list_invert.append(use_inverse[i]+fname_warp_list[i]) # need to check if last warping field is an affine transfo isLastAffine = False path_fname, file_fname, ext_fname = sct.extract_fname(fname_warp_list_invert[-1]) if ext_fname in ['.txt','.mat']: isLastAffine = True # Check file existence sct.printv('\nCheck file existence...', verbose) sct.check_file_exist(fname_src, self.verbose) sct.check_file_exist(fname_dest, self.verbose) for i in range(len(fname_warp_list)): # check if file exist sct.check_file_exist(fname_warp_list[i], self.verbose) # check if destination file is 3d sct.check_if_3d(fname_dest) # N.B. Here we take the inverse of the warp list, because sct_WarpImageMultiTransform concatenates in the reverse order fname_warp_list_invert.reverse() # Extract path, file and extension path_src, file_src, ext_src = sct.extract_fname(fname_src) path_dest, file_dest, ext_dest = sct.extract_fname(fname_dest) # Get output folder and file name if fname_src_reg == '': path_out = '' # output in user's current directory file_out = file_src+'_reg' ext_out = ext_src fname_out = path_out+file_out+ext_out else: fname_out = fname_src_reg # Get dimensions of data sct.printv('\nGet dimensions of data...', verbose) nx, ny, nz, nt, px, py, pz, pt = sct.get_dimension(fname_src) sct.printv(' ' + str(nx) + ' x ' + str(ny) + ' x ' + str(nz)+ ' x ' + str(nt), verbose) # if 3d if nt == 1: # Apply transformation sct.printv('\nApply transformation...', verbose) sct.run('isct_antsApplyTransforms -d 3 -i '+fname_src+' -o '+fname_out+' -t '+' '.join(fname_warp_list_invert)+' -r '+fname_dest+interp, verbose) # if 4d, loop across the T dimension else: # create temporary folder sct.printv('\nCreate temporary folder...', verbose) path_tmp = sct.slash_at_the_end('tmp.'+time.strftime("%y%m%d%H%M%S"), 1) # sct.run('mkdir '+path_tmp, verbose) sct.run('mkdir '+path_tmp, verbose) # Copying input data to tmp folder # NB: cannot use c3d here because c3d cannot convert 4D data. sct.printv('\nCopying input data to tmp folder and convert to nii...', verbose) sct.run('cp '+fname_src+' '+path_tmp+'data'+ext_src, verbose) sct.run('cp '+fname_dest+' '+path_tmp+'dest'+ext_dest, verbose) for i,warp in enumerate(fname_warp_list_invert): sct.run('cp ' + warp + ' ' + path_tmp + warp, verbose) # go to tmp folder os.chdir(path_tmp) try: # convert to nii format sct.run('fslchfiletype NIFTI data', verbose) # split along T dimension sct.printv('\nSplit along T dimension...', verbose) sct.run(fsloutput+'fslsplit data data_T', verbose) # apply transfo sct.printv('\nApply transformation to each 3D volume...', verbose) for it in range(nt): file_data_split = 'data_T'+str(it).zfill(4)+'.nii' file_data_split_reg = 'data_reg_T'+str(it).zfill(4)+'.nii' sct.run('isct_antsApplyTransforms -d 3 -i '+file_data_split+' -o '+file_data_split_reg+' -t '+' '.join(fname_warp_list_invert)+' -r dest'+ext_dest+interp, verbose) # Merge files back sct.printv('\nMerge file back...', verbose) #cmd = fsloutput+'fslmerge -t '+fname_out cmd = 'fslmerge -t '+fname_out for it in range(nt): file_data_split_reg = 'data_reg_T'+str(it).zfill(4)+'.nii' cmd = cmd+' '+file_data_split_reg sct.run(cmd, verbose) except Exception, e: raise e # Copy result to parent folder sct.run('cp ' + fname_out + ' ../' + fname_out) # come back to parent folder os.chdir('..') # Delete temporary folder if specified if int(remove_temp_files): sct.printv('\nRemove temporary files...', verbose) sct.run('rm -rf '+path_tmp, verbose)
def apply(self): # Initialization fname_src = self.input_filename # source image (moving) fname_warp_list = self.warp_input # list of warping fields fname_out = self.output_filename # output fname_dest = self.fname_dest # destination image (fix) verbose = self.verbose remove_temp_files = self.remove_temp_files crop_reference = self.crop # if = 1, put 0 everywhere around warping field, if = 2, real crop interp = sct.get_interpolation('isct_antsApplyTransforms', self.interp) # Parse list of warping fields sct.printv('\nParse list of warping fields...', verbose) use_inverse = [] fname_warp_list_invert = [] # fname_warp_list = fname_warp_list.replace(' ', '') # remove spaces # fname_warp_list = fname_warp_list.split(",") # parse with comma for idx_warp, path_warp in enumerate(fname_warp_list): # Check if inverse matrix is specified with '-' at the beginning of file name if path_warp.startswith("-"): use_inverse.append('-i') fname_warp_list[idx_warp] = path_warp[1:] # remove '-' fname_warp_list_invert += [[use_inverse[idx_warp], fname_warp_list[idx_warp]]] else: use_inverse.append('') fname_warp_list_invert += [[path_warp]] path_warp = fname_warp_list[idx_warp] if path_warp.endswith((".nii", ".nii.gz")) \ and msct_image.Image(fname_warp_list[idx_warp]).header.get_intent()[0] != 'vector': raise ValueError("Displacement field in {} is invalid: should be encoded" \ " in a 5D file with vector intent code" \ " (see https://nifti.nimh.nih.gov/pub/dist/src/niftilib/nifti1.h" \ .format(path_warp)) # need to check if last warping field is an affine transfo isLastAffine = False path_fname, file_fname, ext_fname = sct.extract_fname(fname_warp_list_invert[-1][-1]) if ext_fname in ['.txt', '.mat']: isLastAffine = True # check if destination file is 3d if not sct.check_if_3d(fname_dest): sct.printv('ERROR: Destination data must be 3d') # N.B. Here we take the inverse of the warp list, because sct_WarpImageMultiTransform concatenates in the reverse order fname_warp_list_invert.reverse() fname_warp_list_invert = functools.reduce(lambda x,y: x+y, fname_warp_list_invert) # Extract path, file and extension path_src, file_src, ext_src = sct.extract_fname(fname_src) path_dest, file_dest, ext_dest = sct.extract_fname(fname_dest) # Get output folder and file name if fname_out == '': path_out = '' # output in user's current directory file_out = file_src + '_reg' ext_out = ext_src fname_out = os.path.join(path_out, file_out + ext_out) # Get dimensions of data sct.printv('\nGet dimensions of data...', verbose) img_src = msct_image.Image(fname_src) nx, ny, nz, nt, px, py, pz, pt = img_src.dim # nx, ny, nz, nt, px, py, pz, pt = sct.get_dimension(fname_src) sct.printv(' ' + str(nx) + ' x ' + str(ny) + ' x ' + str(nz) + ' x ' + str(nt), verbose) # if 3d if nt == 1: # Apply transformation sct.printv('\nApply transformation...', verbose) if nz in [0, 1]: dim = '2' else: dim = '3' sct.run(['isct_antsApplyTransforms', '-d', dim, '-i', fname_src, '-o', fname_out, '-t', ] + fname_warp_list_invert + [ '-r', fname_dest, ] + interp, verbose=verbose, is_sct_binary=True) # if 4d, loop across the T dimension else: path_tmp = sct.tmp_create(basename="apply_transfo", verbose=verbose) # convert to nifti into temp folder sct.printv('\nCopying input data to tmp folder and convert to nii...', verbose) img_src.save(os.path.join(path_tmp, "data.nii")) sct.copy(fname_dest, os.path.join(path_tmp, file_dest + ext_dest)) fname_warp_list_tmp = [] for fname_warp in fname_warp_list: path_warp, file_warp, ext_warp = sct.extract_fname(fname_warp) sct.copy(fname_warp, os.path.join(path_tmp, file_warp + ext_warp)) fname_warp_list_tmp.append(file_warp + ext_warp) fname_warp_list_invert_tmp = fname_warp_list_tmp[::-1] curdir = os.getcwd() os.chdir(path_tmp) # split along T dimension sct.printv('\nSplit along T dimension...', verbose) im_dat = msct_image.Image('data.nii') im_header = im_dat.hdr data_split_list = sct_image.split_data(im_dat, 3) for im in data_split_list: im.save() # apply transfo sct.printv('\nApply transformation to each 3D volume...', verbose) for it in range(nt): file_data_split = 'data_T' + str(it).zfill(4) + '.nii' file_data_split_reg = 'data_reg_T' + str(it).zfill(4) + '.nii' status, output = sct.run(['isct_antsApplyTransforms', '-d', '3', '-i', file_data_split, '-o', file_data_split_reg, '-t', ] + fname_warp_list_invert_tmp + [ '-r', file_dest + ext_dest, ] + interp, verbose, is_sct_binary=True) # Merge files back sct.printv('\nMerge file back...', verbose) import glob path_out, name_out, ext_out = sct.extract_fname(fname_out) # im_list = [Image(file_name) for file_name in glob.glob('data_reg_T*.nii')] # concat_data use to take a list of image in input, now takes a list of file names to open the files one by one (see issue #715) fname_list = glob.glob('data_reg_T*.nii') fname_list.sort() im_out = sct_image.concat_data(fname_list, 3, im_header['pixdim']) im_out.save(name_out + ext_out) os.chdir(curdir) sct.generate_output_file(os.path.join(path_tmp, name_out + ext_out), fname_out) # Delete temporary folder if specified if int(remove_temp_files): sct.printv('\nRemove temporary files...', verbose) sct.rmtree(path_tmp, verbose=verbose) # 2. crop the resulting image using dimensions from the warping field warping_field = fname_warp_list_invert[-1] # if last warping field is an affine transfo, we need to compute the space of the concatenate warping field: if isLastAffine: sct.printv('WARNING: the resulting image could have wrong apparent results. You should use an affine transformation as last transformation...', verbose, 'warning') elif crop_reference == 1: ImageCropper(input_file=fname_out, output_file=fname_out, ref=warping_field, background=0).crop() # sct.run('sct_crop_image -i '+fname_out+' -o '+fname_out+' -ref '+warping_field+' -b 0') elif crop_reference == 2: ImageCropper(input_file=fname_out, output_file=fname_out, ref=warping_field).crop() # sct.run('sct_crop_image -i '+fname_out+' -o '+fname_out+' -ref '+warping_field) sct.display_viewer_syntax([fname_dest, fname_out], verbose=verbose)
def register(param, file_src, file_dest, file_mat, file_out, im_mask=None): """ Register two images by estimating slice-wise Tx and Ty transformations, which are regularized along Z. This function uses ANTs' isct_antsSliceRegularizedRegistration. :param param: :param file_src: :param file_dest: :param file_mat: :param file_out: :param im_mask: Image of mask, could be 2D or 3D :return: """ # TODO: deal with mask # initialization failed_transfo = 0 # by default, failed matrix is 0 (i.e., no failure) do_registration = True # get metric radius (if MeanSquares, CC) or nb bins (if MI) if param.metric == 'MI': metric_radius = '16' else: metric_radius = '4' file_out_concat = file_out kw = dict() im_data = Image(file_src) # TODO: pass argument to use antsReg instead of opening Image each time # register file_src to file_dest if param.todo == 'estimate' or param.todo == 'estimate_and_apply': # If orientation is sagittal, use antsRegistration in 2D mode # Note: the parameter --restrict-deformation is irrelevant with affine transfo if param.sampling == 'None': # 'None' sampling means 'fully dense' sampling # see https://github.com/ANTsX/ANTs/wiki/antsRegistration-reproducibility-issues sampling = param.sampling else: # param.sampling should be a float in [0,1], and means the # samplingPercentage that chooses a subset of points to # estimate from. We always use 'Regular' (evenly-spaced) # mode, though antsRegistration offers 'Random' as well. # Be aware: even 'Regular' is not fully deterministic: # > Regular includes a random perturbation on the grid sampling # - https://github.com/ANTsX/ANTs/issues/976#issuecomment-602313884 sampling = 'Regular,' + param.sampling if im_data.orientation[2] in 'LR': cmd = ['isct_antsRegistration', '-d', '2', '--transform', 'Affine[%s]' %param.gradStep, '--metric', param.metric + '[' + file_dest + ',' + file_src + ',1,' + metric_radius + ',' + sampling + ']', '--convergence', param.iter, '--shrink-factors', '1', '--smoothing-sigmas', param.smooth, '--verbose', '1', '--output', '[' + file_mat + ',' + file_out_concat + ']'] cmd += sct.get_interpolation('isct_antsRegistration', param.interp) if im_mask is not None: # if user specified a mask, make sure there are non-null voxels in the image before running the registration if np.count_nonzero(im_mask.data): cmd += ['--masks', im_mask.absolutepath] else: # Mask only contains zeros. Copying the image instead of estimating registration. sct.copy(file_src, file_out_concat, verbose=0) do_registration = False # TODO: create affine mat file with identity, in case used by -g 2 # 3D mode else: cmd = ['isct_antsSliceRegularizedRegistration', '--polydegree', param.poly, '--transform', 'Translation[%s]' %param.gradStep, '--metric', param.metric + '[' + file_dest + ',' + file_src + ',1,' + metric_radius + ',' + sampling + ']', '--iterations', param.iter, '--shrinkFactors', '1', '--smoothingSigmas', param.smooth, '--verbose', '1', '--output', '[' + file_mat + ',' + file_out_concat + ']'] cmd += sct.get_interpolation('isct_antsSliceRegularizedRegistration', param.interp) if im_mask is not None: cmd += ['--mask', im_mask.absolutepath] # run command if do_registration: kw.update(dict(is_sct_binary=True)) # reducing the number of CPU used for moco (see issue #201 and #2642) env = {**os.environ, **{"ITK_GLOBAL_DEFAULT_NUMBER_OF_THREADS": "1"}} status, output = sct.run(cmd, verbose=1 if param.verbose == 2 else 0, env=env, **kw) elif param.todo == 'apply': sct_apply_transfo.main(args=['-i', file_src, '-d', file_dest, '-w', file_mat + param.suffix_mat, '-o', file_out_concat, '-x', param.interp, '-v', '0']) # check if output file exists # Note (from JCA): In the past, i've tried to catch non-zero output from ANTs function (via the 'status' variable), # but in some OSs, the function can fail while outputing zero. So as a pragmatic approach, I decided to go with # the "output file checking" approach, which is 100% sensitive. if not os.path.isfile(file_out_concat): # sct.printv(output, verbose, 'error') sct.printv('WARNING in ' + os.path.basename(__file__) + ': No output. Maybe related to improper calculation of ' 'mutual information. Either the mask you provided is ' 'too small, or the subject moved a lot. If you see too ' 'many messages like this try with a bigger mask. ' 'Using previous transformation for this volume (if it' 'exists).', param.verbose, 'warning') failed_transfo = 1 # If sagittal, copy header (because ANTs screws it) and add singleton in 3rd dimension (for z-concatenation) if im_data.orientation[2] in 'LR' and do_registration: im_out = Image(file_out_concat) im_out.header = im_data.header im_out.data = np.expand_dims(im_out.data, 2) im_out.save(file_out, verbose=0) # return status of failure return failed_transfo
def apply(self): # Initialization fname_src = self.input_filename # source image (moving) list_warp = self.list_warp # list of warping fields fname_out = self.output_filename # output fname_dest = self.fname_dest # destination image (fix) verbose = self.verbose remove_temp_files = self.remove_temp_files crop_reference = self.crop # if = 1, put 0 everywhere around warping field, if = 2, real crop islabel = False if self.interp == 'label': islabel = True self.interp = 'nn' interp = sct.get_interpolation('isct_antsApplyTransforms', self.interp) # Parse list of warping fields sct.printv('\nParse list of warping fields...', verbose) use_inverse = [] fname_warp_list_invert = [] # list_warp = list_warp.replace(' ', '') # remove spaces # list_warp = list_warp.split(",") # parse with comma for idx_warp, path_warp in enumerate(self.list_warp): # Check if this transformation should be inverted if path_warp in self.list_warpinv: use_inverse.append('-i') # list_warp[idx_warp] = path_warp[1:] # remove '-' fname_warp_list_invert += [[use_inverse[idx_warp], list_warp[idx_warp]]] else: use_inverse.append('') fname_warp_list_invert += [[path_warp]] path_warp = list_warp[idx_warp] if path_warp.endswith((".nii", ".nii.gz")) \ and Image(list_warp[idx_warp]).header.get_intent()[0] != 'vector': raise ValueError("Displacement field in {} is invalid: should be encoded" \ " in a 5D file with vector intent code" \ " (see https://nifti.nimh.nih.gov/pub/dist/src/niftilib/nifti1.h" \ .format(path_warp)) # need to check if last warping field is an affine transfo isLastAffine = False path_fname, file_fname, ext_fname = sct.extract_fname(fname_warp_list_invert[-1][-1]) if ext_fname in ['.txt', '.mat']: isLastAffine = True ## check if destination file is 3d # sct.check_dim(fname_dest, dim_lst=[3]) # PR 2598: we decided to skip this line. # N.B. Here we take the inverse of the warp list, because sct_WarpImageMultiTransform concatenates in the reverse order fname_warp_list_invert.reverse() fname_warp_list_invert = functools.reduce(lambda x, y: x + y, fname_warp_list_invert) # Extract path, file and extension path_src, file_src, ext_src = sct.extract_fname(fname_src) path_dest, file_dest, ext_dest = sct.extract_fname(fname_dest) # Get output folder and file name if fname_out == '': path_out = '' # output in user's current directory file_out = file_src + '_reg' ext_out = ext_src fname_out = os.path.join(path_out, file_out + ext_out) # Get dimensions of data sct.printv('\nGet dimensions of data...', verbose) img_src = Image(fname_src) nx, ny, nz, nt, px, py, pz, pt = img_src.dim # nx, ny, nz, nt, px, py, pz, pt = sct.get_dimension(fname_src) sct.printv(' ' + str(nx) + ' x ' + str(ny) + ' x ' + str(nz) + ' x ' + str(nt), verbose) # if 3d if nt == 1: # Apply transformation sct.printv('\nApply transformation...', verbose) if nz in [0, 1]: dim = '2' else: dim = '3' # if labels, dilate before resampling if islabel: sct.printv("\nDilate labels before warping...") path_tmp = sct.tmp_create(basename="apply_transfo", verbose=verbose) fname_dilated_labels = os.path.join(path_tmp, "dilated_data.nii") # dilate points dilate(Image(fname_src), 2, 'ball').save(fname_dilated_labels) fname_src = fname_dilated_labels sct.printv("\nApply transformation and resample to destination space...", verbose) run_proc(['isct_antsApplyTransforms', '-d', dim, '-i', fname_src, '-o', fname_out, '-t' ] + fname_warp_list_invert + ['-r', fname_dest] + interp, verbose=verbose, is_sct_binary=True) # if 4d, loop across the T dimension else: if islabel: raise NotImplementedError dim = '4' path_tmp = sct.tmp_create(basename="apply_transfo", verbose=verbose) # convert to nifti into temp folder sct.printv('\nCopying input data to tmp folder and convert to nii...', verbose) img_src.save(os.path.join(path_tmp, "data.nii")) sct.copy(fname_dest, os.path.join(path_tmp, file_dest + ext_dest)) fname_warp_list_tmp = [] for fname_warp in list_warp: path_warp, file_warp, ext_warp = sct.extract_fname(fname_warp) sct.copy(fname_warp, os.path.join(path_tmp, file_warp + ext_warp)) fname_warp_list_tmp.append(file_warp + ext_warp) fname_warp_list_invert_tmp = fname_warp_list_tmp[::-1] curdir = os.getcwd() os.chdir(path_tmp) # split along T dimension sct.printv('\nSplit along T dimension...', verbose) im_dat = Image('data.nii') im_header = im_dat.hdr data_split_list = sct_image.split_data(im_dat, 3) for im in data_split_list: im.save() # apply transfo sct.printv('\nApply transformation to each 3D volume...', verbose) for it in range(nt): file_data_split = 'data_T' + str(it).zfill(4) + '.nii' file_data_split_reg = 'data_reg_T' + str(it).zfill(4) + '.nii' status, output = run_proc(['isct_antsApplyTransforms', '-d', '3', '-i', file_data_split, '-o', file_data_split_reg, '-t', ] + fname_warp_list_invert_tmp + [ '-r', file_dest + ext_dest, ] + interp, verbose, is_sct_binary=True) # Merge files back sct.printv('\nMerge file back...', verbose) import glob path_out, name_out, ext_out = sct.extract_fname(fname_out) # im_list = [Image(file_name) for file_name in glob.glob('data_reg_T*.nii')] # concat_data use to take a list of image in input, now takes a list of file names to open the files one by one (see issue #715) fname_list = glob.glob('data_reg_T*.nii') fname_list.sort() im_out = sct_image.concat_data(fname_list, 3, im_header['pixdim']) im_out.save(name_out + ext_out) os.chdir(curdir) sct.generate_output_file(os.path.join(path_tmp, name_out + ext_out), fname_out) # Delete temporary folder if specified if remove_temp_files: sct.printv('\nRemove temporary files...', verbose) sct.rmtree(path_tmp, verbose=verbose) # Copy affine matrix from destination space to make sure qform/sform are the same sct.printv("Copy affine matrix from destination space to make sure qform/sform are the same.", verbose) im_src_reg = Image(fname_out) im_src_reg.copy_qform_from_ref(Image(fname_dest)) im_src_reg.save(verbose=0) # set verbose=0 to avoid warning message about rewriting file if islabel: sct.printv("\nTake the center of mass of each registered dilated labels...") labeled_img = cubic_to_point(im_src_reg) labeled_img.save(path=fname_out) if remove_temp_files: sct.printv('\nRemove temporary files...', verbose) sct.rmtree(path_tmp, verbose=verbose) # Crop the resulting image using dimensions from the warping field warping_field = fname_warp_list_invert[-1] # If the last transformation is not an affine transfo, we need to compute the matrix space of the concatenated # warping field if not isLastAffine and crop_reference in [1, 2]: sct.printv('Last transformation is not affine.') if crop_reference in [1, 2]: # Extract only the first ndim of the warping field img_warp = Image(warping_field) if dim == '2': img_warp_ndim = Image(img_src.data[:, :], hdr=img_warp.hdr) elif dim in ['3', '4']: img_warp_ndim = Image(img_src.data[:, :, :], hdr=img_warp.hdr) # Set zero to everything outside the warping field cropper = ImageCropper(Image(fname_out)) cropper.get_bbox_from_ref(img_warp_ndim) if crop_reference == 1: sct.printv('Cropping strategy is: keep same matrix size, put 0 everywhere around warping field') img_out = cropper.crop(background=0) elif crop_reference == 2: sct.printv('Cropping strategy is: crop around warping field (the size of warping field will ' 'change)') img_out = cropper.crop() img_out.save(fname_out) sct.display_viewer_syntax([fname_dest, fname_out], verbose=verbose)
def register(param, file_src, file_dest, file_mat, file_out, im_mask=None): """ Register two images by estimating slice-wise Tx and Ty transformations, which are regularized along Z. This function uses ANTs' isct_antsSliceRegularizedRegistration. :param param: :param file_src: :param file_dest: :param file_mat: :param file_out: :param im_mask: Image of mask, could be 2D or 3D :return: """ # TODO: deal with mask # initialization failed_transfo = 0 # by default, failed matrix is 0 (i.e., no failure) do_registration = True # get metric radius (if MeanSquares, CC) or nb bins (if MI) if param.metric == 'MI': metric_radius = '16' else: metric_radius = '4' file_out_concat = file_out kw = dict() im_data = Image(file_src) # TODO: pass argument to use antsReg instead of opening Image each time # register file_src to file_dest if param.todo == 'estimate' or param.todo == 'estimate_and_apply': # If orientation is sagittal, use antsRegistration in 2D mode # Note: the parameter --restrict-deformation is irrelevant with affine transfo if im_data.orientation[2] in 'LR': cmd = ['isct_antsRegistration', '-d', '2', '--transform', 'Affine[%s]' %param.gradStep, '--metric', param.metric + '[' + file_dest + ',' + file_src + ',1,' + metric_radius + ',Regular,' + param.sampling + ']', '--convergence', param.iter, '--shrink-factors', '1', '--smoothing-sigmas', param.smooth, '--verbose', '1', '--output', '[' + file_mat + ',' + file_out_concat + ']'] cmd += sct.get_interpolation('isct_antsRegistration', param.interp) if im_mask is not None: # if user specified a mask, make sure there are non-null voxels in the image before running the registration if np.count_nonzero(im_mask.data): cmd += ['--masks', im_mask.absolutepath] else: # Mask only contains zeros. Copying the image instead of estimating registration. sct.copy(file_src, file_out_concat, verbose=0) do_registration = False # TODO: create affine mat file with identity, in case used by -g 2 # 3D mode else: cmd = ['isct_antsSliceRegularizedRegistration', '--polydegree', param.poly, '--transform', 'Translation[%s]' %param.gradStep, '--metric', param.metric + '[' + file_dest + ',' + file_src + ',1,' + metric_radius + ',Regular,' + param.sampling + ']', '--iterations', param.iter, '--shrinkFactors', '1', '--smoothingSigmas', param.smooth, '--verbose', '1', '--output', '[' + file_mat + ',' + file_out_concat + ']'] cmd += sct.get_interpolation('isct_antsSliceRegularizedRegistration', param.interp) if im_mask is not None: cmd += ['--mask', im_mask.absolutepath] # run command if do_registration: kw.update(dict(is_sct_binary=True)) env = dict() env.update(os.environ) env = kw.get("env", env) # reducing the number of CPU used for moco (see issue #201) env["ITK_GLOBAL_DEFAULT_NUMBER_OF_THREADS"] = "1" status, output = sct.run(cmd, verbose=0, **kw) elif param.todo == 'apply': sct_apply_transfo.main(args=['-i', file_src, '-d', file_dest, '-w', file_mat + 'Warp.nii.gz', '-o', file_out_concat, '-x', param.interp, '-v', '0']) # check if output file exists if not os.path.isfile(file_out_concat): # sct.printv(output, verbose, 'error') sct.printv('WARNING in ' + os.path.basename(__file__) + ': No output. Maybe related to improper calculation of ' 'mutual information. Either the mask you provided is ' 'too small, or the subject moved a lot. If you see too ' 'many messages like this try with a bigger mask. ' 'Using previous transformation for this volume (if it' 'exists).', param.verbose, 'warning') failed_transfo = 1 # TODO: if sagittal, copy header (because ANTs screws it) and add singleton in 3rd dimension (for z-concatenation) if im_data.orientation[2] in 'LR' and do_registration: im_out = Image(file_out_concat) im_out.header = im_data.header im_out.data = np.expand_dims(im_out.data, 2) im_out.save(file_out, verbose=0) # return status of failure return failed_transfo
def apply(self): # Initialization fname_src = self.input_filename # source image (moving) fname_warp_list = self.warp_input # list of warping fields fname_out = self.output_filename # output fname_dest = self.fname_dest # destination image (fix) verbose = self.verbose remove_temp_files = self.remove_temp_files crop_reference = self.crop # if = 1, put 0 everywhere around warping field, if = 2, real crop interp = sct.get_interpolation('isct_antsApplyTransforms', self.interp) # Parse list of warping fields sct.printv('\nParse list of warping fields...', verbose) use_inverse = [] fname_warp_list_invert = [] # fname_warp_list = fname_warp_list.replace(' ', '') # remove spaces # fname_warp_list = fname_warp_list.split(",") # parse with comma for i in range(len(fname_warp_list)): # Check if inverse matrix is specified with '-' at the beginning of file name if fname_warp_list[i].find('-') == 0: use_inverse.append('-i ') fname_warp_list[i] = fname_warp_list[i][1:] # remove '-' else: use_inverse.append('') sct.printv( ' Transfo #' + str(i) + ': ' + use_inverse[i] + fname_warp_list[i], verbose) fname_warp_list_invert.append(use_inverse[i] + fname_warp_list[i]) # need to check if last warping field is an affine transfo isLastAffine = False path_fname, file_fname, ext_fname = sct.extract_fname( fname_warp_list_invert[-1]) if ext_fname in ['.txt', '.mat']: isLastAffine = True # check if destination file is 3d if not sct.check_if_3d(fname_dest): sct.printv('ERROR: Destination data must be 3d') # N.B. Here we take the inverse of the warp list, because sct_WarpImageMultiTransform concatenates in the reverse order fname_warp_list_invert.reverse() # Extract path, file and extension path_src, file_src, ext_src = sct.extract_fname(fname_src) path_dest, file_dest, ext_dest = sct.extract_fname(fname_dest) # Get output folder and file name if fname_out == '': path_out = '' # output in user's current directory file_out = file_src + '_reg' ext_out = ext_src fname_out = path_out + file_out + ext_out # Get dimensions of data sct.printv('\nGet dimensions of data...', verbose) from msct_image import Image nx, ny, nz, nt, px, py, pz, pt = Image(fname_src).dim # nx, ny, nz, nt, px, py, pz, pt = sct.get_dimension(fname_src) sct.printv( ' ' + str(nx) + ' x ' + str(ny) + ' x ' + str(nz) + ' x ' + str(nt), verbose) # if 3d if nt == 1: # Apply transformation sct.printv('\nApply transformation...', verbose) if nz in [0, 1]: dim = '2' else: dim = '3' sct.run( 'isct_antsApplyTransforms -d ' + dim + ' -i ' + fname_src + ' -o ' + fname_out + ' -t ' + ' '.join(fname_warp_list_invert) + ' -r ' + fname_dest + interp, verbose) # if 4d, loop across the T dimension else: # create temporary folder sct.printv('\nCreate temporary folder...', verbose) path_tmp = sct.slash_at_the_end( 'tmp.' + time.strftime("%y%m%d%H%M%S"), 1) # sct.run('mkdir '+path_tmp, verbose) sct.run('mkdir ' + path_tmp, verbose) # convert to nifti into temp folder sct.printv( '\nCopying input data to tmp folder and convert to nii...', verbose) from sct_convert import convert convert(fname_src, path_tmp + 'data.nii', squeeze_data=False) sct.run('cp ' + fname_dest + ' ' + path_tmp + file_dest + ext_dest) fname_warp_list_tmp = [] for fname_warp in fname_warp_list: path_warp, file_warp, ext_warp = sct.extract_fname(fname_warp) sct.run('cp ' + fname_warp + ' ' + path_tmp + file_warp + ext_warp) fname_warp_list_tmp.append(file_warp + ext_warp) fname_warp_list_invert_tmp = fname_warp_list_tmp[::-1] os.chdir(path_tmp) # split along T dimension sct.printv('\nSplit along T dimension...', verbose) from sct_image import split_data im_dat = Image('data.nii') im_header = im_dat.hdr data_split_list = split_data(im_dat, 3) for im in data_split_list: im.save() # apply transfo sct.printv('\nApply transformation to each 3D volume...', verbose) for it in range(nt): file_data_split = 'data_T' + str(it).zfill(4) + '.nii' file_data_split_reg = 'data_reg_T' + str(it).zfill(4) + '.nii' status, output = sct.run( 'isct_antsApplyTransforms -d 3 -i ' + file_data_split + ' -o ' + file_data_split_reg + ' -t ' + ' '.join(fname_warp_list_invert_tmp) + ' -r ' + file_dest + ext_dest + interp, verbose) # Merge files back sct.printv('\nMerge file back...', verbose) from sct_image import concat_data import glob path_out, name_out, ext_out = sct.extract_fname(fname_out) # im_list = [Image(file_name) for file_name in glob.glob('data_reg_T*.nii')] # concat_data use to take a list of image in input, now takes a list of file names to open the files one by one (see issue #715) fname_list = glob.glob('data_reg_T*.nii') im_out = concat_data(fname_list, 3, im_header['pixdim']) im_out.setFileName(name_out + ext_out) im_out.save(squeeze_data=False) os.chdir('..') sct.generate_output_file(path_tmp + name_out + ext_out, fname_out) # Delete temporary folder if specified if int(remove_temp_files): sct.printv('\nRemove temporary files...', verbose) sct.run('rm -rf ' + path_tmp, verbose, error_exit='warning') # 2. crop the resulting image using dimensions from the warping field warping_field = fname_warp_list_invert[-1] # if last warping field is an affine transfo, we need to compute the space of the concatenate warping field: if isLastAffine: sct.printv( 'WARNING: the resulting image could have wrong apparent results. You should use an affine transformation as last transformation...', verbose, 'warning') elif crop_reference == 1: ImageCropper(input_file=fname_out, output_file=fname_out, ref=warping_field, background=0).crop() # sct.run('sct_crop_image -i '+fname_out+' -o '+fname_out+' -ref '+warping_field+' -b 0') elif crop_reference == 2: ImageCropper(input_file=fname_out, output_file=fname_out, ref=warping_field).crop() # sct.run('sct_crop_image -i '+fname_out+' -o '+fname_out+' -ref '+warping_field) # display elapsed time sct.printv('\nDone! To view results, type:', verbose) sct.printv('fslview ' + fname_dest + ' ' + fname_out + ' &\n', verbose, 'info')
def apply(self): # Initialization fname_src = self.input_filename # source image (moving) fname_warp_list = self.warp_input # list of warping fields fname_out = self.output_filename # output fname_dest = self.fname_dest # destination image (fix) verbose = self.verbose remove_temp_files = self.remove_temp_files crop_reference = self.crop # if = 1, put 0 everywhere around warping field, if = 2, real crop interp = sct.get_interpolation('isct_antsApplyTransforms', self.interp) # Parse list of warping fields sct.printv('\nParse list of warping fields...', verbose) use_inverse = [] fname_warp_list_invert = [] # fname_warp_list = fname_warp_list.replace(' ', '') # remove spaces # fname_warp_list = fname_warp_list.split(",") # parse with comma for i in range(len(fname_warp_list)): # Check if inverse matrix is specified with '-' at the beginning of file name if fname_warp_list[i].find('-') == 0: use_inverse.append('-i ') fname_warp_list[i] = fname_warp_list[i][1:] # remove '-' else: use_inverse.append('') sct.printv(' Transfo #'+str(i)+': '+use_inverse[i]+fname_warp_list[i], verbose) fname_warp_list_invert.append(use_inverse[i]+fname_warp_list[i]) # need to check if last warping field is an affine transfo isLastAffine = False path_fname, file_fname, ext_fname = sct.extract_fname(fname_warp_list_invert[-1]) if ext_fname in ['.txt', '.mat']: isLastAffine = True # Check file existence sct.printv('\nCheck file existence...', verbose) sct.check_file_exist(fname_src, self.verbose) sct.check_file_exist(fname_dest, self.verbose) for i in range(len(fname_warp_list)): # check if file exist sct.check_file_exist(fname_warp_list[i], self.verbose) # check if destination file is 3d if not sct.check_if_3d(fname_dest): sct.printv('ERROR: Destination data must be 3d') # N.B. Here we take the inverse of the warp list, because sct_WarpImageMultiTransform concatenates in the reverse order fname_warp_list_invert.reverse() # Extract path, file and extension path_src, file_src, ext_src = sct.extract_fname(fname_src) path_dest, file_dest, ext_dest = sct.extract_fname(fname_dest) # Get output folder and file name if fname_out == '': path_out = '' # output in user's current directory file_out = file_src+'_reg' ext_out = ext_src fname_out = path_out+file_out+ext_out # Get dimensions of data sct.printv('\nGet dimensions of data...', verbose) from msct_image import Image nx, ny, nz, nt, px, py, pz, pt = Image(fname_src).dim # nx, ny, nz, nt, px, py, pz, pt = sct.get_dimension(fname_src) sct.printv(' ' + str(nx) + ' x ' + str(ny) + ' x ' + str(nz)+ ' x ' + str(nt), verbose) # if 3d if nt == 1: # Apply transformation sct.printv('\nApply transformation...', verbose) sct.run('isct_antsApplyTransforms -d 3 -i '+fname_src+' -o '+fname_out+' -t '+' '.join(fname_warp_list_invert)+' -r '+fname_dest+interp, verbose) # if 4d, loop across the T dimension else: # create temporary folder sct.printv('\nCreate temporary folder...', verbose) path_tmp = sct.slash_at_the_end('tmp.'+time.strftime("%y%m%d%H%M%S"), 1) # sct.run('mkdir '+path_tmp, verbose) sct.run('mkdir '+path_tmp, verbose) # convert to nifti into temp folder sct.printv('\nCopying input data to tmp folder and convert to nii...', verbose) from sct_convert import convert convert(fname_src, path_tmp+'data.nii') # split along T dimension sct.printv('\nSplit along T dimension...', verbose) from sct_split_data import split_data if not split_data(path_tmp+'data.nii', 3, '_T'): sct.printv('ERROR in split_data.', 1, 'error') # apply transfo sct.printv('\nApply transformation to each 3D volume...', verbose) for it in range(nt): file_data_split = path_tmp+'data_T'+str(it).zfill(4)+'.nii' file_data_split_reg = path_tmp+'data_reg_T'+str(it).zfill(4)+'.nii' sct.run('isct_antsApplyTransforms -d 3 -i '+file_data_split+' -o '+file_data_split_reg+' -t '+' '.join(fname_warp_list_invert)+' -r '+fname_dest+interp, verbose) # Merge files back sct.printv('\nMerge file back...', verbose) from sct_concat_data import concat_data import glob concat_data(glob.glob(path_tmp+'data_reg_T*.nii'), fname_out, dim=3) # Delete temporary folder if specified if int(remove_temp_files): sct.printv('\nRemove temporary files...', verbose) sct.run('rm -rf '+path_tmp, verbose) # 2. crop the resulting image using dimensions from the warping field warping_field = fname_warp_list_invert[-1] # if last warping field is an affine transfo, we need to compute the space of the concatenate warping field: if isLastAffine: sct.printv('WARNING: the resulting image could have wrong apparent results. You should use an affine transformation as last transformation...',verbose,'warning') elif crop_reference == 1: ImageCropper(input_file=fname_out, output_file=fname_out, ref=warping_field, background=0).crop() # sct.run('sct_crop_image -i '+fname_out+' -o '+fname_out+' -ref '+warping_field+' -b 0') elif crop_reference == 2: ImageCropper(input_file=fname_out, output_file=fname_out, ref=warping_field).crop() # sct.run('sct_crop_image -i '+fname_out+' -o '+fname_out+' -ref '+warping_field) # display elapsed time sct.printv('\nDone! To view results, type:', verbose) sct.printv('fslview '+fname_dest+' '+fname_out+' &\n', verbose, 'info')