def register_images(fname_source, fname_dest, mask='', paramreg=Paramreg(step='0', type='im', algo='Translation', metric='MI', iter='5', shrink='1', smooth='0', gradStep='0.5'), ants_registration_params={'rigid': '', 'affine': '', 'compositeaffine': '', 'similarity': '', 'translation': '','bspline': ',10', 'gaussiandisplacementfield': ',3,0', 'bsplinedisplacementfield': ',5,10', 'syn': ',3,0', 'bsplinesyn': ',1,3'}, remove_tmp_folder = 1): """Slice-by-slice registration of two images. We first split the 3D images into 2D images (and the mask if inputted). Then we register slices of the two images that physically correspond to one another looking at the physical origin of each image. The images can be of different sizes but the destination image must be smaller thant the input image. We do that using antsRegistration in 2D. Once this has been done for each slices, we gather the results and return them. Algorithms implemented: translation, rigid, affine, syn and BsplineSyn. N.B.: If the mask is inputted, it must also be 3D and it must be in the same space as the destination image. input: fname_source: name of moving image (type: string) fname_dest: name of fixed image (type: string) mask[optional]: name of mask file (type: string) (parameter -x of antsRegistration) paramreg[optional]: parameters of antsRegistration (type: Paramreg class from sct_register_multimodal) ants_registration_params[optional]: specific algorithm's parameters for antsRegistration (type: dictionary) output: if algo==translation: x_displacement: list of translation along x axis for each slice (type: list) y_displacement: list of translation along y axis for each slice (type: list) if algo==rigid: x_displacement: list of translation along x axis for each slice (type: list) y_displacement: list of translation along y axis for each slice (type: list) theta_rotation: list of rotation angle in radian (and in ITK's coordinate system) for each slice (type: list) if algo==affine or algo==syn or algo==bsplinesyn: creation of two 3D warping fields (forward and inverse) that are the concatenations of the slice-by-slice warps. """ # Extracting names path_i, root_i, ext_i = sct.extract_fname(fname_source) path_d, root_d, ext_d = sct.extract_fname(fname_dest) # set metricSize if paramreg.metric == 'MI': metricSize = '32' # corresponds to number of bins else: metricSize = '4' # corresponds to radius (for CC, MeanSquares...) # Get image dimensions and retrieve nz print '\nGet image dimensions of destination image...' nx, ny, nz, nt, px, py, pz, pt = Image(fname_dest).dim print '.. matrix size: '+str(nx)+' x '+str(ny)+' x '+str(nz) print '.. voxel size: '+str(px)+'mm x '+str(py)+'mm x '+str(pz)+'mm' # Define x and y displacement as list x_displacement = [0 for i in range(nz)] y_displacement = [0 for i in range(nz)] theta_rotation = [0 for i in range(nz)] # create temporary folder print('\nCreate temporary folder...') path_tmp = 'tmp.'+time.strftime("%y%m%d%H%M%S") sct.create_folder(path_tmp) print '\nCopy input data...' sct.run('cp '+fname_source+ ' ' + path_tmp +'/'+ root_i+ext_i) sct.run('cp '+fname_dest+ ' ' + path_tmp +'/'+ root_d+ext_d) if mask: sct.run('cp '+mask+ ' '+path_tmp +'/mask.nii.gz') # go to temporary folder os.chdir(path_tmp) # Split input volume along z print '\nSplit input volume...' from sct_split_data import split_data split_data(fname_source, 2, '_z') # Split destination volume along z print '\nSplit destination volume...' split_data(fname_dest, 2, '_z') # Split mask volume along z if mask: print '\nSplit mask volume...' split_data('mask.nii.gz', 2, '_z') im_dest_img = Image(fname_dest) im_input_img = Image(fname_source) coord_origin_dest = im_dest_img.transfo_pix2phys([[0,0,0]]) coord_origin_input = im_input_img.transfo_pix2phys([[0,0,0]]) coord_diff_origin = (asarray(coord_origin_dest[0]) - asarray(coord_origin_input[0])).tolist() [x_o, y_o, z_o] = [coord_diff_origin[0] * 1.0/px, coord_diff_origin[1] * 1.0/py, coord_diff_origin[2] * 1.0/pz] if paramreg.algo == 'BSplineSyN' or paramreg.algo == 'SyN' or paramreg.algo == 'Affine': list_warp_x = [] list_warp_x_inv = [] list_warp_y = [] list_warp_y_inv = [] name_warp_final = 'Warp_total' #if modified, name should also be modified in msct_register (algo slicereg2d_bsplinesyn and slicereg2d_syn) # loop across slices for i in range(nz): # set masking num = numerotation(i) num_2 = numerotation(int(num) + int(z_o)) if mask: masking = '-x mask_z' +num+ '.nii' else: masking = '' cmd = ('isct_antsRegistration ' '--dimensionality 2 ' '--transform '+paramreg.algo+'['+str(paramreg.gradStep) + ants_registration_params[paramreg.algo.lower()]+'] ' '--metric '+paramreg.metric+'['+root_d+'_z'+ num +'.nii' +','+root_i+'_z'+ num_2 +'.nii' +',1,'+metricSize+'] ' #[fixedImage,movingImage,metricWeight +nb_of_bins (MI) or radius (other) '--convergence '+str(paramreg.iter)+' ' '--shrink-factors '+str(paramreg.shrink)+' ' '--smoothing-sigmas '+str(paramreg.smooth)+'mm ' #'--restrict-deformation 1x1x0 ' # how to restrict? should not restrict here, if transform is precised...? '--output [transform_' + num + ','+root_i+'_z'+ num_2 +'reg.nii] ' #--> file.mat (contains Tx,Ty, theta) '--interpolation BSpline[3] ' +masking) try: sct.run(cmd) if paramreg.algo == 'Rigid' or paramreg.algo == 'Translation': f = 'transform_' +num+ '0GenericAffine.mat' matfile = loadmat(f, struct_as_record=True) array_transfo = matfile['AffineTransform_double_2_2'] x_displacement[i] = array_transfo[4][0] # Tx in ITK'S coordinate system y_displacement[i] = array_transfo[5][0] # Ty in ITK'S and fslview's coordinate systems theta_rotation[i] = asin(array_transfo[2]) # angle of rotation theta in ITK'S coordinate system (minus theta for fslview) if paramreg.algo == 'Affine': # New process added for generating total nifti warping field from mat warp name_dest = root_d+'_z'+ num +'.nii' name_reg = root_i+'_z'+ num +'reg.nii' name_output_warp = 'warp_from_mat_' + num_2 + '.nii.gz' name_output_warp_inverse = 'warp_from_mat_' + num + '_inverse.nii.gz' name_warp_null = 'warp_null_' + num + '.nii.gz' name_warp_null_dest = 'warp_null_dest' + num + '.nii.gz' name_warp_mat = 'transform_' + num + '0GenericAffine.mat' # Generating null nifti warping fields nx, ny, nz, nt, px, py, pz, pt = Image(name_reg).dim nx_d, ny_d, nz_d, nt_d, px_d, py_d, pz_d, pt_d = Image(name_dest).dim x_trans = [0 for i in range(nz)] x_trans_d = [0 for i in range(nz_d)] y_trans= [0 for i in range(nz)] y_trans_d = [0 for i in range(nz_d)] generate_warping_field(name_reg, x_trans=x_trans, y_trans=y_trans, fname=name_warp_null, verbose=0) generate_warping_field(name_dest, x_trans=x_trans_d, y_trans=y_trans_d, fname=name_warp_null_dest, verbose=0) # Concatenating mat wrp and null nifti warp to obtain equivalent nifti warp to mat warp sct.run('isct_ComposeMultiTransform 2 ' + name_output_warp + ' -R ' + name_reg + ' ' + name_warp_null + ' ' + name_warp_mat) sct.run('isct_ComposeMultiTransform 2 ' + name_output_warp_inverse + ' -R ' + name_dest + ' ' + name_warp_null_dest + ' -i ' + name_warp_mat) # Split the warping fields into two for displacement along x and y before merge sct.run('isct_c3d -mcs ' + name_output_warp + ' -oo transform_'+num+'0Warp_x.nii.gz transform_'+num+'0Warp_y.nii.gz') sct.run('isct_c3d -mcs ' + name_output_warp_inverse + ' -oo transform_'+num+'0InverseWarp_x.nii.gz transform_'+num+'0InverseWarp_y.nii.gz') # List names of warping fields for futur merge list_warp_x.append('transform_'+num+'0Warp_x.nii.gz') list_warp_x_inv.append('transform_'+num+'0InverseWarp_x.nii.gz') list_warp_y.append('transform_'+num+'0Warp_y.nii.gz') list_warp_y_inv.append('transform_'+num+'0InverseWarp_y.nii.gz') if paramreg.algo == 'BSplineSyN' or paramreg.algo == 'SyN': # Split the warping fields into two for displacement along x and y before merge # Need to separate the merge for x and y displacement as merge of 3d warping fields does not work properly sct.run('isct_c3d -mcs transform_'+num+'0Warp.nii.gz -oo transform_'+num+'0Warp_x.nii.gz transform_'+num+'0Warp_y.nii.gz') sct.run('isct_c3d -mcs transform_'+num+'0InverseWarp.nii.gz -oo transform_'+num+'0InverseWarp_x.nii.gz transform_'+num+'0InverseWarp_y.nii.gz') # List names of warping fields for futur merge list_warp_x.append('transform_'+num+'0Warp_x.nii.gz') list_warp_x_inv.append('transform_'+num+'0InverseWarp_x.nii.gz') list_warp_y.append('transform_'+num+'0Warp_y.nii.gz') list_warp_y_inv.append('transform_'+num+'0InverseWarp_y.nii.gz') # if an exception occurs with ants, take the last value for the transformation except: if paramreg.algo == 'Rigid' or paramreg.algo == 'Translation': x_displacement[i] = x_displacement[i-1] y_displacement[i] = y_displacement[i-1] theta_rotation[i] = theta_rotation[i-1] if paramreg.algo == 'BSplineSyN' or paramreg.algo == 'SyN' or paramreg.algo == 'Affine': print'Problem with ants for slice '+str(i)+'. Copy of the last warping field.' sct.run('cp transform_' + numerotation(i-1) + '0Warp.nii.gz transform_' + num + '0Warp.nii.gz') sct.run('cp transform_' + numerotation(i-1) + '0InverseWarp.nii.gz transform_' + num + '0InverseWarp.nii.gz') # Split the warping fields into two for displacement along x and y before merge sct.run('isct_c3d -mcs transform_'+num+'0Warp.nii.gz -oo transform_'+num+'0Warp_x.nii.gz transform_'+num+'0Warp_y.nii.gz') sct.run('isct_c3d -mcs transform_'+num+'0InverseWarp.nii.gz -oo transform_'+num+'0InverseWarp_x.nii.gz transform_'+num+'0InverseWarp_y.nii.gz') # List names of warping fields for futur merge list_warp_x.append('transform_'+num+'0Warp_x.nii.gz') list_warp_x_inv.append('transform_'+num+'0InverseWarp_x.nii.gz') list_warp_y.append('transform_'+num+'0Warp_y.nii.gz') list_warp_y_inv.append('transform_'+num+'0InverseWarp_y.nii.gz') if paramreg.algo == 'BSplineSyN' or paramreg.algo == 'SyN' or paramreg.algo == 'Affine': print'\nMerge along z of the warping fields...' # from sct_concat_data import concat_data sct.run('sct_concat_data -i '+','.join(list_warp_x)+' -o '+name_warp_final+'_x.nii.gz -dim z') sct.run('sct_concat_data -i '+','.join(list_warp_x_inv)+' -o '+name_warp_final+'_x_inverse.nii.gz -dim z') sct.run('sct_concat_data -i '+','.join(list_warp_y)+' -o '+name_warp_final+'_y.nii.gz -dim z') sct.run('sct_concat_data -i '+','.join(list_warp_y_inv)+' -o '+name_warp_final+'_y_inverse.nii.gz -dim z') # concat_data(','.join(list_warp_x), name_warp_final+'_x.nii.gz', 2) # concat_data(','.join(list_warp_x_inv), name_warp_final+'_x_inverse.nii.gz', 2) # concat_data(','.join(list_warp_y), name_warp_final+'_y.nii.gz', 2) # concat_data(','.join(list_warp_y_inv), name_warp_final+'_y_inverse.nii.gz', 2) # sct.run('fslmerge -z ' + name_warp_final + '_x ' + " ".join(list_warp_x)) # sct.run('fslmerge -z ' + name_warp_final + '_x_inverse ' + " ".join(list_warp_x_inv)) # sct.run('fslmerge -z ' + name_warp_final + '_y ' + " ".join(list_warp_y)) # sct.run('fslmerge -z ' + name_warp_final + '_y_inverse ' + " ".join(list_warp_y_inv)) print'\nChange resolution of warping fields to match the resolution of the destination image...' from sct_copy_header import copy_header copy_header(fname_dest, name_warp_final + '_x.nii.gz') copy_header(fname_source, name_warp_final + '_x_inverse.nii.gz') copy_header(fname_dest, name_warp_final + '_y.nii.gz') copy_header(fname_source, name_warp_final + '_y_inverse.nii.gz') print'\nMerge translation fields along x and y into one global warping field ' sct.run('isct_c3d ' + name_warp_final + '_x.nii.gz ' + name_warp_final + '_y.nii.gz -omc 2 ' + name_warp_final + '.nii.gz') sct.run('isct_c3d ' + name_warp_final + '_x_inverse.nii.gz ' + name_warp_final + '_y_inverse.nii.gz -omc 2 ' + name_warp_final + '_inverse.nii.gz') print'\nCopy to parent folder...' sct.run('cp ' + name_warp_final + '.nii.gz ../') sct.run('cp ' + name_warp_final + '_inverse.nii.gz ../') #Delete tmp folder os.chdir('../') if remove_tmp_folder: print('\nRemove temporary files...') sct.run('rm -rf '+path_tmp) if paramreg.algo == 'Rigid': return x_displacement, y_displacement, theta_rotation if paramreg.algo == 'Translation': return x_displacement, y_displacement
def eddy_correct(param): sct.printv('\n\n\n\n===================================================',param.verbose) sct.printv(' Running: eddy_correct', param.verbose) sct.printv('===================================================\n',param.verbose) fname_data = param.fname_data min_norm = param.min_norm cost_function = param.cost_function_flirt verbose = param.verbose sct.printv(('Input File:'+ param.fname_data),verbose) sct.printv(('Bvecs File:' + param.fname_bvecs),verbose) #Extract path, file and extension path_data, file_data, ext_data = sct.extract_fname(fname_data) if param.mat_eddy=='': param.mat_eddy= 'mat_eddy/' if not os.path.exists(param.mat_eddy): os.makedirs(param.mat_eddy) mat_eddy = param.mat_eddy #Schedule file for FLIRT schedule_file = path_sct + '/flirtsch/schedule_TxTy_2mmScale.sch' sct.printv(('\n.. Schedule file: '+ schedule_file),verbose) #Swap X-Y dimension (to have X as phase-encoding direction) if param.swapXY==1: sct.printv('\nSwap X-Y dimension (to have X as phase-encoding direction)',verbose) fname_data_new = 'tmp.data_swap' cmd = fsloutput + 'fslswapdim ' + fname_data + ' -y -x -z ' + fname_data_new status, output = sct.run(cmd,verbose) sct.printv(('\n.. updated data file name: '+fname_data_new),verbose) else: fname_data_new = fname_data # Get size of data sct.printv('\nGet dimensions data...',verbose) nx, ny, nz, nt, px, py, pz, pt = Image(fname_data).dim sct.printv('.. '+str(nx)+' x '+str(ny)+' x '+str(nz)+' x '+str(nt),verbose) # split along T dimension sct.printv('\nSplit along T dimension...',verbose) from sct_split_data import split_data split_data(fname_data_new+'.nii', 3, '_T') # cmd = fsloutput + 'fslsplit ' + fname_data_new + ' ' + file_data + '_T' # status, output = sct.run(cmd,verbose) #Slice-wise or Volume based method if param.slicewise: nb_loops = nz file_suffix=[] for iZ in range(nz): file_suffix.append('_Z'+ str(iZ).zfill(4)) else: nb_loops = 1 file_suffix = [''] # Identify pairs of opposite gradient directions sct.printv('\nIdentify pairs of opposite gradient directions...',verbose) # Open bvecs file sct.printv('\nOpen bvecs file...',verbose) bvecs = [] with open(param.fname_bvecs) as f: for line in f: bvecs_new = map(float, line.split()) bvecs.append(bvecs_new) # Check if bvecs file is nx3 if not len(bvecs[0][:]) == 3: sct.printv('.. WARNING: bvecs file is 3xn instead of nx3. Consider using sct_dmri_transpose_bvecs.',verbose) sct.printv('Transpose bvecs...',verbose) # transpose bvecs bvecs = zip(*bvecs) bvecs = np.array(bvecs) opposite_gradients_iT = [] opposite_gradients_jT = [] index_identified = [] index_b0 = [] for iT in range(nt-1): if np.linalg.norm(bvecs[iT,:])!=0: if iT not in index_identified: jT = iT+1 if np.linalg.norm((bvecs[iT,:]+bvecs[jT,:]))<min_norm: sct.printv(('.. Opposite gradient for #'+str(iT)+' is: #'+str(jT)),verbose) opposite_gradients_iT.append(iT) opposite_gradients_jT.append(jT) index_identified.append(iT) else: index_b0.append(iT) sct.printv(('.. Opposite gradient for #'+str(iT)+' is: NONE (b=0)'),verbose) nb_oppositeGradients = len(opposite_gradients_iT) sct.printv(('.. Number of gradient directions: ' + str(2*nb_oppositeGradients) + ' (2*' + str(nb_oppositeGradients) + ')'),verbose) sct.printv('.. Index b=0: '+ str(index_b0),verbose) # ========================================================================= # Find transformation # ========================================================================= for iN in range(nb_oppositeGradients): i_plus = opposite_gradients_iT[iN] i_minus = opposite_gradients_jT[iN] sct.printv(('\nFinding affine transformation between volumes #'+str(i_plus)+' and #'+str(i_minus)+' (' + str(iN)+'/'+str(nb_oppositeGradients)+')'),verbose) sct.printv('------------------------------------------------------------------------------------\n',verbose) #Slicewise correction if param.slicewise: sct.printv('\nSplit volumes across Z...',verbose) fname_plus = file_data + '_T' + str(i_plus).zfill(4) fname_plus_Z = file_data + '_T' + str(i_plus).zfill(4) + '_Z' split_data(fname_plus+'.nii', 2, '_Z') # cmd = fsloutput + 'fslsplit ' + fname_plus + ' ' + fname_plus_Z + ' -z' # status, output = sct.run(cmd,verbose) fname_minus = file_data + '_T' + str(i_minus).zfill(4) fname_minus_Z = file_data + '_T' + str(i_minus).zfill(4) + '_Z' split_data(fname_minus+'.nii', 2, '_Z') # cmd = fsloutput + 'fslsplit ' + fname_minus + ' ' + fname_minus_Z + ' -z' # status, output = sct.run(cmd,verbose) #loop across Z for iZ in range(nb_loops): fname_plus = file_data + '_T' + str(i_plus).zfill(4) + file_suffix[iZ] fname_minus = file_data + '_T' + str(i_minus).zfill(4) + file_suffix[iZ] #Find transformation on opposite gradient directions sct.printv('\nFind transformation for each pair of opposite gradient directions...',verbose) fname_plus_corr = file_data + '_T' + str(i_plus).zfill(4) + file_suffix[iZ] + '_corr_' omat = 'mat_' + file_data + '_T' + str(i_plus).zfill(4) + file_suffix[iZ] + '.txt' cmd = fsloutput+'flirt -in '+fname_plus+' -ref '+fname_minus+' -paddingsize 3 -schedule '+schedule_file+' -verbose 2 -omat '+omat+' -cost '+cost_function+' -forcescaling' status, output = sct.run(cmd,verbose) file = open(omat) Matrix = np.loadtxt(file) file.close() M = Matrix[0:4,0:4] sct.printv(('.. Transformation matrix:\n'+str(M)),verbose) sct.printv(('.. Output matrix file: '+omat),verbose) # Divide affine transformation by two sct.printv('\nDivide affine transformation by two...',verbose) A = (M - np.identity(4))/2 Mplus = np.identity(4)+A omat_plus = mat_eddy + 'mat.T' + str(i_plus) + '_Z' + str(iZ) + '.txt' file = open(omat_plus,'w') np.savetxt(omat_plus, Mplus, fmt='%.6e', delimiter=' ', newline='\n', header='', footer='', comments='#') file.close() sct.printv(('.. Output matrix file (plus): '+omat_plus),verbose) Mminus = np.identity(4)-A omat_minus = mat_eddy + 'mat.T' + str(i_minus) + '_Z' + str(iZ) + '.txt' file = open(omat_minus,'w') np.savetxt(omat_minus, Mminus, fmt='%.6e', delimiter=' ', newline='\n', header='', footer='', comments='#') file.close() sct.printv(('.. Output matrix file (minus): '+omat_minus),verbose) # ========================================================================= # Apply affine transformation # ========================================================================= sct.printv('\nApply affine transformation matrix',verbose) sct.printv('------------------------------------------------------------------------------------\n',verbose) for iN in range(nb_oppositeGradients): for iFile in range(2): if iFile==0: i_file = opposite_gradients_iT[iN] else: i_file = opposite_gradients_jT[iN] for iZ in range(nb_loops): fname = file_data + '_T' + str(i_file).zfill(4) + file_suffix[iZ] fname_corr = fname + '_corr_' + '__div2' omat = mat_eddy + 'mat.T' + str(i_file) + '_Z' + str(iZ) + '.txt' cmd = fsloutput + 'flirt -in ' + fname + ' -ref ' + fname + ' -out ' + fname_corr + ' -init ' + omat + ' -applyxfm -paddingsize 3 -interp ' + param.interp status, output = sct.run(cmd,verbose) # ========================================================================= # Merge back across Z # ========================================================================= sct.printv('\nMerge across Z',verbose) sct.printv('------------------------------------------------------------------------------------\n',verbose) for iN in range(nb_oppositeGradients): i_plus = opposite_gradients_iT[iN] fname_plus_corr = file_data + '_T' + str(i_plus).zfill(4) + '_corr_' + '__div2' cmd = fsloutput + 'fslmerge -z ' + fname_plus_corr for iZ in range(nz): fname_plus_Z_corr = file_data + '_T' + str(i_plus).zfill(4) + file_suffix[iZ] + '_corr_' + '__div2' cmd = cmd + ' ' + fname_plus_Z_corr status, output = sct.run(cmd,verbose) i_minus = opposite_gradients_jT[iN] fname_minus_corr = file_data + '_T' + str(i_minus).zfill(4) + '_corr_' + '__div2' cmd = fsloutput + 'fslmerge -z ' + fname_minus_corr for iZ in range(nz): fname_minus_Z_corr = file_data + '_T' + str(i_minus).zfill(4) + file_suffix[iZ] + '_corr_' + '__div2' cmd = cmd + ' ' + fname_minus_Z_corr status, output = sct.run(cmd,verbose) # ========================================================================= # Merge files back # ========================================================================= sct.printv('\nMerge back across T...',verbose) sct.printv('------------------------------------------------------------------------------------\n',verbose) fname_data_corr = param.output_path + file_data + '_eddy' cmd = fsloutput + 'fslmerge -t ' + fname_data_corr path_tmp = os.getcwd() for iT in range(nt): if os.path.isfile((path_tmp + '/' + file_data + '_T' + str(iT).zfill(4) + '_corr_' + '__div2.nii')): fname_data_corr_3d = file_data + '_T' + str(iT).zfill(4) + '_corr_' + '__div2' elif iT in index_b0: fname_data_corr_3d = file_data + '_T' + str(iT).zfill(4) cmd = cmd + ' ' + fname_data_corr_3d status, output = sct.run(cmd,verbose) #Swap back X-Y dimensions if param.swapXY==1: fname_data_final = fname_data sct.printv('\nSwap back X-Y dimensions',verbose) cmd = fsloutput_temp + 'fslswapdim ' + fname_data_corr + ' -y -x -z ' + fname_data_final status, output = sct.run(cmd,verbose) else: fname_data_final = fname_data_corr sct.printv(('... File created: '+fname_data_final),verbose) sct.printv('\n===================================================',verbose) sct.printv(' Completed: eddy_correct',verbose) sct.printv('===================================================\n\n\n',verbose)
def eddy_correct(param): sct.printv('\n\n\n\n===================================================', param.verbose) sct.printv(' Running: eddy_correct', param.verbose) sct.printv('===================================================\n', param.verbose) fname_data = param.fname_data min_norm = param.min_norm cost_function = param.cost_function_flirt verbose = param.verbose sct.printv(('Input File:' + param.fname_data), verbose) sct.printv(('Bvecs File:' + param.fname_bvecs), verbose) #Extract path, file and extension path_data, file_data, ext_data = sct.extract_fname(fname_data) if param.mat_eddy == '': param.mat_eddy = 'mat_eddy/' if not os.path.exists(param.mat_eddy): os.makedirs(param.mat_eddy) mat_eddy = param.mat_eddy #Schedule file for FLIRT schedule_file = path_sct + '/flirtsch/schedule_TxTy_2mmScale.sch' sct.printv(('\n.. Schedule file: ' + schedule_file), verbose) #Swap X-Y dimension (to have X as phase-encoding direction) if param.swapXY == 1: sct.printv( '\nSwap X-Y dimension (to have X as phase-encoding direction)', verbose) fname_data_new = 'tmp.data_swap' cmd = fsloutput + 'fslswapdim ' + fname_data + ' -y -x -z ' + fname_data_new status, output = sct.run(cmd, verbose) sct.printv(('\n.. updated data file name: ' + fname_data_new), verbose) else: fname_data_new = fname_data # Get size of data sct.printv('\nGet dimensions data...', verbose) nx, ny, nz, nt, px, py, pz, pt = Image(fname_data).dim sct.printv( '.. ' + str(nx) + ' x ' + str(ny) + ' x ' + str(nz) + ' x ' + str(nt), verbose) # split along T dimension sct.printv('\nSplit along T dimension...', verbose) from sct_split_data import split_data split_data(fname_data_new + '.nii', 3, '_T') # cmd = fsloutput + 'fslsplit ' + fname_data_new + ' ' + file_data + '_T' # status, output = sct.run(cmd,verbose) #Slice-wise or Volume based method if param.slicewise: nb_loops = nz file_suffix = [] for iZ in range(nz): file_suffix.append('_Z' + str(iZ).zfill(4)) else: nb_loops = 1 file_suffix = [''] # Identify pairs of opposite gradient directions sct.printv('\nIdentify pairs of opposite gradient directions...', verbose) # Open bvecs file sct.printv('\nOpen bvecs file...', verbose) bvecs = [] with open(param.fname_bvecs) as f: for line in f: bvecs_new = map(float, line.split()) bvecs.append(bvecs_new) # Check if bvecs file is nx3 if not len(bvecs[0][:]) == 3: sct.printv( '.. WARNING: bvecs file is 3xn instead of nx3. Consider using sct_dmri_transpose_bvecs.', verbose) sct.printv('Transpose bvecs...', verbose) # transpose bvecs bvecs = zip(*bvecs) bvecs = np.array(bvecs) opposite_gradients_iT = [] opposite_gradients_jT = [] index_identified = [] index_b0 = [] for iT in range(nt - 1): if np.linalg.norm(bvecs[iT, :]) != 0: if iT not in index_identified: jT = iT + 1 if np.linalg.norm((bvecs[iT, :] + bvecs[jT, :])) < min_norm: sct.printv(('.. Opposite gradient for #' + str(iT) + ' is: #' + str(jT)), verbose) opposite_gradients_iT.append(iT) opposite_gradients_jT.append(jT) index_identified.append(iT) else: index_b0.append(iT) sct.printv( ('.. Opposite gradient for #' + str(iT) + ' is: NONE (b=0)'), verbose) nb_oppositeGradients = len(opposite_gradients_iT) sct.printv( ('.. Number of gradient directions: ' + str(2 * nb_oppositeGradients) + ' (2*' + str(nb_oppositeGradients) + ')'), verbose) sct.printv('.. Index b=0: ' + str(index_b0), verbose) # ========================================================================= # Find transformation # ========================================================================= for iN in range(nb_oppositeGradients): i_plus = opposite_gradients_iT[iN] i_minus = opposite_gradients_jT[iN] sct.printv(('\nFinding affine transformation between volumes #' + str(i_plus) + ' and #' + str(i_minus) + ' (' + str(iN) + '/' + str(nb_oppositeGradients) + ')'), verbose) sct.printv( '------------------------------------------------------------------------------------\n', verbose) #Slicewise correction if param.slicewise: sct.printv('\nSplit volumes across Z...', verbose) fname_plus = file_data + '_T' + str(i_plus).zfill(4) fname_plus_Z = file_data + '_T' + str(i_plus).zfill(4) + '_Z' split_data(fname_plus + '.nii', 2, '_Z') # cmd = fsloutput + 'fslsplit ' + fname_plus + ' ' + fname_plus_Z + ' -z' # status, output = sct.run(cmd,verbose) fname_minus = file_data + '_T' + str(i_minus).zfill(4) fname_minus_Z = file_data + '_T' + str(i_minus).zfill(4) + '_Z' split_data(fname_minus + '.nii', 2, '_Z') # cmd = fsloutput + 'fslsplit ' + fname_minus + ' ' + fname_minus_Z + ' -z' # status, output = sct.run(cmd,verbose) #loop across Z for iZ in range(nb_loops): fname_plus = file_data + '_T' + str(i_plus).zfill( 4) + file_suffix[iZ] fname_minus = file_data + '_T' + str(i_minus).zfill( 4) + file_suffix[iZ] #Find transformation on opposite gradient directions sct.printv( '\nFind transformation for each pair of opposite gradient directions...', verbose) fname_plus_corr = file_data + '_T' + str(i_plus).zfill( 4) + file_suffix[iZ] + '_corr_' omat = 'mat_' + file_data + '_T' + str(i_plus).zfill( 4) + file_suffix[iZ] + '.txt' cmd = fsloutput + 'flirt -in ' + fname_plus + ' -ref ' + fname_minus + ' -paddingsize 3 -schedule ' + schedule_file + ' -verbose 2 -omat ' + omat + ' -cost ' + cost_function + ' -forcescaling' status, output = sct.run(cmd, verbose) file = open(omat) Matrix = np.loadtxt(file) file.close() M = Matrix[0:4, 0:4] sct.printv(('.. Transformation matrix:\n' + str(M)), verbose) sct.printv(('.. Output matrix file: ' + omat), verbose) # Divide affine transformation by two sct.printv('\nDivide affine transformation by two...', verbose) A = (M - np.identity(4)) / 2 Mplus = np.identity(4) + A omat_plus = mat_eddy + 'mat.T' + str(i_plus) + '_Z' + str( iZ) + '.txt' file = open(omat_plus, 'w') np.savetxt(omat_plus, Mplus, fmt='%.6e', delimiter=' ', newline='\n', header='', footer='', comments='#') file.close() sct.printv(('.. Output matrix file (plus): ' + omat_plus), verbose) Mminus = np.identity(4) - A omat_minus = mat_eddy + 'mat.T' + str(i_minus) + '_Z' + str( iZ) + '.txt' file = open(omat_minus, 'w') np.savetxt(omat_minus, Mminus, fmt='%.6e', delimiter=' ', newline='\n', header='', footer='', comments='#') file.close() sct.printv(('.. Output matrix file (minus): ' + omat_minus), verbose) # ========================================================================= # Apply affine transformation # ========================================================================= sct.printv('\nApply affine transformation matrix', verbose) sct.printv( '------------------------------------------------------------------------------------\n', verbose) for iN in range(nb_oppositeGradients): for iFile in range(2): if iFile == 0: i_file = opposite_gradients_iT[iN] else: i_file = opposite_gradients_jT[iN] for iZ in range(nb_loops): fname = file_data + '_T' + str(i_file).zfill( 4) + file_suffix[iZ] fname_corr = fname + '_corr_' + '__div2' omat = mat_eddy + 'mat.T' + str(i_file) + '_Z' + str( iZ) + '.txt' cmd = fsloutput + 'flirt -in ' + fname + ' -ref ' + fname + ' -out ' + fname_corr + ' -init ' + omat + ' -applyxfm -paddingsize 3 -interp ' + param.interp status, output = sct.run(cmd, verbose) # ========================================================================= # Merge back across Z # ========================================================================= sct.printv('\nMerge across Z', verbose) sct.printv( '------------------------------------------------------------------------------------\n', verbose) for iN in range(nb_oppositeGradients): i_plus = opposite_gradients_iT[iN] fname_plus_corr = file_data + '_T' + str(i_plus).zfill( 4) + '_corr_' + '__div2' cmd = fsloutput + 'fslmerge -z ' + fname_plus_corr for iZ in range(nz): fname_plus_Z_corr = file_data + '_T' + str(i_plus).zfill( 4) + file_suffix[iZ] + '_corr_' + '__div2' cmd = cmd + ' ' + fname_plus_Z_corr status, output = sct.run(cmd, verbose) i_minus = opposite_gradients_jT[iN] fname_minus_corr = file_data + '_T' + str(i_minus).zfill( 4) + '_corr_' + '__div2' cmd = fsloutput + 'fslmerge -z ' + fname_minus_corr for iZ in range(nz): fname_minus_Z_corr = file_data + '_T' + str(i_minus).zfill( 4) + file_suffix[iZ] + '_corr_' + '__div2' cmd = cmd + ' ' + fname_minus_Z_corr status, output = sct.run(cmd, verbose) # ========================================================================= # Merge files back # ========================================================================= sct.printv('\nMerge back across T...', verbose) sct.printv( '------------------------------------------------------------------------------------\n', verbose) fname_data_corr = param.output_path + file_data + '_eddy' cmd = fsloutput + 'fslmerge -t ' + fname_data_corr path_tmp = os.getcwd() for iT in range(nt): if os.path.isfile((path_tmp + '/' + file_data + '_T' + str(iT).zfill(4) + '_corr_' + '__div2.nii')): fname_data_corr_3d = file_data + '_T' + str(iT).zfill( 4) + '_corr_' + '__div2' elif iT in index_b0: fname_data_corr_3d = file_data + '_T' + str(iT).zfill(4) cmd = cmd + ' ' + fname_data_corr_3d status, output = sct.run(cmd, verbose) #Swap back X-Y dimensions if param.swapXY == 1: fname_data_final = fname_data sct.printv('\nSwap back X-Y dimensions', verbose) cmd = fsloutput_temp + 'fslswapdim ' + fname_data_corr + ' -y -x -z ' + fname_data_final status, output = sct.run(cmd, verbose) else: fname_data_final = fname_data_corr sct.printv(('... File created: ' + fname_data_final), verbose) sct.printv('\n===================================================', verbose) sct.printv(' Completed: eddy_correct', verbose) sct.printv('===================================================\n\n\n', verbose)
def main(): # Initialization fname_anat = '' fname_centerline = '' centerline_fitting = 'polynome' remove_temp_files = param.remove_temp_files interp = param.interp degree_poly = param.deg_poly # extract path of the script path_script = os.path.dirname(__file__) + '/' # Parameters for debug mode if param.debug == 1: print '\n*** WARNING: DEBUG MODE ON ***\n' status, path_sct_data = commands.getstatusoutput( 'echo $SCT_TESTING_DATA_DIR') fname_anat = path_sct_data + '/t2/t2.nii.gz' fname_centerline = path_sct_data + '/t2/t2_seg.nii.gz' else: # Check input param try: opts, args = getopt.getopt(sys.argv[1:], 'hi:c:r:d:f:s:') except getopt.GetoptError as err: print str(err) usage() if not opts: usage() for opt, arg in opts: if opt == '-h': usage() elif opt in ('-i'): fname_anat = arg elif opt in ('-c'): fname_centerline = arg elif opt in ('-r'): remove_temp_files = int(arg) elif opt in ('-d'): degree_poly = int(arg) elif opt in ('-f'): centerline_fitting = str(arg) elif opt in ('-s'): interp = str(arg) # display usage if a mandatory argument is not provided if fname_anat == '' or fname_centerline == '': usage() # check existence of input files sct.check_file_exist(fname_anat) sct.check_file_exist(fname_centerline) # extract path/file/extension path_anat, file_anat, ext_anat = sct.extract_fname(fname_anat) # Display arguments print '\nCheck input arguments...' print ' Input volume ...................... ' + fname_anat print ' Centerline ........................ ' + fname_centerline print '' # Get input image orientation input_image_orientation = get_orientation(fname_anat) # Reorient input data into RL PA IS orientation set_orientation(fname_anat, 'RPI', 'tmp.anat_orient.nii') set_orientation(fname_centerline, 'RPI', 'tmp.centerline_orient.nii') # Open centerline #========================================================================================== print '\nGet dimensions of input centerline...' nx, ny, nz, nt, px, py, pz, pt = Image('tmp.centerline_orient.nii').dim print '.. matrix size: ' + str(nx) + ' x ' + str(ny) + ' x ' + str(nz) print '.. voxel size: ' + str(px) + 'mm x ' + str(py) + 'mm x ' + str( pz) + 'mm' print '\nOpen centerline volume...' file = nibabel.load('tmp.centerline_orient.nii') data = file.get_data() X, Y, Z = (data > 0).nonzero() min_z_index, max_z_index = min(Z), max(Z) # loop across z and associate x,y coordinate with the point having maximum intensity x_centerline = [0 for iz in range(min_z_index, max_z_index + 1, 1)] y_centerline = [0 for iz in range(min_z_index, max_z_index + 1, 1)] z_centerline = [iz for iz in range(min_z_index, max_z_index + 1, 1)] # Two possible scenario: # 1. the centerline is probabilistic: each slices contains voxels with the probability of containing the centerline [0:...:1] # We only take the maximum value of the image to aproximate the centerline. # 2. The centerline/segmentation image contains many pixels per slice with values {0,1}. # We take all the points and approximate the centerline on all these points. X, Y, Z = ((data < 1) * (data > 0)).nonzero() # X is empty if binary image if (len(X) > 0): # Scenario 1 for iz in range(min_z_index, max_z_index + 1, 1): x_centerline[iz - min_z_index], y_centerline[ iz - min_z_index] = numpy.unravel_index( data[:, :, iz].argmax(), data[:, :, iz].shape) else: # Scenario 2 for iz in range(min_z_index, max_z_index + 1, 1): x_seg, y_seg = (data[:, :, iz] > 0).nonzero() if len(x_seg) > 0: x_centerline[iz - min_z_index] = numpy.mean(x_seg) y_centerline[iz - min_z_index] = numpy.mean(y_seg) # TODO: find a way to do the previous loop with this, which is more neat: # [numpy.unravel_index(data[:,:,iz].argmax(), data[:,:,iz].shape) for iz in range(0,nz,1)] # clear variable del data # Fit the centerline points with the kind of curve given as argument of the script and return the new smoothed coordinates if centerline_fitting == 'splines': try: x_centerline_fit, y_centerline_fit = b_spline_centerline( x_centerline, y_centerline, z_centerline) except ValueError: print "splines fitting doesn't work, trying with polynomial fitting...\n" x_centerline_fit, y_centerline_fit = polynome_centerline( x_centerline, y_centerline, z_centerline) elif centerline_fitting == 'polynome': x_centerline_fit, y_centerline_fit = polynome_centerline( x_centerline, y_centerline, z_centerline) #========================================================================================== # Split input volume print '\nSplit input volume...' from sct_split_data import split_data if not split_data('tmp.anat_orient.nii', 2, '_z'): sct.printv('ERROR in split_data.', 1, 'error') file_anat_split = [ 'tmp.anat_orient_z' + str(z).zfill(4) for z in range(0, nz, 1) ] # initialize variables file_mat_inv_cumul = [ 'tmp.mat_inv_cumul_z' + str(z).zfill(4) for z in range(0, nz, 1) ] z_init = min_z_index displacement_max_z_index = x_centerline_fit[ z_init - min_z_index] - x_centerline_fit[max_z_index - min_z_index] # write centerline as text file print '\nGenerate fitted transformation matrices...' file_mat_inv_cumul_fit = [ 'tmp.mat_inv_cumul_fit_z' + str(z).zfill(4) for z in range(0, nz, 1) ] for iz in range(min_z_index, max_z_index + 1, 1): # compute inverse cumulative fitted transformation matrix fid = open(file_mat_inv_cumul_fit[iz], 'w') if (x_centerline[iz - min_z_index] == 0 and y_centerline[iz - min_z_index] == 0): displacement = 0 else: displacement = x_centerline_fit[ z_init - min_z_index] - x_centerline_fit[iz - min_z_index] fid.write('%i %i %i %f\n' % (1, 0, 0, displacement)) fid.write('%i %i %i %f\n' % (0, 1, 0, 0)) fid.write('%i %i %i %i\n' % (0, 0, 1, 0)) fid.write('%i %i %i %i\n' % (0, 0, 0, 1)) fid.close() # we complete the displacement matrix in z direction for iz in range(0, min_z_index, 1): fid = open(file_mat_inv_cumul_fit[iz], 'w') fid.write('%i %i %i %f\n' % (1, 0, 0, 0)) fid.write('%i %i %i %f\n' % (0, 1, 0, 0)) fid.write('%i %i %i %i\n' % (0, 0, 1, 0)) fid.write('%i %i %i %i\n' % (0, 0, 0, 1)) fid.close() for iz in range(max_z_index + 1, nz, 1): fid = open(file_mat_inv_cumul_fit[iz], 'w') fid.write('%i %i %i %f\n' % (1, 0, 0, displacement_max_z_index)) fid.write('%i %i %i %f\n' % (0, 1, 0, 0)) fid.write('%i %i %i %i\n' % (0, 0, 1, 0)) fid.write('%i %i %i %i\n' % (0, 0, 0, 1)) fid.close() # apply transformations to data print '\nApply fitted transformation matrices...' file_anat_split_fit = [ 'tmp.anat_orient_fit_z' + str(z).zfill(4) for z in range(0, nz, 1) ] for iz in range(0, nz, 1): # forward cumulative transformation to data sct.run(fsloutput + 'flirt -in ' + file_anat_split[iz] + ' -ref ' + file_anat_split[iz] + ' -applyxfm -init ' + file_mat_inv_cumul_fit[iz] + ' -out ' + file_anat_split_fit[iz] + ' -interp ' + interp) # Merge into 4D volume print '\nMerge into 4D volume...' from sct_concat_data import concat_data from glob import glob concat_data(glob('tmp.anat_orient_fit_z*.nii'), 'tmp.anat_orient_fit.nii', dim=2) # sct.run(fsloutput+'fslmerge -z tmp.anat_orient_fit tmp.anat_orient_fit_z*') # Reorient data as it was before print '\nReorient data back into native orientation...' set_orientation('tmp.anat_orient_fit.nii', input_image_orientation, 'tmp.anat_orient_fit_reorient.nii') # Generate output file (in current folder) print '\nGenerate output file (in current folder)...' sct.generate_output_file('tmp.anat_orient_fit_reorient.nii', file_anat + '_flatten' + ext_anat) # Delete temporary files if remove_temp_files == 1: print '\nDelete temporary files...' sct.run('rm -rf tmp.*') # to view results print '\nDone! To view results, type:' print 'fslview ' + file_anat + ext_anat + ' ' + file_anat + '_flatten' + ext_anat + ' &\n'
def main(): # Initialization fsloutput = 'export FSLOUTPUTTYPE=NIFTI; ' # for faster processing, all outputs are in NIFTI fname_data = '' fname_bvecs = '' fname_bvals = '' path_out = '' average = param.average verbose = param.verbose remove_tmp_files = param.remove_tmp_files start_time = time.time() # get path of the toolbox status, path_sct = commands.getstatusoutput('echo $SCT_DIR') # Parameters for debug mode if param.debug: fname_data = path_sct+'/testing/data/errsm_23/dmri/dmri.nii.gz' fname_bvecs = path_sct+'/testing/data/errsm_23/dmri/bvecs.txt' average = 1 verbose = 1 else: # Check input parameters try: opts, args = getopt.getopt(sys.argv[1:],'ha:b:i:m:o:r:v:') except getopt.GetoptError: usage() if not opts: usage() for opt, arg in opts: if opt == '-h': usage() elif opt in ("-a"): average = int(arg) elif opt in ("-b"): fname_bvecs = arg elif opt in ("-i"): fname_data = arg elif opt in ('-m'): fname_bvals = arg elif opt in ("-o"): path_out = arg elif opt in ("-r"): remove_temp_file = int(arg) elif opt in ('-v'): verbose = int(arg) # display usage if a mandatory argument is not provided if fname_data == '' or fname_bvecs == '': usage() # check existence of input files sct.check_file_exist(fname_data, verbose) sct.check_file_exist(fname_bvecs, verbose) if not fname_bvals == '': sct.check_file_exist(fname_bvals, verbose) # print arguments sct.printv('\nInput parameters:', verbose) sct.printv(' input file ............'+fname_data, verbose) sct.printv(' bvecs file ............'+fname_bvecs, verbose) sct.printv(' average ...............'+str(average), verbose) # Get full path fname_data = os.path.abspath(fname_data) fname_bvecs = os.path.abspath(fname_bvecs) # Extract path, file and extension path_data, file_data, ext_data = sct.extract_fname(fname_data) # # get output folder # if path_out == '': # path_out = '' # 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) # copy files into tmp folder and convert to nifti sct.printv('\nCopy files into temporary folder...', verbose) from sct_convert import convert if not convert(fname_data, path_tmp+'dmri.nii'): sct.printv('ERROR in convert.', 1, 'error') sct.run('cp '+fname_bvecs+' '+path_tmp+'bvecs', verbose) # go to tmp folder os.chdir(path_tmp) # Get size of data sct.printv('\nGet dimensions data...', verbose) nx, ny, nz, nt, px, py, pz, pt = Image('dmri.nii').dim sct.printv('.. '+str(nx)+' x '+str(ny)+' x '+str(nz)+' x '+str(nt), verbose) # Identify b=0 and DWI images index_b0, index_dwi, nb_b0, nb_dwi = identify_b0(fname_bvecs, fname_bvals, param.bval_min, verbose) # Split into T dimension sct.printv('\nSplit along T dimension...', verbose) from sct_split_data import split_data if not split_data('dmri.nii', 3, '_T'): sct.printv('ERROR in split_data.', 1, 'error') # Merge b=0 images sct.printv('\nMerge b=0...', verbose) cmd = 'sct_concat_data -dim t -o b0.nii -i ' for it in range(nb_b0): cmd = cmd + 'dmri_T' + str(index_b0[it]).zfill(4) + '.nii,' cmd = cmd[:-1] # remove ',' at the end of the string status, output = sct.run(cmd, param.verbose) # Average b=0 images if average: sct.printv('\nAverage b=0...', verbose) sct.run('sct_maths -i b0.nii -o b0_mean.nii -mean t', verbose) # Merge DWI sct.printv('\nMerge DWI...', verbose) cmd = 'sct_concat_data -dim t -o dwi.nii -i ' for it in range(nb_dwi): cmd = cmd + 'dmri_T' + str(index_dwi[it]).zfill(4) + '.nii,' cmd = cmd[:-1] # remove ',' at the end of the string status, output = sct.run(cmd, param.verbose) # Average DWI images if average: sct.printv('\nAverage DWI...', verbose) sct.run('sct_maths -i dwi.nii -o dwi_mean.nii -mean t', verbose) # if not average_data_across_dimension('dwi.nii', 'dwi_mean.nii', 3): # sct.printv('ERROR in average_data_across_dimension', 1, 'error') # sct.run(fsloutput + 'fslmaths dwi -Tmean dwi_mean', verbose) # come back to parent folder os.chdir('..') # Generate output files sct.printv('\nGenerate output files...', verbose) sct.generate_output_file(path_tmp+'b0.nii', path_out+'b0'+ext_data, verbose) sct.generate_output_file(path_tmp+'dwi.nii', path_out+'dwi'+ext_data, verbose) if average: sct.generate_output_file(path_tmp+'b0_mean.nii', path_out+'b0_mean'+ext_data, verbose) sct.generate_output_file(path_tmp+'dwi_mean.nii', path_out+'dwi_mean'+ext_data, verbose) # Remove temporary files if remove_tmp_files == 1: sct.printv('\nRemove temporary files...', verbose) sct.run('rm -rf '+path_tmp, verbose) # display elapsed time elapsed_time = time.time() - start_time sct.printv('\nFinished! Elapsed time: '+str(int(round(elapsed_time)))+'s', verbose) # to view results sct.printv('\nTo view results, type: ', verbose) if average: sct.printv('fslview b0 b0_mean dwi dwi_mean &\n', verbose) else: sct.printv('fslview b0 dwi &\n', verbose)
def main(): # Initialization fname_anat = '' fname_point = '' slice_gap = param.gap remove_tmp_files = param.remove_tmp_files gaussian_kernel = param.gaussian_kernel start_time = time.time() verbose = 1 # get path of the toolbox status, path_sct = commands.getstatusoutput('echo $SCT_DIR') path_sct = sct.slash_at_the_end(path_sct, 1) # Parameters for debug mode if param.debug == 1: sct.printv('\n*** WARNING: DEBUG MODE ON ***\n\t\t\tCurrent working directory: '+os.getcwd(), 'warning') status, path_sct_testing_data = commands.getstatusoutput('echo $SCT_TESTING_DATA_DIR') fname_anat = path_sct_testing_data+'/t2/t2.nii.gz' fname_point = path_sct_testing_data+'/t2/t2_centerline_init.nii.gz' slice_gap = 5 else: # Check input param try: opts, args = getopt.getopt(sys.argv[1:],'hi:p:g:r:k:') except getopt.GetoptError as err: print str(err) usage() if not opts: usage() for opt, arg in opts: if opt == '-h': usage() elif opt in ('-i'): fname_anat = arg elif opt in ('-p'): fname_point = arg elif opt in ('-g'): slice_gap = int(arg) elif opt in ('-r'): remove_tmp_files = int(arg) elif opt in ('-k'): gaussian_kernel = int(arg) # display usage if a mandatory argument is not provided if fname_anat == '' or fname_point == '': usage() # check existence of input files sct.check_file_exist(fname_anat) sct.check_file_exist(fname_point) # extract path/file/extension path_anat, file_anat, ext_anat = sct.extract_fname(fname_anat) path_point, file_point, ext_point = sct.extract_fname(fname_point) # extract path of schedule file # TODO: include schedule file in sct # TODO: check existence of schedule file file_schedule = path_sct + param.schedule_file # Get input image orientation input_image_orientation = get_orientation(fname_anat) # Display arguments print '\nCheck input arguments...' print ' Anatomical image: '+fname_anat print ' Orientation: '+input_image_orientation print ' Point in spinal cord: '+fname_point print ' Slice gap: '+str(slice_gap) print ' Gaussian kernel: '+str(gaussian_kernel) print ' Degree of polynomial: '+str(param.deg_poly) # create temporary folder print('\nCreate temporary folder...') path_tmp = 'tmp.'+time.strftime("%y%m%d%H%M%S") sct.create_folder(path_tmp) print '\nCopy input data...' sct.run('cp '+fname_anat+ ' '+path_tmp+'/tmp.anat'+ext_anat) sct.run('cp '+fname_point+ ' '+path_tmp+'/tmp.point'+ext_point) # go to temporary folder os.chdir(path_tmp) # convert to nii convert('tmp.anat'+ext_anat, 'tmp.anat.nii') convert('tmp.point'+ext_point, 'tmp.point.nii') # Reorient input anatomical volume into RL PA IS orientation print '\nReorient input volume to RL PA IS orientation...' #sct.run(sct.fsloutput + 'fslswapdim tmp.anat RL PA IS tmp.anat_orient') set_orientation('tmp.anat.nii', 'RPI', 'tmp.anat_orient.nii') # Reorient binary point into RL PA IS orientation print '\nReorient binary point into RL PA IS orientation...' # sct.run(sct.fsloutput + 'fslswapdim tmp.point RL PA IS tmp.point_orient') set_orientation('tmp.point.nii', 'RPI', 'tmp.point_orient.nii') # Get image dimensions print '\nGet image dimensions...' nx, ny, nz, nt, px, py, pz, pt = Image('tmp.anat_orient.nii').dim print '.. matrix size: '+str(nx)+' x '+str(ny)+' x '+str(nz) print '.. voxel size: '+str(px)+'mm x '+str(py)+'mm x '+str(pz)+'mm' # Split input volume print '\nSplit input volume...' split_data('tmp.anat_orient.nii', 2, '_z') file_anat_split = ['tmp.anat_orient_z'+str(z).zfill(4) for z in range(0, nz, 1)] split_data('tmp.point_orient.nii', 2, '_z') file_point_split = ['tmp.point_orient_z'+str(z).zfill(4) for z in range(0, nz, 1)] # Extract coordinates of input point # sct.printv('\nExtract the slice corresponding to z='+str(z_init)+'...', verbose) # data_point = Image('tmp.point_orient.nii').data x_init, y_init, z_init = unravel_index(data_point.argmax(), data_point.shape) sct.printv('Coordinates of input point: ('+str(x_init)+', '+str(y_init)+', '+str(z_init)+')', verbose) # Create 2D gaussian mask sct.printv('\nCreate gaussian mask from point...', verbose) xx, yy = mgrid[:nx, :ny] mask2d = zeros((nx, ny)) radius = round(float(gaussian_kernel+1)/2) # add 1 because the radius includes the center. sigma = float(radius) mask2d = exp(-(((xx-x_init)**2)/(2*(sigma**2)) + ((yy-y_init)**2)/(2*(sigma**2)))) # Save mask to 2d file file_mask_split = ['tmp.mask_orient_z'+str(z).zfill(4) for z in range(0,nz,1)] nii_mask2d = Image('tmp.anat_orient_z0000.nii') nii_mask2d.data = mask2d nii_mask2d.setFileName(file_mask_split[z_init]+'.nii') nii_mask2d.save() # # # Get the coordinates of the input point # print '\nGet the coordinates of the input point...' # data_point = Image('tmp.point_orient.nii').data # x_init, y_init, z_init = unravel_index(data_point.argmax(), data_point.shape) # print '('+str(x_init)+', '+str(y_init)+', '+str(z_init)+')' # x_init, y_init, z_init = (data > 0).nonzero() # x_init = x_init[0] # y_init = y_init[0] # z_init = z_init[0] # print '('+str(x_init)+', '+str(y_init)+', '+str(z_init)+')' # # numpy.unravel_index(a.argmax(), a.shape) # # file = nibabel.load('tmp.point_orient.nii') # data = file.get_data() # x_init, y_init, z_init = (data > 0).nonzero() # x_init = x_init[0] # y_init = y_init[0] # z_init = z_init[0] # print '('+str(x_init)+', '+str(y_init)+', '+str(z_init)+')' # # # Extract the slice corresponding to z=z_init # print '\nExtract the slice corresponding to z='+str(z_init)+'...' # file_point_split = ['tmp.point_orient_z'+str(z).zfill(4) for z in range(0,nz,1)] # nii = Image('tmp.point_orient.nii') # data_crop = nii.data[:, :, z_init:z_init+1] # nii.data = data_crop # nii.setFileName(file_point_split[z_init]+'.nii') # nii.save() # # # Create gaussian mask from point # print '\nCreate gaussian mask from point...' # file_mask_split = ['tmp.mask_orient_z'+str(z).zfill(4) for z in range(0,nz,1)] # sct.run(sct.fsloutput+'fslmaths '+file_point_split[z_init]+' -s '+str(gaussian_kernel)+' '+file_mask_split[z_init]) # # # Obtain max value from mask # print '\nFind maximum value from mask...' # file = nibabel.load(file_mask_split[z_init]+'.nii') # data = file.get_data() # max_value_mask = numpy.max(data) # print '..'+str(max_value_mask) # # # Normalize mask beween 0 and 1 # print '\nNormalize mask beween 0 and 1...' # sct.run(sct.fsloutput+'fslmaths '+file_mask_split[z_init]+' -div '+str(max_value_mask)+' '+file_mask_split[z_init]) ## Take the square of the mask #print '\nCalculate the square of the mask...' #sct.run(sct.fsloutput+'fslmaths '+file_mask_split[z_init]+' -mul '+file_mask_split[z_init]+' '+file_mask_split[z_init]) # initialize variables file_mat = ['tmp.mat_z'+str(z).zfill(4) for z in range(0,nz,1)] file_mat_inv = ['tmp.mat_inv_z'+str(z).zfill(4) for z in range(0,nz,1)] file_mat_inv_cumul = ['tmp.mat_inv_cumul_z'+str(z).zfill(4) for z in range(0,nz,1)] # create identity matrix for initial transformation matrix fid = open(file_mat_inv_cumul[z_init], 'w') fid.write('%i %i %i %i\n' %(1, 0, 0, 0) ) fid.write('%i %i %i %i\n' %(0, 1, 0, 0) ) fid.write('%i %i %i %i\n' %(0, 0, 1, 0) ) fid.write('%i %i %i %i\n' %(0, 0, 0, 1) ) fid.close() # initialize centerline: give value corresponding to initial point x_centerline = [x_init] y_centerline = [y_init] z_centerline = [z_init] warning_count = 0 # go up (1), then down (2) in reference to the binary point for iUpDown in range(1, 3): if iUpDown == 1: # z increases slice_gap_signed = slice_gap elif iUpDown == 2: # z decreases slice_gap_signed = -slice_gap # reverse centerline (because values will be appended at the end) x_centerline.reverse() y_centerline.reverse() z_centerline.reverse() # initialization before looping z_dest = z_init # point given by user z_src = z_dest + slice_gap_signed # continue looping if 0 < z < nz while 0 <= z_src and z_src <= nz-1: # print current z: print 'z='+str(z_src)+':' # estimate transformation sct.run(fsloutput+'flirt -in '+file_anat_split[z_src]+' -ref '+file_anat_split[z_dest]+' -schedule '+file_schedule+ ' -verbose 0 -omat '+file_mat[z_src]+' -cost normcorr -forcescaling -inweight '+file_mask_split[z_dest]+' -refweight '+file_mask_split[z_dest]) # display transfo status, output = sct.run('cat '+file_mat[z_src]) print output # check if transformation is bigger than 1.5x slice_gap tx = float(output.split()[3]) ty = float(output.split()[7]) norm_txy = linalg.norm([tx, ty],ord=2) if norm_txy > 1.5*slice_gap: print 'WARNING: Transformation is too large --> using previous one.' warning_count = warning_count + 1 # if previous transformation exists, replace current one with previous one if os.path.isfile(file_mat[z_dest]): sct.run('cp '+file_mat[z_dest]+' '+file_mat[z_src]) # estimate inverse transformation matrix sct.run('convert_xfm -omat '+file_mat_inv[z_src]+' -inverse '+file_mat[z_src]) # compute cumulative transformation sct.run('convert_xfm -omat '+file_mat_inv_cumul[z_src]+' -concat '+file_mat_inv[z_src]+' '+file_mat_inv_cumul[z_dest]) # apply inverse cumulative transformation to initial gaussian mask (to put it in src space) sct.run(fsloutput+'flirt -in '+file_mask_split[z_init]+' -ref '+file_mask_split[z_init]+' -applyxfm -init '+file_mat_inv_cumul[z_src]+' -out '+file_mask_split[z_src]) # open inverse cumulative transformation file and generate centerline fid = open(file_mat_inv_cumul[z_src]) mat = fid.read().split() x_centerline.append(x_init + float(mat[3])) y_centerline.append(y_init + float(mat[7])) z_centerline.append(z_src) #z_index = z_index+1 # define new z_dest (target slice) and new z_src (moving slice) z_dest = z_dest + slice_gap_signed z_src = z_src + slice_gap_signed # Reconstruct centerline # ==================================================================================================== # reverse back centerline (because it's been reversed once, so now all values are in the right order) x_centerline.reverse() y_centerline.reverse() z_centerline.reverse() # fit centerline in the Z-X plane using polynomial function print '\nFit centerline in the Z-X plane using polynomial function...' coeffsx = polyfit(z_centerline, x_centerline, deg=param.deg_poly) polyx = poly1d(coeffsx) x_centerline_fit = polyval(polyx, z_centerline) # calculate RMSE rmse = linalg.norm(x_centerline_fit-x_centerline)/sqrt( len(x_centerline) ) # calculate max absolute error max_abs = max( abs(x_centerline_fit-x_centerline) ) print '.. RMSE (in mm): '+str(rmse*px) print '.. Maximum absolute error (in mm): '+str(max_abs*px) # fit centerline in the Z-Y plane using polynomial function print '\nFit centerline in the Z-Y plane using polynomial function...' coeffsy = polyfit(z_centerline, y_centerline, deg=param.deg_poly) polyy = poly1d(coeffsy) y_centerline_fit = polyval(polyy, z_centerline) # calculate RMSE rmse = linalg.norm(y_centerline_fit-y_centerline)/sqrt( len(y_centerline) ) # calculate max absolute error max_abs = max( abs(y_centerline_fit-y_centerline) ) print '.. RMSE (in mm): '+str(rmse*py) print '.. Maximum absolute error (in mm): '+str(max_abs*py) # display if param.debug == 1: import matplotlib.pyplot as plt plt.figure() plt.plot(z_centerline,x_centerline,'.',z_centerline,x_centerline_fit,'r') plt.legend(['Data','Polynomial Fit']) plt.title('Z-X plane polynomial interpolation') plt.show() plt.figure() plt.plot(z_centerline,y_centerline,'.',z_centerline,y_centerline_fit,'r') plt.legend(['Data','Polynomial Fit']) plt.title('Z-Y plane polynomial interpolation') plt.show() # generate full range z-values for centerline z_centerline_full = [iz for iz in range(0, nz, 1)] # calculate X and Y values for the full centerline x_centerline_fit_full = polyval(polyx, z_centerline_full) y_centerline_fit_full = polyval(polyy, z_centerline_full) # Generate fitted transformation matrices and write centerline coordinates in text file print '\nGenerate fitted transformation matrices and write centerline coordinates in text file...' file_mat_inv_cumul_fit = ['tmp.mat_inv_cumul_fit_z'+str(z).zfill(4) for z in range(0,nz,1)] file_mat_cumul_fit = ['tmp.mat_cumul_fit_z'+str(z).zfill(4) for z in range(0,nz,1)] fid_centerline = open('tmp.centerline_coordinates.txt', 'w') for iz in range(0, nz, 1): # compute inverse cumulative fitted transformation matrix fid = open(file_mat_inv_cumul_fit[iz], 'w') fid.write('%i %i %i %f\n' %(1, 0, 0, x_centerline_fit_full[iz]-x_init) ) fid.write('%i %i %i %f\n' %(0, 1, 0, y_centerline_fit_full[iz]-y_init) ) fid.write('%i %i %i %i\n' %(0, 0, 1, 0) ) fid.write('%i %i %i %i\n' %(0, 0, 0, 1) ) fid.close() # compute forward cumulative fitted transformation matrix sct.run('convert_xfm -omat '+file_mat_cumul_fit[iz]+' -inverse '+file_mat_inv_cumul_fit[iz]) # write centerline coordinates in x, y, z format fid_centerline.write('%f %f %f\n' %(x_centerline_fit_full[iz], y_centerline_fit_full[iz], z_centerline_full[iz]) ) fid_centerline.close() # Prepare output data # ==================================================================================================== # write centerline as text file for iz in range(0, nz, 1): # compute inverse cumulative fitted transformation matrix fid = open(file_mat_inv_cumul_fit[iz], 'w') fid.write('%i %i %i %f\n' %(1, 0, 0, x_centerline_fit_full[iz]-x_init) ) fid.write('%i %i %i %f\n' %(0, 1, 0, y_centerline_fit_full[iz]-y_init) ) fid.write('%i %i %i %i\n' %(0, 0, 1, 0) ) fid.write('%i %i %i %i\n' %(0, 0, 0, 1) ) fid.close() # write polynomial coefficients savetxt('tmp.centerline_polycoeffs_x.txt',coeffsx) savetxt('tmp.centerline_polycoeffs_y.txt',coeffsy) # apply transformations to data print '\nApply fitted transformation matrices...' file_anat_split_fit = ['tmp.anat_orient_fit_z'+str(z).zfill(4) for z in range(0,nz,1)] file_mask_split_fit = ['tmp.mask_orient_fit_z'+str(z).zfill(4) for z in range(0,nz,1)] file_point_split_fit = ['tmp.point_orient_fit_z'+str(z).zfill(4) for z in range(0,nz,1)] for iz in range(0, nz, 1): # forward cumulative transformation to data sct.run(fsloutput+'flirt -in '+file_anat_split[iz]+' -ref '+file_anat_split[iz]+' -applyxfm -init '+file_mat_cumul_fit[iz]+' -out '+file_anat_split_fit[iz]) # inverse cumulative transformation to mask sct.run(fsloutput+'flirt -in '+file_mask_split[z_init]+' -ref '+file_mask_split[z_init]+' -applyxfm -init '+file_mat_inv_cumul_fit[iz]+' -out '+file_mask_split_fit[iz]) # inverse cumulative transformation to point sct.run(fsloutput+'flirt -in '+file_point_split[z_init]+' -ref '+file_point_split[z_init]+' -applyxfm -init '+file_mat_inv_cumul_fit[iz]+' -out '+file_point_split_fit[iz]+' -interp nearestneighbour') # Merge into 4D volume print '\nMerge into 4D volume...' # sct.run(fsloutput+'fslmerge -z tmp.anat_orient_fit tmp.anat_orient_fit_z*') # sct.run(fsloutput+'fslmerge -z tmp.mask_orient_fit tmp.mask_orient_fit_z*') # sct.run(fsloutput+'fslmerge -z tmp.point_orient_fit tmp.point_orient_fit_z*') concat_data(glob.glob('tmp.anat_orient_fit_z*.nii'), 'tmp.anat_orient_fit.nii', dim=2) concat_data(glob.glob('tmp.mask_orient_fit_z*.nii'), 'tmp.mask_orient_fit.nii', dim=2) concat_data(glob.glob('tmp.point_orient_fit_z*.nii'), 'tmp.point_orient_fit.nii', dim=2) # Copy header geometry from input data print '\nCopy header geometry from input data...' copy_header('tmp.anat_orient.nii', 'tmp.anat_orient_fit.nii') copy_header('tmp.anat_orient.nii', 'tmp.mask_orient_fit.nii') copy_header('tmp.anat_orient.nii', 'tmp.point_orient_fit.nii') # Reorient outputs into the initial orientation of the input image print '\nReorient the centerline into the initial orientation of the input image...' set_orientation('tmp.point_orient_fit.nii', input_image_orientation, 'tmp.point_orient_fit.nii') set_orientation('tmp.mask_orient_fit.nii', input_image_orientation, 'tmp.mask_orient_fit.nii') # Generate output file (in current folder) print '\nGenerate output file (in current folder)...' os.chdir('..') # come back to parent folder #sct.generate_output_file('tmp.centerline_polycoeffs_x.txt','./','centerline_polycoeffs_x','.txt') #sct.generate_output_file('tmp.centerline_polycoeffs_y.txt','./','centerline_polycoeffs_y','.txt') #sct.generate_output_file('tmp.centerline_coordinates.txt','./','centerline_coordinates','.txt') #sct.generate_output_file('tmp.anat_orient.nii','./',file_anat+'_rpi',ext_anat) #sct.generate_output_file('tmp.anat_orient_fit.nii', file_anat+'_rpi_align'+ext_anat) #sct.generate_output_file('tmp.mask_orient_fit.nii', file_anat+'_mask'+ext_anat) fname_output_centerline = sct.generate_output_file(path_tmp+'/tmp.point_orient_fit.nii', file_anat+'_centerline'+ext_anat) # Delete temporary files if remove_tmp_files == 1: print '\nRemove temporary files...' sct.run('rm -rf '+path_tmp) # print number of warnings print '\nNumber of warnings: '+str(warning_count)+' (if >10, you should probably reduce the gap and/or increase the kernel size' # display elapsed time elapsed_time = time.time() - start_time print '\nFinished! \n\tGenerated file: '+fname_output_centerline+'\n\tElapsed time: '+str(int(round(elapsed_time)))+'s\n'
def moco(param): # retrieve parameters fsloutput = 'export FSLOUTPUTTYPE=NIFTI; ' # for faster processing, all outputs are in NIFTI file_data = param.file_data file_target = param.file_target folder_mat = sct.slash_at_the_end(param.mat_moco, 1) # output folder of mat file todo = param.todo suffix = param.suffix #file_schedule = param.file_schedule verbose = param.verbose ext = '.nii' # get path of the toolbox status, path_sct = commands.getstatusoutput('echo $SCT_DIR') # print arguments sct.printv('\nInput parameters:', param.verbose) sct.printv(' Input file ............'+file_data, param.verbose) sct.printv(' Reference file ........'+file_target, param.verbose) sct.printv(' Polynomial degree .....'+param.param[0], param.verbose) sct.printv(' Smoothing kernel ......'+param.param[1], param.verbose) sct.printv(' Gradient step .........'+param.param[2], param.verbose) sct.printv(' Metric ................'+param.param[3], param.verbose) sct.printv(' Todo ..................'+todo, param.verbose) sct.printv(' Mask .................'+param.fname_mask, param.verbose) sct.printv(' Output mat folder .....'+folder_mat, param.verbose) # create folder for mat files sct.create_folder(folder_mat) # Get size of data sct.printv('\nGet dimensions data...', verbose) nx, ny, nz, nt, px, py, pz, pt = Image(file_data+ext).dim sct.printv(('.. '+str(nx)+' x '+str(ny)+' x '+str(nz)+' x '+str(nt)), verbose) # copy file_target to a temporary file sct.printv('\nCopy file_target to a temporary file...', verbose) sct.run('cp '+file_target+ext+' target.nii') file_target = 'target' # Split data along T dimension sct.printv('\nSplit data along T dimension...', verbose) from sct_split_data import split_data split_data(file_data+ext, 3, '_T') # status, output = sct.run('sct_split_data -i ' + file_data + ext + ' -dim t -suffix _T', param.verbose) file_data_splitT = file_data + '_T' # Motion correction: initialization index = np.arange(nt) file_data_splitT_num = [] file_data_splitT_moco_num = [] failed_transfo = [0 for i in range(nt)] file_mat = [[] for i in range(nt)] # Motion correction: Loop across T for indice_index in range(nt): # create indices and display stuff it = index[indice_index] file_data_splitT_num.append(file_data_splitT + str(it).zfill(4)) file_data_splitT_moco_num.append(file_data + suffix + '_T' + str(it).zfill(4)) sct.printv(('\nVolume '+str((it))+'/'+str(nt-1)+':'), verbose) file_mat[it] = folder_mat + 'mat.T' + str(it) # run 3D registration failed_transfo[it] = register(param, file_data_splitT_num[it], file_target, file_mat[it], file_data_splitT_moco_num[it]) # average registered volume with target image # N.B. use weighted averaging: (target * nb_it + moco) / (nb_it + 1) if param.iterative_averaging and indice_index < 10 and failed_transfo[it] == 0: sct.run('isct_c3d '+file_target+ext+' -scale '+str(indice_index+1)+' '+file_data_splitT_moco_num[it]+ext+' -add -scale '+str(float(1)/(indice_index+2))+' -o '+file_target+ext) # Replace failed transformation with the closest good one sct.printv(('\nReplace failed transformations...'), verbose) fT = [i for i, j in enumerate(failed_transfo) if j == 1] gT = [i for i, j in enumerate(failed_transfo) if j == 0] for it in range(len(fT)): abs_dist = [abs(gT[i]-fT[it]) for i in range(len(gT))] if not abs_dist == []: index_good = abs_dist.index(min(abs_dist)) sct.printv(' transfo #'+str(fT[it])+' --> use transfo #'+str(gT[index_good]), verbose) # copy transformation sct.run('cp '+file_mat[gT[index_good]]+'Warp.nii.gz'+' '+file_mat[fT[it]]+'Warp.nii.gz') # apply transformation sct.run('sct_apply_transfo -i '+file_data_splitT_num[fT[it]]+'.nii -d '+file_target+'.nii -w '+file_mat[fT[it]]+'Warp.nii.gz'+' -o '+file_data_splitT_moco_num[fT[it]]+'.nii'+' -p '+param.interp, verbose) else: # exit program if no transformation exists. sct.printv('\nERROR in '+os.path.basename(__file__)+': No good transformation exist. Exit program.\n', verbose, 'error') sys.exit(2) # Merge data along T file_data_moco = file_data+suffix if todo != 'estimate': sct.printv('\nMerge data back along T...', verbose) # cmd = fsloutput + 'fslmerge -t ' + file_data_moco # for indice_index in range(len(index)): # cmd = cmd + ' ' + file_data_splitT_moco_num[indice_index] cmd = 'sct_concat_data -dim t -o ' + file_data_moco + ext + ' -i ' for indice_index in range(len(index)): cmd = cmd + file_data_splitT_moco_num[indice_index] + ext + ',' cmd = cmd[:-1] # remove ',' at the end of the string sct.run(cmd, verbose)
def moco(param): # retrieve parameters fsloutput = 'export FSLOUTPUTTYPE=NIFTI; ' # for faster processing, all outputs are in NIFTI file_data = param.file_data file_target = param.file_target folder_mat = sct.slash_at_the_end(param.mat_moco, 1) # output folder of mat file todo = param.todo suffix = param.suffix #file_schedule = param.file_schedule verbose = param.verbose ext = '.nii' # get path of the toolbox status, path_sct = commands.getstatusoutput('echo $SCT_DIR') # print arguments sct.printv('\nInput parameters:', param.verbose) sct.printv(' Input file ............' + file_data, param.verbose) sct.printv(' Reference file ........' + file_target, param.verbose) sct.printv(' Polynomial degree .....' + param.param[0], param.verbose) sct.printv(' Smoothing kernel ......' + param.param[1], param.verbose) sct.printv(' Gradient step .........' + param.param[2], param.verbose) sct.printv(' Metric ................' + param.param[3], param.verbose) sct.printv(' Todo ..................' + todo, param.verbose) sct.printv(' Mask .................' + param.fname_mask, param.verbose) sct.printv(' Output mat folder .....' + folder_mat, param.verbose) # create folder for mat files sct.create_folder(folder_mat) # Get size of data sct.printv('\nGet dimensions data...', verbose) nx, ny, nz, nt, px, py, pz, pt = Image(file_data + ext).dim sct.printv(('.. ' + str(nx) + ' x ' + str(ny) + ' x ' + str(nz) + ' x ' + str(nt)), verbose) # copy file_target to a temporary file sct.printv('\nCopy file_target to a temporary file...', verbose) sct.run('cp ' + file_target + ext + ' target.nii') file_target = 'target' # Split data along T dimension sct.printv('\nSplit data along T dimension...', verbose) from sct_split_data import split_data split_data(file_data + ext, 3, '_T') # status, output = sct.run('sct_split_data -i ' + file_data + ext + ' -dim t -suffix _T', param.verbose) file_data_splitT = file_data + '_T' # Motion correction: initialization index = np.arange(nt) file_data_splitT_num = [] file_data_splitT_moco_num = [] failed_transfo = [0 for i in range(nt)] file_mat = [[] for i in range(nt)] # Motion correction: Loop across T for indice_index in range(nt): # create indices and display stuff it = index[indice_index] file_data_splitT_num.append(file_data_splitT + str(it).zfill(4)) file_data_splitT_moco_num.append(file_data + suffix + '_T' + str(it).zfill(4)) sct.printv(('\nVolume ' + str((it)) + '/' + str(nt - 1) + ':'), verbose) file_mat[it] = folder_mat + 'mat.T' + str(it) # run 3D registration failed_transfo[it] = register(param, file_data_splitT_num[it], file_target, file_mat[it], file_data_splitT_moco_num[it]) # average registered volume with target image # N.B. use weighted averaging: (target * nb_it + moco) / (nb_it + 1) if param.iterative_averaging and indice_index < 10 and failed_transfo[ it] == 0: sct.run('isct_c3d ' + file_target + ext + ' -scale ' + str(indice_index + 1) + ' ' + file_data_splitT_moco_num[it] + ext + ' -add -scale ' + str(float(1) / (indice_index + 2)) + ' -o ' + file_target + ext) # Replace failed transformation with the closest good one sct.printv(('\nReplace failed transformations...'), verbose) fT = [i for i, j in enumerate(failed_transfo) if j == 1] gT = [i for i, j in enumerate(failed_transfo) if j == 0] for it in range(len(fT)): abs_dist = [abs(gT[i] - fT[it]) for i in range(len(gT))] if not abs_dist == []: index_good = abs_dist.index(min(abs_dist)) sct.printv( ' transfo #' + str(fT[it]) + ' --> use transfo #' + str(gT[index_good]), verbose) # copy transformation sct.run('cp ' + file_mat[gT[index_good]] + 'Warp.nii.gz' + ' ' + file_mat[fT[it]] + 'Warp.nii.gz') # apply transformation sct.run( 'sct_apply_transfo -i ' + file_data_splitT_num[fT[it]] + '.nii -d ' + file_target + '.nii -w ' + file_mat[fT[it]] + 'Warp.nii.gz' + ' -o ' + file_data_splitT_moco_num[fT[it]] + '.nii' + ' -p ' + param.interp, verbose) else: # exit program if no transformation exists. sct.printv( '\nERROR in ' + os.path.basename(__file__) + ': No good transformation exist. Exit program.\n', verbose, 'error') sys.exit(2) # Merge data along T file_data_moco = file_data + suffix if todo != 'estimate': sct.printv('\nMerge data back along T...', verbose) # cmd = fsloutput + 'fslmerge -t ' + file_data_moco # for indice_index in range(len(index)): # cmd = cmd + ' ' + file_data_splitT_moco_num[indice_index] cmd = 'sct_concat_data -dim t -o ' + file_data_moco + ext + ' -i ' for indice_index in range(len(index)): cmd = cmd + file_data_splitT_moco_num[indice_index] + ext + ',' cmd = cmd[:-1] # remove ',' at the end of the string sct.run(cmd, verbose)
def main(): # Initialization fname_anat = '' fname_centerline = '' centerline_fitting = 'polynome' remove_temp_files = param.remove_temp_files interp = param.interp degree_poly = param.deg_poly # extract path of the script path_script = os.path.dirname(__file__)+'/' # Parameters for debug mode if param.debug == 1: print '\n*** WARNING: DEBUG MODE ON ***\n' status, path_sct_data = commands.getstatusoutput('echo $SCT_TESTING_DATA_DIR') fname_anat = path_sct_data+'/t2/t2.nii.gz' fname_centerline = path_sct_data+'/t2/t2_seg.nii.gz' else: # Check input param try: opts, args = getopt.getopt(sys.argv[1:],'hi:c:r:d:f:s:') except getopt.GetoptError as err: print str(err) usage() if not opts: usage() for opt, arg in opts: if opt == '-h': usage() elif opt in ('-i'): fname_anat = arg elif opt in ('-c'): fname_centerline = arg elif opt in ('-r'): remove_temp_files = int(arg) elif opt in ('-d'): degree_poly = int(arg) elif opt in ('-f'): centerline_fitting = str(arg) elif opt in ('-s'): interp = str(arg) # display usage if a mandatory argument is not provided if fname_anat == '' or fname_centerline == '': usage() # check existence of input files sct.check_file_exist(fname_anat) sct.check_file_exist(fname_centerline) # extract path/file/extension path_anat, file_anat, ext_anat = sct.extract_fname(fname_anat) # Display arguments print '\nCheck input arguments...' print ' Input volume ...................... '+fname_anat print ' Centerline ........................ '+fname_centerline print '' # Get input image orientation input_image_orientation = get_orientation(fname_anat) # Reorient input data into RL PA IS orientation set_orientation(fname_anat, 'RPI', 'tmp.anat_orient.nii') set_orientation(fname_centerline, 'RPI', 'tmp.centerline_orient.nii') # Open centerline #========================================================================================== print '\nGet dimensions of input centerline...' nx, ny, nz, nt, px, py, pz, pt = Image('tmp.centerline_orient.nii').dim print '.. matrix size: '+str(nx)+' x '+str(ny)+' x '+str(nz) print '.. voxel size: '+str(px)+'mm x '+str(py)+'mm x '+str(pz)+'mm' print '\nOpen centerline volume...' file = nibabel.load('tmp.centerline_orient.nii') data = file.get_data() X, Y, Z = (data>0).nonzero() min_z_index, max_z_index = min(Z), max(Z) # loop across z and associate x,y coordinate with the point having maximum intensity x_centerline = [0 for iz in range(min_z_index, max_z_index+1, 1)] y_centerline = [0 for iz in range(min_z_index, max_z_index+1, 1)] z_centerline = [iz for iz in range(min_z_index, max_z_index+1, 1)] # Two possible scenario: # 1. the centerline is probabilistic: each slices contains voxels with the probability of containing the centerline [0:...:1] # We only take the maximum value of the image to aproximate the centerline. # 2. The centerline/segmentation image contains many pixels per slice with values {0,1}. # We take all the points and approximate the centerline on all these points. X, Y, Z = ((data<1)*(data>0)).nonzero() # X is empty if binary image if (len(X) > 0): # Scenario 1 for iz in range(min_z_index, max_z_index+1, 1): x_centerline[iz-min_z_index], y_centerline[iz-min_z_index] = numpy.unravel_index(data[:,:,iz].argmax(), data[:,:,iz].shape) else: # Scenario 2 for iz in range(min_z_index, max_z_index+1, 1): x_seg, y_seg = (data[:,:,iz]>0).nonzero() if len(x_seg) > 0: x_centerline[iz-min_z_index] = numpy.mean(x_seg) y_centerline[iz-min_z_index] = numpy.mean(y_seg) # TODO: find a way to do the previous loop with this, which is more neat: # [numpy.unravel_index(data[:,:,iz].argmax(), data[:,:,iz].shape) for iz in range(0,nz,1)] # clear variable del data # Fit the centerline points with the kind of curve given as argument of the script and return the new smoothed coordinates if centerline_fitting == 'splines': try: x_centerline_fit, y_centerline_fit = b_spline_centerline(x_centerline,y_centerline,z_centerline) except ValueError: print "splines fitting doesn't work, trying with polynomial fitting...\n" x_centerline_fit, y_centerline_fit = polynome_centerline(x_centerline,y_centerline,z_centerline) elif centerline_fitting == 'polynome': x_centerline_fit, y_centerline_fit = polynome_centerline(x_centerline,y_centerline,z_centerline) #========================================================================================== # Split input volume print '\nSplit input volume...' from sct_split_data import split_data if not split_data('tmp.anat_orient.nii', 2, '_z'): sct.printv('ERROR in split_data.', 1, 'error') file_anat_split = ['tmp.anat_orient_z'+str(z).zfill(4) for z in range(0, nz, 1)] # initialize variables file_mat_inv_cumul = ['tmp.mat_inv_cumul_z'+str(z).zfill(4) for z in range(0,nz,1)] z_init = min_z_index displacement_max_z_index = x_centerline_fit[z_init-min_z_index]-x_centerline_fit[max_z_index-min_z_index] # write centerline as text file print '\nGenerate fitted transformation matrices...' file_mat_inv_cumul_fit = ['tmp.mat_inv_cumul_fit_z'+str(z).zfill(4) for z in range(0,nz,1)] for iz in range(min_z_index, max_z_index+1, 1): # compute inverse cumulative fitted transformation matrix fid = open(file_mat_inv_cumul_fit[iz], 'w') if (x_centerline[iz-min_z_index] == 0 and y_centerline[iz-min_z_index] == 0): displacement = 0 else: displacement = x_centerline_fit[z_init-min_z_index]-x_centerline_fit[iz-min_z_index] fid.write('%i %i %i %f\n' %(1, 0, 0, displacement) ) fid.write('%i %i %i %f\n' %(0, 1, 0, 0) ) fid.write('%i %i %i %i\n' %(0, 0, 1, 0) ) fid.write('%i %i %i %i\n' %(0, 0, 0, 1) ) fid.close() # we complete the displacement matrix in z direction for iz in range(0, min_z_index, 1): fid = open(file_mat_inv_cumul_fit[iz], 'w') fid.write('%i %i %i %f\n' %(1, 0, 0, 0) ) fid.write('%i %i %i %f\n' %(0, 1, 0, 0) ) fid.write('%i %i %i %i\n' %(0, 0, 1, 0) ) fid.write('%i %i %i %i\n' %(0, 0, 0, 1) ) fid.close() for iz in range(max_z_index+1, nz, 1): fid = open(file_mat_inv_cumul_fit[iz], 'w') fid.write('%i %i %i %f\n' %(1, 0, 0, displacement_max_z_index) ) fid.write('%i %i %i %f\n' %(0, 1, 0, 0) ) fid.write('%i %i %i %i\n' %(0, 0, 1, 0) ) fid.write('%i %i %i %i\n' %(0, 0, 0, 1) ) fid.close() # apply transformations to data print '\nApply fitted transformation matrices...' file_anat_split_fit = ['tmp.anat_orient_fit_z'+str(z).zfill(4) for z in range(0,nz,1)] for iz in range(0, nz, 1): # forward cumulative transformation to data sct.run(fsloutput+'flirt -in '+file_anat_split[iz]+' -ref '+file_anat_split[iz]+' -applyxfm -init '+file_mat_inv_cumul_fit[iz]+' -out '+file_anat_split_fit[iz]+' -interp '+interp) # Merge into 4D volume print '\nMerge into 4D volume...' from sct_concat_data import concat_data from glob import glob concat_data(glob('tmp.anat_orient_fit_z*.nii'), 'tmp.anat_orient_fit.nii', dim=2) # sct.run(fsloutput+'fslmerge -z tmp.anat_orient_fit tmp.anat_orient_fit_z*') # Reorient data as it was before print '\nReorient data back into native orientation...' set_orientation('tmp.anat_orient_fit.nii', input_image_orientation, 'tmp.anat_orient_fit_reorient.nii') # Generate output file (in current folder) print '\nGenerate output file (in current folder)...' sct.generate_output_file('tmp.anat_orient_fit_reorient.nii', file_anat+'_flatten'+ext_anat) # Delete temporary files if remove_temp_files == 1: print '\nDelete temporary files...' sct.run('rm -rf tmp.*') # to view results print '\nDone! To view results, type:' print 'fslview '+file_anat+ext_anat+' '+file_anat+'_flatten'+ext_anat+' &\n'
def register_images( fname_source, fname_dest, mask='', paramreg=Paramreg(step='0', type='im', algo='Translation', metric='MI', iter='5', shrink='1', smooth='0', gradStep='0.5'), ants_registration_params={ 'rigid': '', 'affine': '', 'compositeaffine': '', 'similarity': '', 'translation': '', 'bspline': ',10', 'gaussiandisplacementfield': ',3,0', 'bsplinedisplacementfield': ',5,10', 'syn': ',3,0', 'bsplinesyn': ',1,3' }, remove_tmp_folder=1): """Slice-by-slice registration of two images. We first split the 3D images into 2D images (and the mask if inputted). Then we register slices of the two images that physically correspond to one another looking at the physical origin of each image. The images can be of different sizes but the destination image must be smaller thant the input image. We do that using antsRegistration in 2D. Once this has been done for each slices, we gather the results and return them. Algorithms implemented: translation, rigid, affine, syn and BsplineSyn. N.B.: If the mask is inputted, it must also be 3D and it must be in the same space as the destination image. input: fname_source: name of moving image (type: string) fname_dest: name of fixed image (type: string) mask[optional]: name of mask file (type: string) (parameter -x of antsRegistration) paramreg[optional]: parameters of antsRegistration (type: Paramreg class from sct_register_multimodal) ants_registration_params[optional]: specific algorithm's parameters for antsRegistration (type: dictionary) output: if algo==translation: x_displacement: list of translation along x axis for each slice (type: list) y_displacement: list of translation along y axis for each slice (type: list) if algo==rigid: x_displacement: list of translation along x axis for each slice (type: list) y_displacement: list of translation along y axis for each slice (type: list) theta_rotation: list of rotation angle in radian (and in ITK's coordinate system) for each slice (type: list) if algo==affine or algo==syn or algo==bsplinesyn: creation of two 3D warping fields (forward and inverse) that are the concatenations of the slice-by-slice warps. """ # Extracting names path_i, root_i, ext_i = sct.extract_fname(fname_source) path_d, root_d, ext_d = sct.extract_fname(fname_dest) # set metricSize if paramreg.metric == 'MI': metricSize = '32' # corresponds to number of bins else: metricSize = '4' # corresponds to radius (for CC, MeanSquares...) # Get image dimensions and retrieve nz print '\nGet image dimensions of destination image...' nx, ny, nz, nt, px, py, pz, pt = Image(fname_dest).dim print '.. matrix size: ' + str(nx) + ' x ' + str(ny) + ' x ' + str(nz) print '.. voxel size: ' + str(px) + 'mm x ' + str(py) + 'mm x ' + str( pz) + 'mm' # Define x and y displacement as list x_displacement = [0 for i in range(nz)] y_displacement = [0 for i in range(nz)] theta_rotation = [0 for i in range(nz)] # create temporary folder print('\nCreate temporary folder...') path_tmp = 'tmp.' + time.strftime("%y%m%d%H%M%S") sct.create_folder(path_tmp) print '\nCopy input data...' sct.run('cp ' + fname_source + ' ' + path_tmp + '/' + root_i + ext_i) sct.run('cp ' + fname_dest + ' ' + path_tmp + '/' + root_d + ext_d) if mask: sct.run('cp ' + mask + ' ' + path_tmp + '/mask.nii.gz') # go to temporary folder os.chdir(path_tmp) # Split input volume along z print '\nSplit input volume...' from sct_split_data import split_data split_data(fname_source, 2, '_z') # Split destination volume along z print '\nSplit destination volume...' split_data(fname_dest, 2, '_z') # Split mask volume along z if mask: print '\nSplit mask volume...' split_data('mask.nii.gz', 2, '_z') im_dest_img = Image(fname_dest) im_input_img = Image(fname_source) coord_origin_dest = im_dest_img.transfo_pix2phys([[0, 0, 0]]) coord_origin_input = im_input_img.transfo_pix2phys([[0, 0, 0]]) coord_diff_origin = (asarray(coord_origin_dest[0]) - asarray(coord_origin_input[0])).tolist() [x_o, y_o, z_o] = [ coord_diff_origin[0] * 1.0 / px, coord_diff_origin[1] * 1.0 / py, coord_diff_origin[2] * 1.0 / pz ] if paramreg.algo == 'BSplineSyN' or paramreg.algo == 'SyN' or paramreg.algo == 'Affine': list_warp_x = [] list_warp_x_inv = [] list_warp_y = [] list_warp_y_inv = [] name_warp_final = 'Warp_total' #if modified, name should also be modified in msct_register (algo slicereg2d_bsplinesyn and slicereg2d_syn) # loop across slices for i in range(nz): # set masking num = numerotation(i) num_2 = numerotation(int(num) + int(z_o)) if mask: masking = '-x mask_z' + num + '.nii' else: masking = '' cmd = ( 'isct_antsRegistration ' '--dimensionality 2 ' '--transform ' + paramreg.algo + '[' + str(paramreg.gradStep) + ants_registration_params[paramreg.algo.lower()] + '] ' '--metric ' + paramreg.metric + '[' + root_d + '_z' + num + '.nii' + ',' + root_i + '_z' + num_2 + '.nii' + ',1,' + metricSize + '] ' #[fixedImage,movingImage,metricWeight +nb_of_bins (MI) or radius (other) '--convergence ' + str(paramreg.iter) + ' ' '--shrink-factors ' + str(paramreg.shrink) + ' ' '--smoothing-sigmas ' + str(paramreg.smooth) + 'mm ' #'--restrict-deformation 1x1x0 ' # how to restrict? should not restrict here, if transform is precised...? '--output [transform_' + num + ',' + root_i + '_z' + num_2 + 'reg.nii] ' #--> file.mat (contains Tx,Ty, theta) '--interpolation BSpline[3] ' + masking) try: sct.run(cmd) if paramreg.algo == 'Rigid' or paramreg.algo == 'Translation': f = 'transform_' + num + '0GenericAffine.mat' matfile = loadmat(f, struct_as_record=True) array_transfo = matfile['AffineTransform_double_2_2'] x_displacement[i] = array_transfo[4][ 0] # Tx in ITK'S coordinate system y_displacement[i] = array_transfo[5][ 0] # Ty in ITK'S and fslview's coordinate systems theta_rotation[i] = asin( array_transfo[2] ) # angle of rotation theta in ITK'S coordinate system (minus theta for fslview) if paramreg.algo == 'Affine': # New process added for generating total nifti warping field from mat warp name_dest = root_d + '_z' + num + '.nii' name_reg = root_i + '_z' + num + 'reg.nii' name_output_warp = 'warp_from_mat_' + num_2 + '.nii.gz' name_output_warp_inverse = 'warp_from_mat_' + num + '_inverse.nii.gz' name_warp_null = 'warp_null_' + num + '.nii.gz' name_warp_null_dest = 'warp_null_dest' + num + '.nii.gz' name_warp_mat = 'transform_' + num + '0GenericAffine.mat' # Generating null nifti warping fields nx, ny, nz, nt, px, py, pz, pt = Image(name_reg).dim nx_d, ny_d, nz_d, nt_d, px_d, py_d, pz_d, pt_d = Image( name_dest).dim x_trans = [0 for i in range(nz)] x_trans_d = [0 for i in range(nz_d)] y_trans = [0 for i in range(nz)] y_trans_d = [0 for i in range(nz_d)] generate_warping_field(name_reg, x_trans=x_trans, y_trans=y_trans, fname=name_warp_null, verbose=0) generate_warping_field(name_dest, x_trans=x_trans_d, y_trans=y_trans_d, fname=name_warp_null_dest, verbose=0) # Concatenating mat wrp and null nifti warp to obtain equivalent nifti warp to mat warp sct.run('isct_ComposeMultiTransform 2 ' + name_output_warp + ' -R ' + name_reg + ' ' + name_warp_null + ' ' + name_warp_mat) sct.run('isct_ComposeMultiTransform 2 ' + name_output_warp_inverse + ' -R ' + name_dest + ' ' + name_warp_null_dest + ' -i ' + name_warp_mat) # Split the warping fields into two for displacement along x and y before merge sct.run('isct_c3d -mcs ' + name_output_warp + ' -oo transform_' + num + '0Warp_x.nii.gz transform_' + num + '0Warp_y.nii.gz') sct.run('isct_c3d -mcs ' + name_output_warp_inverse + ' -oo transform_' + num + '0InverseWarp_x.nii.gz transform_' + num + '0InverseWarp_y.nii.gz') # List names of warping fields for futur merge list_warp_x.append('transform_' + num + '0Warp_x.nii.gz') list_warp_x_inv.append('transform_' + num + '0InverseWarp_x.nii.gz') list_warp_y.append('transform_' + num + '0Warp_y.nii.gz') list_warp_y_inv.append('transform_' + num + '0InverseWarp_y.nii.gz') if paramreg.algo == 'BSplineSyN' or paramreg.algo == 'SyN': # Split the warping fields into two for displacement along x and y before merge # Need to separate the merge for x and y displacement as merge of 3d warping fields does not work properly sct.run('isct_c3d -mcs transform_' + num + '0Warp.nii.gz -oo transform_' + num + '0Warp_x.nii.gz transform_' + num + '0Warp_y.nii.gz') sct.run('isct_c3d -mcs transform_' + num + '0InverseWarp.nii.gz -oo transform_' + num + '0InverseWarp_x.nii.gz transform_' + num + '0InverseWarp_y.nii.gz') # List names of warping fields for futur merge list_warp_x.append('transform_' + num + '0Warp_x.nii.gz') list_warp_x_inv.append('transform_' + num + '0InverseWarp_x.nii.gz') list_warp_y.append('transform_' + num + '0Warp_y.nii.gz') list_warp_y_inv.append('transform_' + num + '0InverseWarp_y.nii.gz') # if an exception occurs with ants, take the last value for the transformation except: if paramreg.algo == 'Rigid' or paramreg.algo == 'Translation': x_displacement[i] = x_displacement[i - 1] y_displacement[i] = y_displacement[i - 1] theta_rotation[i] = theta_rotation[i - 1] if paramreg.algo == 'BSplineSyN' or paramreg.algo == 'SyN' or paramreg.algo == 'Affine': print 'Problem with ants for slice ' + str( i) + '. Copy of the last warping field.' sct.run('cp transform_' + numerotation(i - 1) + '0Warp.nii.gz transform_' + num + '0Warp.nii.gz') sct.run('cp transform_' + numerotation(i - 1) + '0InverseWarp.nii.gz transform_' + num + '0InverseWarp.nii.gz') # Split the warping fields into two for displacement along x and y before merge sct.run('isct_c3d -mcs transform_' + num + '0Warp.nii.gz -oo transform_' + num + '0Warp_x.nii.gz transform_' + num + '0Warp_y.nii.gz') sct.run('isct_c3d -mcs transform_' + num + '0InverseWarp.nii.gz -oo transform_' + num + '0InverseWarp_x.nii.gz transform_' + num + '0InverseWarp_y.nii.gz') # List names of warping fields for futur merge list_warp_x.append('transform_' + num + '0Warp_x.nii.gz') list_warp_x_inv.append('transform_' + num + '0InverseWarp_x.nii.gz') list_warp_y.append('transform_' + num + '0Warp_y.nii.gz') list_warp_y_inv.append('transform_' + num + '0InverseWarp_y.nii.gz') if paramreg.algo == 'BSplineSyN' or paramreg.algo == 'SyN' or paramreg.algo == 'Affine': print '\nMerge along z of the warping fields...' # from sct_concat_data import concat_data sct.run('sct_concat_data -i ' + ','.join(list_warp_x) + ' -o ' + name_warp_final + '_x.nii.gz -dim z') sct.run('sct_concat_data -i ' + ','.join(list_warp_x_inv) + ' -o ' + name_warp_final + '_x_inverse.nii.gz -dim z') sct.run('sct_concat_data -i ' + ','.join(list_warp_y) + ' -o ' + name_warp_final + '_y.nii.gz -dim z') sct.run('sct_concat_data -i ' + ','.join(list_warp_y_inv) + ' -o ' + name_warp_final + '_y_inverse.nii.gz -dim z') # concat_data(','.join(list_warp_x), name_warp_final+'_x.nii.gz', 2) # concat_data(','.join(list_warp_x_inv), name_warp_final+'_x_inverse.nii.gz', 2) # concat_data(','.join(list_warp_y), name_warp_final+'_y.nii.gz', 2) # concat_data(','.join(list_warp_y_inv), name_warp_final+'_y_inverse.nii.gz', 2) # sct.run('fslmerge -z ' + name_warp_final + '_x ' + " ".join(list_warp_x)) # sct.run('fslmerge -z ' + name_warp_final + '_x_inverse ' + " ".join(list_warp_x_inv)) # sct.run('fslmerge -z ' + name_warp_final + '_y ' + " ".join(list_warp_y)) # sct.run('fslmerge -z ' + name_warp_final + '_y_inverse ' + " ".join(list_warp_y_inv)) print '\nChange resolution of warping fields to match the resolution of the destination image...' from sct_copy_header import copy_header copy_header(fname_dest, name_warp_final + '_x.nii.gz') copy_header(fname_source, name_warp_final + '_x_inverse.nii.gz') copy_header(fname_dest, name_warp_final + '_y.nii.gz') copy_header(fname_source, name_warp_final + '_y_inverse.nii.gz') print '\nMerge translation fields along x and y into one global warping field ' sct.run('isct_c3d ' + name_warp_final + '_x.nii.gz ' + name_warp_final + '_y.nii.gz -omc 2 ' + name_warp_final + '.nii.gz') sct.run('isct_c3d ' + name_warp_final + '_x_inverse.nii.gz ' + name_warp_final + '_y_inverse.nii.gz -omc 2 ' + name_warp_final + '_inverse.nii.gz') print '\nCopy to parent folder...' sct.run('cp ' + name_warp_final + '.nii.gz ../') sct.run('cp ' + name_warp_final + '_inverse.nii.gz ../') #Delete tmp folder os.chdir('../') if remove_tmp_folder: print('\nRemove temporary files...') sct.run('rm -rf ' + path_tmp) if paramreg.algo == 'Rigid': return x_displacement, y_displacement, theta_rotation if paramreg.algo == 'Translation': return x_displacement, y_displacement
def main(args = None): orientation = '' change_header = '' fname_out = '' if not args: args = sys.argv[1:] # Building the command, do sanity checks parser = get_parser() arguments = parser.parse(sys.argv[1:]) fname_in = arguments['-i'] if '-o' in arguments: fname_out = arguments['-o'] if '-s' in arguments: orientation = arguments['-s'] if '-a' in arguments: change_header = arguments['-a'] remove_tmp_files = int(arguments['-r']) verbose = int(arguments['-v']) inversion = False # change orientation # create temporary folder sct.printv('\nCreate temporary folder...', verbose) path_tmp = 'tmp.'+time.strftime("%y%m%d%H%M%S/") status, output = sct.run('mkdir '+path_tmp, verbose) # copy file in temp folder sct.printv('\nCopy files to tmp folder...', verbose) convert(fname_in, path_tmp+'data.nii') # go to temp folder os.chdir(path_tmp) # Get dimensions of data sct.printv('\nGet dimensions of data...', verbose) nx, ny, nz, nt, px, py, pz, pt = Image('data.nii').dim sct.printv(str(nx) + ' x ' + str(ny) + ' x ' + str(nz)+ ' x ' + str(nt), verbose) # if data are 3d, directly set or get orientation if nt == 1: if orientation != '': # set orientation sct.printv('\nChange orientation...', verbose) if change_header == '': set_orientation('data.nii', orientation, 'data_orient.nii') else: set_orientation('data.nii', change_header, 'data_orient.nii', True) else: # get orientation sct.printv('\nGet orientation...', verbose) print get_orientation('data.nii') else: # split along T dimension sct.printv('\nSplit along T dimension...', verbose) from sct_split_data import split_data split_data('data.nii', 3, '_T') if orientation != '': # set orientation sct.printv('\nChange orientation...', verbose) for it in range(nt): file_data_split = 'data_T'+str(it).zfill(4)+'.nii' file_data_split_orient = 'data_orient_T'+str(it).zfill(4)+'.nii' set_orientation(file_data_split, orientation, file_data_split_orient) # Merge files back sct.printv('\nMerge file back...', verbose) from sct_concat_data import concat_data from glob import glob concat_data(glob('data_orient_T*.nii'), 'data_orient.nii', dim=3) else: sct.printv('\nGet orientation...', verbose) print get_orientation('data_T0000.nii') # come back to parent folder os.chdir('..') # Generate output files if orientation != '': # Build fname_out if fname_out == '': path_data, file_data, ext_data = sct.extract_fname(fname_in) fname_out = path_data+file_data+'_'+orientation+ext_data sct.printv('\nGenerate output files...', verbose) sct.generate_output_file(path_tmp+'data_orient.nii', fname_out) # Remove temporary files if remove_tmp_files == 1: sct.printv('\nRemove temporary files...', verbose) sct.run('rm -rf '+path_tmp, verbose)
def resample(): fsloutput = 'export FSLOUTPUTTYPE=NIFTI; ' # for faster processing, all outputs are in NIFTI ext = '.nii' # display usage if a mandatory argument is not provided if param.fname_data == '' or param.factor == '': sct.printv('\nERROR: All mandatory arguments are not provided. See usage (add -h).\n', 1, 'error') # check existence of input files sct.printv('\nCheck existence of input files...', param.verbose) sct.check_file_exist(param.fname_data, param.verbose) # extract resampling factor sct.printv('\nParse resampling factor...', param.verbose) factor_split = param.factor.split('x') factor = [float(factor_split[i]) for i in range(len(factor_split))] # check if it has three values if not len(factor) == 3: sct.printv('\nERROR: factor should have three dimensions. E.g., 2x2x1.\n', 1, 'error') else: fx, fy, fz = [float(factor_split[i]) for i in range(len(factor_split))] # check interpolation if param.interpolation not in ['NearestNeighbor','Linear','Cubic','Sinc','Gaussian']: sct.printv('\nERROR: interpolation should be one of those:NearestNeighbor|Linear|Cubic|Sinc|Gaussian.\n', 1, 'error') # display input parameters sct.printv('\nInput parameters:', param.verbose) sct.printv(' data ..................'+param.fname_data, param.verbose) sct.printv(' resampling factor .....'+param.factor, param.verbose) # Extract path/file/extension path_data, file_data, ext_data = sct.extract_fname(param.fname_data) path_out, file_out, ext_out = '', file_data, ext_data # create temporary folder sct.printv('\nCreate temporary folder...', param.verbose) path_tmp = sct.slash_at_the_end('tmp.'+time.strftime("%y%m%d%H%M%S"), 1) sct.run('mkdir '+path_tmp, param.verbose) # Copying input data to tmp folder and convert to nii # NB: cannot use c3d here because c3d cannot convert 4D data. sct.printv('\nCopying input data to tmp folder and convert to nii...', param.verbose) sct.run('cp '+param.fname_data+' '+path_tmp+'data'+ext_data, param.verbose) # go to tmp folder os.chdir(path_tmp) # convert to nii format convert('data'+ext_data, 'data.nii') # Get dimensions of data sct.printv('\nGet dimensions of data...', param.verbose) nx, ny, nz, nt, px, py, pz, pt = Image('data.nii').dim sct.printv(' ' + str(nx) + ' x ' + str(ny) + ' x ' + str(nz)+ ' x ' + str(nt), param.verbose) dim = 4 # by default, will be adjusted later if nt == 1: dim = 3 if nz == 1: dim = 2 sct.run('ERROR (sct_resample): Dimension of input data is different from 3 or 4. Exit program', param.verbose, 'error') # Calculate new dimensions sct.printv('\nCalculate new dimensions...', param.verbose) nx_new = int(round(nx*fx)) ny_new = int(round(ny*fy)) nz_new = int(round(nz*fz)) sct.printv(' ' + str(nx_new) + ' x ' + str(ny_new) + ' x ' + str(nz_new)+ ' x ' + str(nt), param.verbose) # if dim=4, split data if dim == 4: # Split into T dimension sct.printv('\nSplit along T dimension...', param.verbose) from sct_split_data import split_data split_data('data.nii', 3, '_T') elif dim == 3: # rename file to have compatible code with 4d status, output = sct.run('cp data.nii data_T0000.nii', param.verbose) for it in range(nt): # identify current volume file_data_splitT = 'data_T'+str(it).zfill(4) file_data_splitT_resample = file_data_splitT+'r' # resample volume sct.printv(('\nResample volume '+str((it+1))+'/'+str(nt)+':'), param.verbose) sct.run('isct_c3d '+file_data_splitT+ext+' -interpolation '+param.interpolation+' -resample '+str(nx_new)+'x'+str(ny_new)+'x'+str(nz_new)+'vox -o '+file_data_splitT_resample+ext) # pad data (for ANTs) # # TODO: check if need to pad also for the estimate_and_apply # if program == 'ants' and todo == 'estimate' and slicewise == 0: # sct.run('isct_c3d '+file_data_splitT_num[it]+' -pad 0x0x3vox 0x0x3vox 0 -o '+file_data_splitT_num[it]+'_pad.nii') # file_data_splitT_num[it] = file_data_splitT_num[it]+'_pad' # merge data back along T file_data_resample = file_data+param.file_suffix sct.printv('\nMerge data back along T...', param.verbose) from sct_concat_data import concat_data import glob concat_data(glob.glob('data_T*r.nii'), file_data_resample, dim=3) # come back to parent folder os.chdir('..') # Generate output files sct.printv('\nGenerate output files...', param.verbose) if not param.fname_out: param.fname_out = path_out+file_out+param.file_suffix+ext_out sct.generate_output_file(path_tmp+file_data_resample+ext, param.fname_out) # Remove temporary files if param.remove_tmp_files == 1: print('\nRemove temporary files...') sct.run('rm -rf '+path_tmp, param.verbose) # to view results sct.printv('\nDone! To view results, type:', param.verbose) sct.printv('fslview '+param.fname_out+' &', param.verbose, 'info') print
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')