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
self.im_plot_frontal.set_interpolation('nearest') ax = self.fig.add_subplot(223) self.im_plot_sagittal = ax.imshow(self.image.data[:,:,int(self.im_size[2]/2)]) self.im_plot_sagittal.set_cmap('gray') self.im_plot_sagittal.set_interpolation('nearest') trio = TrioPlot(self.im_plot_axial, self.im_plot_frontal, self.im_plot_sagittal, self.image) trio.connect() #slider_ax = self.fig.add_axes([0.15, 0.05, 0.75, 0.03]) #slider_axial = Slider(slider_ax, 'Axial slices', 0, self.im_size[1], valinit=int(self.im_size[1]/2)) #slider_axial.on_changed(self.updateAxial) plt.show() #======================================================================================================================= # Start program #======================================================================================================================= if __name__ == "__main__": parser = Parser(__file__) parser.usage.set_description('Volume Viewer') parser.add_option("-i", "file", "file", True) arguments = parser.parse(sys.argv[1:]) image = Image(arguments["-i"]) viewer = VolViewer(image) viewer.show()
def generate_warping_field(fname_dest, x_trans, y_trans, theta_rot=None, center_rotation=None, fname='warping_field.nii.gz', verbose=1): """Generation of a warping field towards an image and given transformation parameters. Given a destination image and transformation parameters this functions creates a NIFTI 3D warping field that can be applied afterwards. The transformation parameters corresponds to a slice-by-slice registration of images, thus the transformation parameters must be precised for each slice of the image. inputs: fname_dest: name of destination image (type: string) x_trans: list of translations along x axis for each slice (type: list, length: height of fname_dest) y_trans: list of translations along y axis for each slice (type: list, length: height of fname_dest) theta_rot[optional]: list of rotation angles in radian (and in ITK's coordinate system) for each slice (type: list) center_rotation[optional]: pixel coordinates in plan xOy of the wanted center of rotation (type: list, length: 2, example: [0,ny/2]) fname[optional]: name of output warp (type: string) verbose: display parameter (type: int) output: creation of a warping field of name 'fname' with an header similar to the destination image. """ from nibabel import load from math import cos, sin from sct_orientation import get_orientation #Make sure image is in rpi format sct.printv( '\nChecking if the image of destination is in RPI orientation for the warping field generation ...', verbose) orientation = get_orientation(fname_dest) if orientation != 'RPI': sct.printv( '\nWARNING: The image of destination is not in RPI format. Dimensions of the warping field might be inverted.', verbose) else: sct.printv('\tOK', verbose) sct.printv( '\n\nCreating warping field ' + fname + ' for transformations along z...', verbose) file_dest = load(fname_dest) hdr_file_dest = file_dest.get_header() hdr_warp = hdr_file_dest.copy() # Get image dimensions sct.printv('\nGet image dimensions of destination image...', verbose) nx, ny, nz, nt, px, py, pz, pt = Image(fname_dest).dim sct.printv( '.. matrix size: ' + str(nx) + ' x ' + str(ny) + ' x ' + str(nz), verbose) sct.printv( '.. voxel size: ' + str(px) + 'mm x ' + str(py) + 'mm x ' + str(pz) + 'mm', verbose) #Center of rotation if center_rotation == None: x_a = int(round(nx / 2)) y_a = int(round(ny / 2)) else: x_a = center_rotation[0] y_a = center_rotation[1] # Calculate displacement for each voxel data_warp = zeros(((((nx, ny, nz, 1, 3))))) # For translations if theta_rot == None: for i in range(nx): for j in range(ny): for k in range(nz): data_warp[i, j, k, 0, 0] = x_trans[k] data_warp[i, j, k, 0, 1] = y_trans[k] data_warp[i, j, k, 0, 2] = 0 # # For rigid transforms (not optimized) # if theta_rot != None: # for k in range(nz): # for i in range(nx): # for j in range(ny): # # data_warp[i, j, k, 0, 0] = (cos(theta_rot[k])-1) * (i - x_a) - sin(theta_rot[k]) * (j - y_a) - x_trans[k] # # data_warp[i, j, k, 0, 1] = -(sin(theta_rot[k]) * (i - x_a) + (cos(theta_rot[k])-1) * (j - y_a)) + y_trans[k] # # data_warp[i, j, k, 0, 0] = (cos(theta_rot[k]) - 1) * (i - x_a) - sin(theta_rot[k]) * (j - y_a) + x_trans[k] #+ sin(theta_rot[k]) * (int(round(nx/2))-x_a) # data_warp[i, j, k, 0, 1] = - sin(theta_rot[k]) * (i - x_a) - (cos(theta_rot[k]) - 1) * (j - y_a) + y_trans[k] #- sin(theta_rot[k]) * (int(round(nx/2))-x_a) # data_warp[i, j, k, 0, 2] = 0 # For rigid transforms with array (time optimization) if theta_rot != None: vector_i = [[[i - x_a], [j - y_a]] for i in range(nx) for j in range(ny)] for k in range(nz): matrix_rot_a = asarray([[cos(theta_rot[k]), -sin(theta_rot[k])], [-sin(theta_rot[k]), -cos(theta_rot[k])]]) tmp = matrix_rot_a + array(((-1, 0), (0, 1))) result = dot(tmp, array(vector_i).T[0]) + array([[x_trans[k]], [y_trans[k]]]) for i in range(nx): data_warp[i, :, k, 0, 0] = result[0][i * nx:i * nx + ny] data_warp[i, :, k, 0, 1] = result[1][i * nx:i * nx + ny] # Generate warp file as a warping field hdr_warp.set_intent('vector', (), '') hdr_warp.set_data_dtype('float32') img = nibabel.Nifti1Image(data_warp, None, hdr_warp) nibabel.save(img, fname) sct.printv('\nDONE ! Warping field generated: ' + fname, verbose)
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)
if '-bin' in arguments: fname_input1_bin = sct.add_suffix(fname_input1, '_bin') sct.run([ 'sct_maths', '-i', fname_input1, '-bin', '0', '-o', fname_input1_bin ]) fname_input1 = fname_input1_bin fname_input2_bin = sct.add_suffix(fname_input2, '_bin') sct.run([ 'sct_maths', '-i', fname_input2, '-bin', '0', '-o', fname_input2_bin ]) fname_input2 = fname_input2_bin # copy header of im_1 to im_2 im_1, im_2 = Image(fname_input1), Image(fname_input2) im_2_cor = copy_header(im_1, im_2) im_2_cor.save() cmd = ['isct_dice_coefficient', fname_input1, fname_input2] if '-2d-slices' in arguments: cmd += ['-2d-slices', arguments['-2d-slices']] if '-b' in arguments: bounding_box = arguments['-b'] cmd += ['-b'] + bounding_box if '-bmax' in arguments and arguments['-bmax'] == '1': cmd += ['-bmax'] if '-bzmax' in arguments and arguments['-bzmax'] == '1': cmd += ['-bzmax'] if '-o' in arguments:
def crop(self): """ Crop image (change dimension) """ # create command line self.cmd = [ "isct_crop_image", "-i", self.input_filename, "-o", self.output_filename ] # Handling optional arguments # if mask is specified, find -start and -end arguments if self.mask is not None: # if user already specified -start or -end arguments, let him know they will be ignored if self.start is not None or self.end is not None: sct.printv( 'WARNING: Mask was specified for cropping. Arguments -start and -end will be ignored', 1, 'warning') self.start, self.end, self.dim = find_mask_boundaries(self.mask) if self.start is not None: self.cmd += ["-start", ','.join(map(str, self.start))] if self.end is not None: self.cmd += ["-end", ','.join(map(str, self.end))] if self.dim is not None: self.cmd += ["-dim", ','.join(map(str, self.dim))] if self.shift is not None: self.cmd += ["-shift", ','.join(map(str, self.shift))] if self.background is not None: self.cmd += ["-b", str(self.background)] if self.bmax is True: self.cmd += ["-bmax"] if self.ref is not None: self.cmd += ["-ref", self.ref] if self.mesh is not None: self.cmd += ["-mesh", self.mesh] verb = 0 if self.verbose == 1: verb = 2 if self.mask is not None and self.background is not None: self.crop_from_mask_with_background() else: # Run command line sct.run(self.cmd, verb) self.result = Image(self.output_filename, verbose=self.verbose) # removes the output file created by the script if it is not needed if self.rm_output_file: try: os.remove(self.output_filename) except OSError: sct.printv( "WARNING : Couldn't remove output file. Either it is opened elsewhere or " "it doesn't exist.", self.verbose, 'warning') else: sct.display_viewer_syntax([self.output_filename]) return self.result
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') # sct.printv(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.poly, param.verbose) sct.printv(' Smoothing kernel ......' + param.smooth, param.verbose) sct.printv(' Gradient step .........' + param.gradStep, param.verbose) sct.printv(' Metric ................' + param.metric, param.verbose) sct.printv(' Sampling ..............' + param.sampling, 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) data_im = Image(file_data + ext) nx, ny, nz, nt, px, py, pz, pt = data_im.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) data_split_list = split_data(data_im, dim=3) for im in data_split_list: im.save() 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 and not param.todo == 'apply': sct.run('sct_maths -i ' + file_target + ext + ' -mul ' + str(indice_index + 1) + ' -o ' + file_target + ext) sct.run('sct_maths -i ' + file_target + ext + ' -add ' + file_data_splitT_moco_num[it] + ext + ' -o ' + file_target + ext) sct.run('sct_maths -i ' + file_target + ext + ' -div ' + str(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' + ' -x ' + 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) from sct_image import concat_data # im_list = [] fname_list = [] for indice_index in range(len(index)): # im_list.append(Image(file_data_splitT_moco_num[indice_index] + ext)) fname_list.append(file_data_splitT_moco_num[indice_index] + ext) im_out = concat_data(fname_list, 3) im_out.setFileName(file_data_moco + ext) im_out.save() # delete file target.nii (to avoid conflict if this function is run another time) sct.printv('\nRemove temporary file...', verbose) # os.remove('target.nii') sct.run('rm target.nii')
def continuous_vertebral_levels(self): """ This function transforms the vertebral levels file from the template into a continuous file. Instead of having integer representing the vertebral level on each slice, a continuous value that represents the position of the slice in the vertebral level coordinate system. The image must be RPI :return: """ im_input = Image(self.image_input, self.verbose) im_output = Image(self.image_input, self.verbose) im_output.data *= 0 # 1. extract vertebral levels from input image # a. extract centerline # b. for each slice, extract corresponding level nx, ny, nz, nt, px, py, pz, pt = im_input.dim from sct_straighten_spinalcord import smooth_centerline x_centerline_fit, y_centerline_fit, z_centerline_fit, x_centerline_deriv, y_centerline_deriv, z_centerline_deriv = smooth_centerline( self.image_input, algo_fitting='nurbs', verbose=0) value_centerline = np.array([ im_input.data[int(x_centerline_fit[it]), int(y_centerline_fit[it]), int(z_centerline_fit[it])] for it in range(len(z_centerline_fit)) ]) # 2. compute distance for each vertebral level --> Di for i being the vertebral levels vertebral_levels = {} for slice_image, level in enumerate(value_centerline): if level not in vertebral_levels: vertebral_levels[level] = slice_image length_levels = {} for level in vertebral_levels: indexes_slice = np.where(value_centerline == level) length_levels[level] = np.sum([ math.sqrt( ((x_centerline_fit[indexes_slice[0][index_slice + 1]] - x_centerline_fit[indexes_slice[0][index_slice]]) * px)**2 + ((y_centerline_fit[indexes_slice[0][index_slice + 1]] - y_centerline_fit[indexes_slice[0][index_slice]]) * py)**2 + ((z_centerline_fit[indexes_slice[0][index_slice + 1]] - z_centerline_fit[indexes_slice[0][index_slice]]) * pz)**2) for index_slice in range(len(indexes_slice[0]) - 1) ]) # 2. for each slice: # a. identify corresponding vertebral level --> i # b. calculate distance of slice from upper vertebral level --> d # c. compute relative distance in the vertebral level coordinate system --> d/Di continuous_values = {} for it, iz in enumerate(z_centerline_fit): level = value_centerline[it] indexes_slice = np.where(value_centerline == level) indexes_slice = indexes_slice[0][indexes_slice[0] >= it] distance_from_level = np.sum([ math.sqrt(((x_centerline_fit[indexes_slice[index_slice + 1]] - x_centerline_fit[indexes_slice[index_slice]]) * px * px)**2 + ((y_centerline_fit[indexes_slice[index_slice + 1]] - y_centerline_fit[indexes_slice[index_slice]]) * py * py)**2 + ((z_centerline_fit[indexes_slice[index_slice + 1]] - z_centerline_fit[indexes_slice[index_slice]]) * pz * pz)**2) for index_slice in range(len(indexes_slice) - 1) ]) continuous_values[iz] = level + 2.0 * distance_from_level / float( length_levels[level]) # 3. saving data # for each slice, get all non-zero pixels and replace with continuous values coordinates_input = self.image_input.getNonZeroCoordinates() im_output.changeType('float32') # for all points in input, find the value that has to be set up, depending on the vertebral level for i, coord in enumerate(coordinates_input): im_output.data[int(coord.x), int(coord.y), int(coord.z)] = continuous_values[coord.z] return im_output
def crop_image_around_segmentation(fname_in, fname_seg, path_output_im, path_output_seg, size_crop, offset, remove_tmp_files, verbose): # 1. Resample to 1mm^3 isotropic fname_in_resampled = sct.add_suffix(fname_in, 'r') sct.run('sct_resample -i ' + fname_in + ' -mm 1x1x1 -o ' + fname_in_resampled, verbose=verbose) fname_in = fname_in_resampled fname_seg_resample = sct.add_suffix(fname_seg, 'r') sct.run('sct_resample -i ' + fname_seg + ' -mm 1x1x1 -o ' + fname_seg_resample, verbose=verbose) fname_seg = fname_seg_resample # 2. Orient both input images to RPI for the sake of simplicity sct.run('sct_image -i ' + fname_in + ' -setorient RPI', verbose=verbose) fname_in = sct.add_suffix(fname_in, '_RPI') sct.run('sct_image -i ' + fname_seg + ' -setorient RPI', verbose=verbose) fname_seg = sct.add_suffix(fname_seg, '_RPI') # 3. Pad both images to avoid edge issues when cropping fname_in_pad = sct.add_suffix(fname_in, 'p') pad_image = str(int(int(size_crop) / 2)) sct.run('sct_image -i ' + fname_in + ' -pad ' + pad_image + ',' + pad_image + ',0 -o ' + fname_in_pad, verbose=verbose) fname_in = fname_in_pad fname_seg_pad = sct.add_suffix(fname_seg, 'p') sct.run('sct_image -i ' + fname_seg + ' -pad ' + pad_image + ',' + pad_image + ',0 -o ' + fname_seg_pad, verbose=verbose) fname_seg = fname_seg_pad # 4. Extract centerline from segmentation fname_centerline = sct.add_suffix(fname_seg, '_centerline') sct.run('sct_process_segmentation -i ' + fname_seg + ' -p centerline', verbose=verbose) # -o ' + fname_centerline) # 5. Create a square mask around the spinal cord centerline fname_mask_box = 'mask_box.nii.gz' sct.run('sct_create_mask -i ' + fname_in + ' -m centerline,' + fname_centerline + ' -s ' + str(size_crop) + ' -o ' + fname_mask_box + ' -f box -e 1 -k ' + offset, verbose=verbose) # 6. Crop image around the spinal cord and create a stack of square images sct.printv('Cropping around mask and stacking slices...', verbose=verbose) im_mask_box = Image(fname_mask_box) im_input = Image(fname_in) im_input.crop_and_stack(im_mask_box, suffix='_stack', save=True) im_seg = Image(fname_seg) im_seg.crop_and_stack(im_mask_box, suffix='_stack', save=True) # 6.5 Change name of images fname_stack_image = sct.add_suffix(fname_in, '_stack') fname_stack_seg = sct.add_suffix(fname_seg, '_stack') import random output_im_filename = str(random.randint(1, 1000000000000)) output_im_fname = output_im_filename + '_im.nii.gz' output_seg_fname = output_im_filename + '_seg.nii.gz' sct.run('mv ' + fname_stack_image + ' ' + output_im_fname, verbose=verbose) sct.run('mv ' + fname_stack_seg + ' ' + output_seg_fname, verbose=verbose) # 7. Split the two stack images and save each slice sct.run('sct_image -i ' + output_im_fname + ' -split z', verbose=verbose) sct.run('sct_image -i ' + output_seg_fname + ' -split z', verbose=verbose) # 8. Move all images to output folders path_fname, file_fname, ext_fname = sct.extract_fname(output_im_fname) sct.run('mv ' + file_fname + '_* ' + path_output_im, verbose=verbose) path_fname, file_fname, ext_fname = sct.extract_fname(output_seg_fname) sct.run('mv ' + file_fname + '_* ' + path_output_seg, verbose=verbose)
def main(): # Initialization fname_mt0 = '' fname_mt1 = '' file_out = param.file_out # register = param.register # remove_tmp_files = param.remove_tmp_files # verbose = param.verbose # get path of the toolbox # status, path_sct = commands.getstatusoutput('echo $SCT_DIR') # Check input parameters parser = get_parser() arguments = parser.parse(sys.argv[1:]) fname_mt0 = arguments['-mt0'] fname_mt1 = arguments['-mt1'] remove_tmp_files = int(arguments['-r']) verbose = int(arguments['-v']) # Extract path/file/extension path_mt0, file_mt0, ext_mt0 = sct.extract_fname(fname_mt0) path_out, file_out, ext_out = '', file_out, ext_mt0 # create temporary folder path_tmp = sct.tmp_create() # Copying input data to tmp folder and convert to nii sct.printv('\nCopying input data to tmp folder and convert to nii...', verbose) from sct_convert import convert convert(fname_mt0, path_tmp + 'mt0.nii', type='float32') convert(fname_mt1, path_tmp + 'mt1.nii', type='float32') # go to tmp folder os.chdir(path_tmp) # compute MTR sct.printv('\nCompute MTR...', verbose) from msct_image import Image nii_mt1 = Image('mt1.nii') data_mt1 = nii_mt1.data data_mt0 = Image('mt0.nii').data data_mtr = 100 * (data_mt0 - data_mt1) / data_mt0 # save MTR file nii_mtr = nii_mt1 nii_mtr.data = data_mtr nii_mtr.setFileName('mtr.nii') nii_mtr.save() # sct.run(fsloutput+'fslmaths -dt double mt0.nii -sub mt1.nii -mul 100 -div mt0.nii -thr 0 -uthr 100 mtr.nii', verbose) # come back to parent folder os.chdir('..') # Generate output files sct.printv('\nGenerate output files...', verbose) sct.generate_output_file(path_tmp + 'mtr.nii', path_out + file_out + ext_out) # Remove temporary files if remove_tmp_files == 1: print('\nRemove temporary files...') sct.run('rm -rf ' + path_tmp) # to view results sct.printv('\nDone! To view results, type:', verbose) sct.printv( 'fslview ' + fname_mt0 + ' ' + fname_mt1 + ' ' + file_out + ' &\n', verbose, 'info')
def main(): # get default parameters step1 = Paramreg(step='1', type='seg', algo='slicereg', metric='MeanSquares', iter='10') step2 = Paramreg(step='2', type='im', algo='syn', metric='MI', iter='3') # step1 = Paramreg() paramreg = ParamregMultiStep([step1, step2]) # step1 = Paramreg_step(step='1', type='seg', algo='bsplinesyn', metric='MeanSquares', iter='10', shrink='1', smooth='0', gradStep='0.5') # step2 = Paramreg_step(step='2', type='im', algo='syn', metric='MI', iter='10', shrink='1', smooth='0', gradStep='0.5') # paramreg = ParamregMultiStep([step1, step2]) # Initialize the parser parser = Parser(__file__) parser.usage.set_description('Register anatomical image to the template.') parser.add_option(name="-i", type_value="file", description="Anatomical image.", mandatory=True, example="anat.nii.gz") parser.add_option(name="-s", type_value="file", description="Spinal cord segmentation.", mandatory=True, example="anat_seg.nii.gz") parser.add_option( name="-l", type_value="file", description= "Labels. See: http://sourceforge.net/p/spinalcordtoolbox/wiki/create_labels/", mandatory=True, default_value='', example="anat_labels.nii.gz") parser.add_option(name="-t", type_value="folder", description="Path to MNI-Poly-AMU template.", mandatory=False, default_value=param.path_template) parser.add_option( name="-p", type_value=[[':'], 'str'], description= """Parameters for registration (see sct_register_multimodal). Default:\n--\nstep=1\ntype=""" + paramreg.steps['1'].type + """\nalgo=""" + paramreg.steps['1'].algo + """\nmetric=""" + paramreg.steps['1'].metric + """\npoly=""" + paramreg.steps['1'].poly + """\n--\nstep=2\ntype=""" + paramreg.steps['2'].type + """\nalgo=""" + paramreg.steps['2'].algo + """\nmetric=""" + paramreg.steps['2'].metric + """\niter=""" + paramreg.steps['2'].iter + """\nshrink=""" + paramreg.steps['2'].shrink + """\nsmooth=""" + paramreg.steps['2'].smooth + """\ngradStep=""" + paramreg.steps['2'].gradStep + """\n--""", mandatory=False, example= "step=2,type=seg,algo=bsplinesyn,metric=MeanSquares,iter=5,shrink=2:step=3,type=im,algo=syn,metric=MI,iter=5,shrink=1,gradStep=0.3" ) parser.add_option(name="-r", type_value="multiple_choice", description="""Remove temporary files.""", mandatory=False, default_value='1', example=['0', '1']) parser.add_option( name="-v", type_value="multiple_choice", description="""Verbose. 0: nothing. 1: basic. 2: extended.""", mandatory=False, default_value=param.verbose, example=['0', '1', '2']) if param.debug: print '\n*** WARNING: DEBUG MODE ON ***\n' fname_data = '/Users/julien/data/temp/sct_example_data/t2/t2.nii.gz' fname_landmarks = '/Users/julien/data/temp/sct_example_data/t2/labels.nii.gz' fname_seg = '/Users/julien/data/temp/sct_example_data/t2/t2_seg.nii.gz' path_template = param.path_template remove_temp_files = 0 verbose = 2 # speed = 'superfast' #param_reg = '2,BSplineSyN,0.6,MeanSquares' else: arguments = parser.parse(sys.argv[1:]) # get arguments fname_data = arguments['-i'] fname_seg = arguments['-s'] fname_landmarks = arguments['-l'] path_template = arguments['-t'] remove_temp_files = int(arguments['-r']) verbose = int(arguments['-v']) if '-p' in arguments: paramreg_user = arguments['-p'] # update registration parameters for paramStep in paramreg_user: paramreg.addStep(paramStep) # initialize other parameters file_template = param.file_template file_template_label = param.file_template_label file_template_seg = param.file_template_seg output_type = param.output_type zsubsample = param.zsubsample # smoothing_sigma = param.smoothing_sigma # start timer start_time = time.time() # get absolute path - TO DO: remove! NEVER USE ABSOLUTE PATH... path_template = os.path.abspath(path_template) # get fname of the template + template objects fname_template = sct.slash_at_the_end(path_template, 1) + file_template fname_template_label = sct.slash_at_the_end(path_template, 1) + file_template_label fname_template_seg = sct.slash_at_the_end(path_template, 1) + file_template_seg # check file existence sct.printv('\nCheck template files...') sct.check_file_exist(fname_template, verbose) sct.check_file_exist(fname_template_label, verbose) sct.check_file_exist(fname_template_seg, verbose) # print arguments sct.printv('\nCheck parameters:', verbose) sct.printv('.. Data: ' + fname_data, verbose) sct.printv('.. Landmarks: ' + fname_landmarks, verbose) sct.printv('.. Segmentation: ' + fname_seg, verbose) sct.printv('.. Path template: ' + path_template, verbose) sct.printv('.. Output type: ' + str(output_type), verbose) sct.printv('.. Remove temp files: ' + str(remove_temp_files), verbose) sct.printv('\nParameters for registration:') for pStep in range(1, len(paramreg.steps) + 1): sct.printv('Step #' + paramreg.steps[str(pStep)].step, verbose) sct.printv('.. Type #' + paramreg.steps[str(pStep)].type, verbose) sct.printv( '.. Algorithm................ ' + paramreg.steps[str(pStep)].algo, verbose) sct.printv( '.. Metric................... ' + paramreg.steps[str(pStep)].metric, verbose) sct.printv( '.. Number of iterations..... ' + paramreg.steps[str(pStep)].iter, verbose) sct.printv( '.. Shrink factor............ ' + paramreg.steps[str(pStep)].shrink, verbose) sct.printv( '.. Smoothing factor......... ' + paramreg.steps[str(pStep)].smooth, verbose) sct.printv( '.. Gradient step............ ' + paramreg.steps[str(pStep)].gradStep, verbose) sct.printv( '.. Degree of polynomial..... ' + paramreg.steps[str(pStep)].poly, verbose) path_data, file_data, ext_data = sct.extract_fname(fname_data) sct.printv('\nCheck input labels...') # check if label image contains coherent labels image_label = Image(fname_landmarks) # -> all labels must be different labels = image_label.getNonZeroCoordinates(sorting='value') hasDifferentLabels = True for lab in labels: for otherlabel in labels: if lab != otherlabel and lab.hasEqualValue(otherlabel): hasDifferentLabels = False break if not hasDifferentLabels: sct.printv( 'ERROR: Wrong landmarks input. All labels must be different.', verbose, 'error') # all labels must be available in tempalte image_label_template = Image(fname_template_label) labels_template = image_label_template.getNonZeroCoordinates( sorting='value') if labels[-1].value > labels_template[-1].value: sct.printv( 'ERROR: Wrong landmarks input. Labels must have correspondance in tempalte space. \nLabel max ' 'provided: ' + str(labels[-1].value) + '\nLabel max from template: ' + str(labels_template[-1].value), verbose, 'error') # 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) # copy files to temporary folder sct.printv('\nCopy files...', verbose) sct.run('isct_c3d ' + fname_data + ' -o ' + path_tmp + '/data.nii') sct.run('isct_c3d ' + fname_landmarks + ' -o ' + path_tmp + '/landmarks.nii.gz') sct.run('isct_c3d ' + fname_seg + ' -o ' + path_tmp + '/segmentation.nii.gz') sct.run('isct_c3d ' + fname_template + ' -o ' + path_tmp + '/template.nii') sct.run('isct_c3d ' + fname_template_label + ' -o ' + path_tmp + '/template_labels.nii.gz') sct.run('isct_c3d ' + fname_template_seg + ' -o ' + path_tmp + '/template_seg.nii.gz') # go to tmp folder os.chdir(path_tmp) # resample data to 1mm isotropic sct.printv('\nResample data to 1mm isotropic...', verbose) sct.run( 'isct_c3d data.nii -resample-mm 1.0x1.0x1.0mm -interpolation Linear -o datar.nii' ) sct.run( 'isct_c3d segmentation.nii.gz -resample-mm 1.0x1.0x1.0mm -interpolation NearestNeighbor -o segmentationr.nii.gz' ) # N.B. resampling of labels is more complicated, because they are single-point labels, therefore resampling with neighrest neighbour can make them disappear. Therefore a more clever approach is required. resample_labels('landmarks.nii.gz', 'datar.nii', 'landmarksr.nii.gz') # # TODO # sct.run('sct_label_utils -i datar.nii -t create -x 124,186,19,2:129,98,23,8 -o landmarksr.nii.gz') # Change orientation of input images to RPI sct.printv('\nChange orientation of input images to RPI...', verbose) set_orientation('datar.nii', 'RPI', 'data_rpi.nii') set_orientation('landmarksr.nii.gz', 'RPI', 'landmarks_rpi.nii.gz') set_orientation('segmentationr.nii.gz', 'RPI', 'segmentation_rpi.nii.gz') # # Change orientation of input images to RPI # sct.printv('\nChange orientation of input images to RPI...', verbose) # set_orientation('data.nii', 'RPI', 'data_rpi.nii') # set_orientation('landmarks.nii.gz', 'RPI', 'landmarks_rpi.nii.gz') # set_orientation('segmentation.nii.gz', 'RPI', 'segmentation_rpi.nii.gz') # get landmarks in native space # crop segmentation # output: segmentation_rpi_crop.nii.gz sct.run( 'sct_crop_image -i segmentation_rpi.nii.gz -o segmentation_rpi_crop.nii.gz -dim 2 -bzmax' ) # straighten segmentation sct.printv('\nStraighten the spinal cord using centerline/segmentation...', verbose) sct.run( 'sct_straighten_spinalcord -i segmentation_rpi_crop.nii.gz -c segmentation_rpi_crop.nii.gz -r 0 -v ' + str(verbose), verbose) # re-define warping field using non-cropped space (to avoid issue #367) sct.run( 'sct_concat_transfo -w warp_straight2curve.nii.gz -d data_rpi.nii -o warp_straight2curve.nii.gz' ) # Label preparation: # -------------------------------------------------------------------------------- # Remove unused label on template. Keep only label present in the input label image sct.printv( '\nRemove unused label on template. Keep only label present in the input label image...', verbose) sct.run( 'sct_label_utils -t remove -i template_labels.nii.gz -o template_label.nii.gz -r landmarks_rpi.nii.gz' ) # Make sure landmarks are INT sct.printv('\nConvert landmarks to INT...', verbose) sct.run( 'isct_c3d template_label.nii.gz -type int -o template_label.nii.gz', verbose) # Create a cross for the template labels - 5 mm sct.printv('\nCreate a 5 mm cross for the template labels...', verbose) sct.run( 'sct_label_utils -t cross -i template_label.nii.gz -o template_label_cross.nii.gz -c 5' ) # Create a cross for the input labels and dilate for straightening preparation - 5 mm sct.printv( '\nCreate a 5mm cross for the input labels and dilate for straightening preparation...', verbose) sct.run( 'sct_label_utils -t cross -i landmarks_rpi.nii.gz -o landmarks_rpi_cross3x3.nii.gz -c 5 -d' ) # Apply straightening to labels sct.printv('\nApply straightening to labels...', verbose) sct.run( 'sct_apply_transfo -i landmarks_rpi_cross3x3.nii.gz -o landmarks_rpi_cross3x3_straight.nii.gz -d segmentation_rpi_crop_straight.nii.gz -w warp_curve2straight.nii.gz -x nn' ) # Convert landmarks from FLOAT32 to INT sct.printv('\nConvert landmarks from FLOAT32 to INT...', verbose) sct.run( 'isct_c3d landmarks_rpi_cross3x3_straight.nii.gz -type int -o landmarks_rpi_cross3x3_straight.nii.gz' ) # Remove labels that do not correspond with each others. sct.printv('\nRemove labels that do not correspond with each others.', verbose) sct.run( 'sct_label_utils -t remove-symm -i landmarks_rpi_cross3x3_straight.nii.gz -o landmarks_rpi_cross3x3_straight.nii.gz,template_label_cross.nii.gz -r template_label_cross.nii.gz' ) # Estimate affine transfo: straight --> template (landmark-based)' sct.printv( '\nEstimate affine transfo: straight anat --> template (landmark-based)...', verbose) # converting landmarks straight and curved to physical coordinates image_straight = Image('landmarks_rpi_cross3x3_straight.nii.gz') landmark_straight = image_straight.getNonZeroCoordinates(sorting='value') image_template = Image('template_label_cross.nii.gz') landmark_template = image_template.getNonZeroCoordinates(sorting='value') # Reorganize landmarks points_fixed, points_moving = [], [] landmark_straight_mean = [] for coord in landmark_straight: if coord.value not in [c.value for c in landmark_straight_mean]: temp_landmark = coord temp_number = 1 for other_coord in landmark_straight: if coord.hasEqualValue(other_coord) and coord != other_coord: temp_landmark += other_coord temp_number += 1 landmark_straight_mean.append(temp_landmark / temp_number) for coord in landmark_straight_mean: point_straight = image_straight.transfo_pix2phys( [[coord.x, coord.y, coord.z]]) points_moving.append( [point_straight[0][0], point_straight[0][1], point_straight[0][2]]) for coord in landmark_template: point_template = image_template.transfo_pix2phys( [[coord.x, coord.y, coord.z]]) points_fixed.append( [point_template[0][0], point_template[0][1], point_template[0][2]]) # Register curved landmarks on straight landmarks based on python implementation sct.printv( '\nComputing rigid transformation (algo=translation-scaling-z) ...', verbose) import msct_register_landmarks (rotation_matrix, translation_array, points_moving_reg, points_moving_barycenter) = \ msct_register_landmarks.getRigidTransformFromLandmarks( points_fixed, points_moving, constraints='translation-scaling-z', show=False) # writing rigid transformation file text_file = open("straight2templateAffine.txt", "w") text_file.write("#Insight Transform File V1.0\n") text_file.write("#Transform 0\n") text_file.write( "Transform: FixedCenterOfRotationAffineTransform_double_3_3\n") text_file.write( "Parameters: %.9f %.9f %.9f %.9f %.9f %.9f %.9f %.9f %.9f %.9f %.9f %.9f\n" % (1.0 / rotation_matrix[0, 0], rotation_matrix[0, 1], rotation_matrix[0, 2], rotation_matrix[1, 0], 1.0 / rotation_matrix[1, 1], rotation_matrix[1, 2], rotation_matrix[2, 0], rotation_matrix[2, 1], 1.0 / rotation_matrix[2, 2], translation_array[0, 0], translation_array[0, 1], -translation_array[0, 2])) text_file.write("FixedParameters: %.9f %.9f %.9f\n" % (points_moving_barycenter[0], points_moving_barycenter[1], points_moving_barycenter[2])) text_file.close() # Apply affine transformation: straight --> template sct.printv('\nApply affine transformation: straight --> template...', verbose) sct.run( 'sct_concat_transfo -w warp_curve2straight.nii.gz,straight2templateAffine.txt -d template.nii -o warp_curve2straightAffine.nii.gz' ) sct.run( 'sct_apply_transfo -i data_rpi.nii -o data_rpi_straight2templateAffine.nii -d template.nii -w warp_curve2straightAffine.nii.gz' ) sct.run( 'sct_apply_transfo -i segmentation_rpi.nii.gz -o segmentation_rpi_straight2templateAffine.nii.gz -d template.nii -w warp_curve2straightAffine.nii.gz -x linear' ) # threshold to 0.5 nii = Image('segmentation_rpi_straight2templateAffine.nii.gz') data = nii.data data[data < 0.5] = 0 nii.data = data nii.setFileName('segmentation_rpi_straight2templateAffine_th.nii.gz') nii.save() # find min-max of anat2template (for subsequent cropping) zmin_template, zmax_template = find_zmin_zmax( 'segmentation_rpi_straight2templateAffine_th.nii.gz') # crop template in z-direction (for faster processing) sct.printv('\nCrop data in template space (for faster processing)...', verbose) sct.run( 'sct_crop_image -i template.nii -o template_crop.nii -dim 2 -start ' + str(zmin_template) + ' -end ' + str(zmax_template)) sct.run( 'sct_crop_image -i template_seg.nii.gz -o template_seg_crop.nii.gz -dim 2 -start ' + str(zmin_template) + ' -end ' + str(zmax_template)) sct.run( 'sct_crop_image -i data_rpi_straight2templateAffine.nii -o data_rpi_straight2templateAffine_crop.nii -dim 2 -start ' + str(zmin_template) + ' -end ' + str(zmax_template)) sct.run( 'sct_crop_image -i segmentation_rpi_straight2templateAffine.nii.gz -o segmentation_rpi_straight2templateAffine_crop.nii.gz -dim 2 -start ' + str(zmin_template) + ' -end ' + str(zmax_template)) # sub-sample in z-direction sct.printv('\nSub-sample in z-direction (for faster processing)...', verbose) sct.run( 'sct_resample -i template_crop.nii -o template_crop_r.nii -f 1x1x' + zsubsample, verbose) sct.run( 'sct_resample -i template_seg_crop.nii.gz -o template_seg_crop_r.nii.gz -f 1x1x' + zsubsample, verbose) sct.run( 'sct_resample -i data_rpi_straight2templateAffine_crop.nii -o data_rpi_straight2templateAffine_crop_r.nii -f 1x1x' + zsubsample, verbose) sct.run( 'sct_resample -i segmentation_rpi_straight2templateAffine_crop.nii.gz -o segmentation_rpi_straight2templateAffine_crop_r.nii.gz -f 1x1x' + zsubsample, verbose) # Registration straight spinal cord to template sct.printv('\nRegister straight spinal cord to template...', verbose) # loop across registration steps warp_forward = [] warp_inverse = [] for i_step in range(1, len(paramreg.steps) + 1): sct.printv( '\nEstimate transformation for step #' + str(i_step) + '...', verbose) # identify which is the src and dest if paramreg.steps[str(i_step)].type == 'im': src = 'data_rpi_straight2templateAffine_crop_r.nii' dest = 'template_crop_r.nii' interp_step = 'linear' elif paramreg.steps[str(i_step)].type == 'seg': src = 'segmentation_rpi_straight2templateAffine_crop_r.nii.gz' dest = 'template_seg_crop_r.nii.gz' interp_step = 'nn' else: sct.printv('ERROR: Wrong image type.', 1, 'error') # if step>1, apply warp_forward_concat to the src image to be used if i_step > 1: # sct.run('sct_apply_transfo -i '+src+' -d '+dest+' -w '+','.join(warp_forward)+' -o '+sct.add_suffix(src, '_reg')+' -x '+interp_step, verbose) sct.run( 'sct_apply_transfo -i ' + src + ' -d ' + dest + ' -w ' + ','.join(warp_forward) + ' -o ' + sct.add_suffix(src, '_reg') + ' -x ' + interp_step, verbose) src = sct.add_suffix(src, '_reg') # register src --> dest warp_forward_out, warp_inverse_out = register(src, dest, paramreg, param, str(i_step)) warp_forward.append(warp_forward_out) warp_inverse.append(warp_inverse_out) # Concatenate transformations: sct.printv('\nConcatenate transformations: anat --> template...', verbose) sct.run( 'sct_concat_transfo -w warp_curve2straightAffine.nii.gz,' + ','.join(warp_forward) + ' -d template.nii -o warp_anat2template.nii.gz', verbose) # sct.run('sct_concat_transfo -w warp_curve2straight.nii.gz,straight2templateAffine.txt,'+','.join(warp_forward)+' -d template.nii -o warp_anat2template.nii.gz', verbose) warp_inverse.reverse() sct.run( 'sct_concat_transfo -w ' + ','.join(warp_inverse) + ',-straight2templateAffine.txt,warp_straight2curve.nii.gz -d data.nii -o warp_template2anat.nii.gz', verbose) # Apply warping fields to anat and template if output_type == 1: sct.run( 'sct_apply_transfo -i template.nii -o template2anat.nii.gz -d data.nii -w warp_template2anat.nii.gz -c 1', verbose) sct.run( 'sct_apply_transfo -i data.nii -o anat2template.nii.gz -d template.nii -w warp_anat2template.nii.gz -c 1', verbose) # come back to parent folder os.chdir('..') # Generate output files sct.printv('\nGenerate output files...', verbose) sct.generate_output_file(path_tmp + '/warp_template2anat.nii.gz', 'warp_template2anat.nii.gz', verbose) sct.generate_output_file(path_tmp + '/warp_anat2template.nii.gz', 'warp_anat2template.nii.gz', verbose) if output_type == 1: sct.generate_output_file(path_tmp + '/template2anat.nii.gz', 'template2anat' + ext_data, verbose) sct.generate_output_file(path_tmp + '/anat2template.nii.gz', 'anat2template' + ext_data, verbose) # Delete temporary files if remove_temp_files: sct.printv('\nDelete temporary files...', verbose) sct.run('rm -rf ' + path_tmp) # 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) sct.printv('fslview ' + fname_data + ' template2anat -b 0,4000 &', verbose, 'info') sct.printv('fslview ' + fname_template + ' -b 0,5000 anat2template &\n', verbose, 'info')
def compute_texture(self): offset = int(self.param_glcm.distance) printv('\nCompute texture metrics...', self.param.verbose, 'normal') # open image and re-orient it to RPI if needed im_tmp = Image(self.param.fname_im) if self.orientation_im != self.orientation_extraction: im_tmp = set_orientation(im_tmp, self.orientation_extraction) dct_metric = {} for m in self.metric_lst: im_2save = im_tmp.copy() im_2save.changeType(type='float64') im_2save.data *= 0 dct_metric[m] = im_2save # dct_metric[m] = Image(self.fname_metric_lst[m]) timer = Timer(number_of_iteration=len(self.dct_im_seg['im'])) timer.start() for im_z, seg_z, zz in zip(self.dct_im_seg['im'], self.dct_im_seg['seg'], range(len(self.dct_im_seg['im']))): for xx in range(im_z.shape[0]): for yy in range(im_z.shape[1]): if not seg_z[xx, yy]: continue if xx < offset or yy < offset: continue if xx > (im_z.shape[0] - offset - 1) or yy > (im_z.shape[1] - offset - 1): continue # to check if the whole glcm_window is in the axial_slice if False in np.unique(seg_z[xx - offset:xx + offset + 1, yy - offset:yy + offset + 1]): continue # to check if the whole glcm_window is in the mask of the axial_slice glcm_window = im_z[xx - offset:xx + offset + 1, yy - offset:yy + offset + 1] glcm_window = glcm_window.astype(np.uint8) dct_glcm = {} for a in self.param_glcm.angle.split( ',' ): # compute the GLCM for self.param_glcm.distance and for each self.param_glcm.angle dct_glcm[a] = greycomatrix( glcm_window, [self.param_glcm.distance], [radians(int(a))], symmetric=self.param_glcm.symmetric, normed=self.param_glcm.normed) for m in self.metric_lst: # compute the GLCM property (m.split('_')[0]) of the voxel xx,yy,zz dct_metric[m].data[xx, yy, zz] = greycoprops( dct_glcm[m.split('_')[2]], m.split('_')[0])[0][0] timer.add_iteration() timer.stop() for m in self.metric_lst: fname_out = add_suffix( ''.join(extract_fname(self.param.fname_im)[1:]), '_' + m) dct_metric[m].setFileName(fname_out) dct_metric[m].save() self.fname_metric_lst[m] = fname_out
import sct_utils as sct from msct_image import Image # parameters fname_wm = '/Users/julien/Dropbox/Public/sct/PAM50/template/PAM50_wm.nii.gz' fname_gm = '/Users/julien/Dropbox/Public/sct/PAM50/template/PAM50_gm.nii.gz' fname_cord = '/Users/julien/data/sct_dev/PAM50/template/PAM50_cord.nii.gz' # create temporary folder path_tmp = sct.tmp_create() # go to temp folder os.chdir(path_tmp) # open volumes im_wm = Image(fname_wm) data_wm = im_wm.data im_gm = Image(fname_gm) data_gm = im_gm.data im_cord = Image(fname_cord) data_cord = im_cord.data dim = im_cord.dim # sum wm/gm data_wmgm = data_wm + data_gm # get min/max z slices from wm/gm zsum = np.sum(np.sum(data_wmgm, 0), 0) zmin_wm = np.min(np.nonzero(zsum)) zmax_wm = np.max(np.nonzero(zsum))
def main(): # initialization fname_mask = '' # Get parser info parser = get_parser() arguments = parser.parse(sys.argv[1:]) fname_data = arguments['-i'] fname_mask = arguments['-m'] vert_label_fname = arguments["-vertfile"] vert_levels = arguments["-vert"] slices_of_interest = arguments["-z"] index_vol = arguments['-vol'] method = arguments["-method"] verbose = int(arguments['-v']) # Check if data are in RPI input_im = Image(fname_data) input_orient = get_orientation(input_im) # If orientation is not RPI, change to RPI if input_orient != 'RPI': sct.printv( '\nCreate temporary folder to change the orientation of the NIFTI files into RPI...', verbose) path_tmp = sct.tmp_create() # change orientation and load data sct.printv('\nChange input image orientation and load it...', verbose) input_im_rpi = orientation(input_im, ori='RPI', set=True, fname_out=path_tmp + 'input_RPI.nii') input_data = input_im_rpi.data # Do the same for the mask sct.printv('\nChange mask orientation and load it...', verbose) mask_im_rpi = orientation(Image(fname_mask), ori='RPI', set=True, fname_out=path_tmp + 'mask_RPI.nii') mask_data = mask_im_rpi.data # Do the same for vertebral labeling if present if vert_levels != 'None': sct.printv( '\nChange vertebral labeling file orientation and load it...', verbose) vert_label_im_rpi = orientation(Image(vert_label_fname), ori='RPI', set=True, fname_out=path_tmp + 'vert_labeling_RPI.nii') vert_labeling_data = vert_label_im_rpi.data # Remove the temporary folder used to change the NIFTI files orientation into RPI sct.printv('\nRemove the temporary folder...', verbose) shutil.rmtree(path_tmp, True) else: # Load data sct.printv('\nLoad data...', verbose) input_data = input_im.data mask_data = Image(fname_mask).data if vert_levels != 'None': vert_labeling_data = Image(vert_label_fname).data sct.printv('\tDone.', verbose) # Get slices corresponding to vertebral levels if vert_levels != 'None': from sct_extract_metric import get_slices_matching_with_vertebral_levels slices_of_interest, actual_vert_levels, warning_vert_levels = get_slices_matching_with_vertebral_levels( mask_data, vert_levels, vert_labeling_data, verbose) # Remove slices that were not selected if slices_of_interest == 'None': slices_of_interest = '0:' + str(mask_data.shape[2] - 1) slices_boundary = slices_of_interest.split(':') slices_of_interest_list = range(int(slices_boundary[0]), int(slices_boundary[1]) + 1) # Crop input_data = input_data[:, :, slices_of_interest_list, :] mask_data = mask_data[:, :, slices_of_interest_list] # if user selected all slices (-vol -1), then assign index_vol if index_vol[0] == -1: index_vol = range(0, input_data.shape[3], 1) # Get signal and noise indexes_roi = np.where(mask_data == 1) if method == 'mult': # get voxels in ROI to obtain a (x*y*z)*t 2D matrix input_data_in_roi = input_data[indexes_roi] # compute signal and STD across by averaging across time signal = np.mean(input_data_in_roi[:, index_vol]) std_input_temporal = np.std(input_data_in_roi[:, index_vol], 1) noise = np.mean(std_input_temporal) elif method == 'diff': # if user did not select two volumes, then exit with error if not len(index_vol) == 2: sct.printv( 'ERROR: ' + str(len(index_vol)) + ' volumes were specified. Method "diff" should be used with exactly two volumes.', 1, 'error') data_1 = input_data[:, :, :, index_vol[0]] data_2 = input_data[:, :, :, index_vol[1]] # compute voxel-average of voxelwise sum signal = np.mean(np.add(data_1[indexes_roi], data_2[indexes_roi])) # compute voxel-STD of voxelwise substraction, multiplied by sqrt(2) as described in equation 7 of Dietrich et al. noise = np.std(np.subtract(data_1[indexes_roi], data_2[indexes_roi])) * np.sqrt(2) # compute SNR SNR = signal / noise # Display result sct.printv('\nSNR_' + method + ' = ' + str(SNR) + '\n', type='info')
def register_landmarks(fname_src, fname_dest, dof, fname_affine='affine.txt', verbose=1, path_qc=None): """ Register two NIFTI volumes containing landmarks :param fname_src: fname of source landmarks :param fname_dest: fname of destination landmarks :param dof: degree of freedom. Separate with "_". Example: Tx_Ty_Tz_Rx_Ry_Sz :param fname_affine: output affine transformation :param verbose: 0, 1, 2 :return: """ from msct_image import Image # open src label im_src = Image(fname_src) # coord_src = im_src.getNonZeroCoordinates(sorting='value') # landmarks are sorted by value coord_src = im_src.getCoordinatesAveragedByValue( ) # landmarks are sorted by value # open dest labels im_dest = Image(fname_dest) # coord_dest = im_dest.getNonZeroCoordinates(sorting='value') coord_dest = im_dest.getCoordinatesAveragedByValue() # Reorganize landmarks points_src, points_dest = [], [] for coord in coord_src: point_src = im_src.transfo_pix2phys([[coord.x, coord.y, coord.z]]) # convert NIFTI to ITK world coordinate # points_src.append([point_src[0][0], point_src[0][1], point_src[0][2]]) points_src.append( [-point_src[0][0], -point_src[0][1], point_src[0][2]]) for coord in coord_dest: point_dest = im_dest.transfo_pix2phys([[coord.x, coord.y, coord.z]]) # convert NIFTI to ITK world coordinate # points_dest.append([point_dest[0][0], point_dest[0][1], point_dest[0][2]]) points_dest.append( [-point_dest[0][0], -point_dest[0][1], point_dest[0][2]]) # display sct.printv('Labels src: ' + str(points_src), verbose) sct.printv('Labels dest: ' + str(points_dest), verbose) sct.printv('Degrees of freedom (dof): ' + dof, verbose) if len(coord_src) != len(coord_dest): raise Exception( 'Error: number of source and destination landmarks are not the same, so landmarks cannot be paired.' ) # estimate transformation # N.B. points_src and points_dest are inverted below, because ITK uses inverted transformation matrices, i.e., src->dest is defined in dest instead of src. # (rotation_matrix, translation_array, points_moving_reg, points_moving_barycenter) = getRigidTransformFromLandmarks(points_dest, points_src, constraints=dof, verbose=verbose, path_qc=path_qc) (rotation_matrix, translation_array, points_moving_reg, points_moving_barycenter) = getRigidTransformFromLandmarks( points_src, points_dest, constraints=dof, verbose=verbose, path_qc=path_qc) # writing rigid transformation file # N.B. x and y dimensions have a negative sign to ensure compatibility between Python and ITK transfo text_file = open(fname_affine, 'w') text_file.write("#Insight Transform File V1.0\n") text_file.write("#Transform 0\n") text_file.write("Transform: AffineTransform_double_3_3\n") text_file.write( "Parameters: %.9f %.9f %.9f %.9f %.9f %.9f %.9f %.9f %.9f %.9f %.9f %.9f\n" % (rotation_matrix[0, 0], rotation_matrix[0, 1], rotation_matrix[0, 2], rotation_matrix[1, 0], rotation_matrix[1, 1], rotation_matrix[1, 2], rotation_matrix[2, 0], rotation_matrix[2, 1], rotation_matrix[2, 2], translation_array[0, 0], translation_array[0, 1], translation_array[0, 2])) text_file.write("FixedParameters: %.9f %.9f %.9f\n" % (points_moving_barycenter[0], points_moving_barycenter[1], points_moving_barycenter[2])) text_file.close()
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
# path_tmp = tmp_create() # tmp_copy_nifti(input_file, path_tmp, 'raw.nii') # run('cp '+warping_fields_filename[0]+' '+path_tmp) # chdir(path_tmp) run('mkdir images') run('mkdir niftis') while True: try: warping_fields[0].num_of_frames = number_of_frames image_output_iter, iteration = warping_fields[0].next() image_output_iter.save() filename_warp = image_output_iter.path + image_output_iter.file_name + image_output_iter.ext filename_output = "niftis/tmp.warped_image_" + str( iteration - 1) + image_output_iter.ext run("sct_apply_transfo -i " + input_file + " -d " + reference_image + " -w " + filename_warp + " -o " + filename_output) result = Image(filename_output) result.change_orientation() toimage(result.data[int(result.data.shape[0] / 2)].squeeze(), cmin=0.0).save('images/' + extract_fname(filename_output)[1] + '.jpg') filenames_output.append(filename_output) except ValueError: printv('\nError during warping field generation...', 1, 'error') except StopIteration: printv('\nFinished iterations.') break
def crop_with_gui(self): import matplotlib.pyplot as plt import matplotlib.image as mpimg # Initialization fname_data = self.input_filename suffix_out = '_crop' remove_temp_files = self.rm_tmp_files verbose = self.verbose # Check file existence sct.printv('\nCheck file existence...', verbose) sct.check_file_exist(fname_data, verbose) # Get dimensions of data sct.printv('\nGet dimensions of data...', verbose) nx, ny, nz, nt, px, py, pz, pt = Image(fname_data).dim sct.printv('.. ' + str(nx) + ' x ' + str(ny) + ' x ' + str(nz), verbose) # check if 4D data if not nt == 1: sct.printv( '\nERROR in ' + os.path.basename(__file__) + ': Data should be 3D.\n', 1, 'error') sys.exit(2) # sct.printv(arguments) sct.printv('\nCheck parameters:') sct.printv(' data ................... ' + fname_data) # Extract path/file/extension path_data, file_data, ext_data = sct.extract_fname(fname_data) path_out, file_out, ext_out = '', file_data + suffix_out, ext_data path_tmp = sct.tmp_create() + "/" # copy files into tmp folder from sct_convert import convert sct.printv('\nCopying input data to tmp folder and convert to nii...', verbose) convert(fname_data, os.path.join(path_tmp, "data.nii")) # go to tmp folder curdir = os.getcwd() os.chdir(path_tmp) # change orientation sct.printv('\nChange orientation to RPI...', verbose) sct.run([ 'sct_image', '-i', 'data.nii', '-setorient', 'RPI', '-o', 'data_rpi.nii' ]) # get image of medial slab sct.printv('\nGet image of medial slab...', verbose) image_array = nibabel.load('data_rpi.nii').get_data() nx, ny, nz = image_array.shape scipy.misc.imsave('image.jpg', image_array[math.floor(nx / 2), :, :]) # Display the image sct.printv('\nDisplay image and get cropping region...', verbose) fig = plt.figure() # fig = plt.gcf() # ax = plt.gca() ax = fig.add_subplot(111) img = mpimg.imread("image.jpg") implot = ax.imshow(img.T) implot.set_cmap('gray') plt.gca().invert_yaxis() # mouse callback ax.set_title( 'Left click on the top and bottom of your cropping field.\n Right click to remove last point.\n Close window when your done.' ) line, = ax.plot([], [], 'ro') # empty line cropping_coordinates = LineBuilder(line) plt.show() # disconnect callback # fig.canvas.mpl_disconnect(line) # check if user clicked two times if len(cropping_coordinates.xs) != 2: sct.printv( '\nERROR: You have to select two points. Exit program.\n', 1, 'error') sys.exit(2) # convert coordinates to integer zcrop = [int(i) for i in cropping_coordinates.ys] # sort coordinates zcrop.sort() # crop image sct.printv('\nCrop image...', verbose) nii = Image('data_rpi.nii') data_crop = nii.data[:, :, zcrop[0]:zcrop[1]] nii.data = data_crop nii.setFileName('data_rpi_crop.nii') nii.save() # come back os.chdir(curdir) sct.printv('\nGenerate output files...', verbose) sct.generate_output_file(os.path.join(path_tmp, "data_rpi_crop.nii"), os.path.join(path_out, file_out + ext_out)) # Remove temporary files if remove_temp_files == 1: sct.printv('\nRemove temporary files...') sct.rmtree(path_tmp) sct.display_viewer_syntax( files=[os.path.join(path_out, file_out + ext_out)])