def execute(self): """ This method executes the symmetry detection :return: returns the symmetry data """ img = Image(self.input_image) raw_orientation = img.change_orientation() data = np.squeeze(img.data) dim = data.shape section_length = dim[1]/self.nb_sections result = np.zeros(dim) for i in range(0, self.nb_sections): if (i+1)*section_length > dim[1]: y_length = (i+1)*section_length - ((i+1)*section_length - dim[1]) result[:, i*section_length:i*section_length + y_length, :] = symmetry_detector_right_left(data[:, i*section_length:i*section_length + y_length, :], cropped_xy=self.crop_xy) sym = symmetry_detector_right_left(data[:, i*section_length:(i+1)*section_length, :], cropped_xy=self.crop_xy) result[:, i*section_length:(i+1)*section_length, :] = sym result_image = Image(img) if len(result_image.data) == 4: result_image.data = result[:,:,:,np.newaxis] else: result_image.data = result result_image.change_orientation(raw_orientation) return result_image.data
def compute_dti(fname_in, fname_bvals, fname_bvecs, prefix): """ Compute DTI. :param fname_in: input 4d file. :param bvals: bvals txt file :param bvecs: bvecs txt file :param prefix: output prefix. Example: "dti_" :return: True/False """ # Open file. from msct_image import Image nii = Image(fname_in) data = nii.data print('data.shape (%d, %d, %d, %d)' % data.shape) # open bvecs/bvals from dipy.io import read_bvals_bvecs bvals, bvecs = read_bvals_bvecs(fname_bvals, fname_bvecs) from dipy.core.gradients import gradient_table gtab = gradient_table(bvals, bvecs) # # mask and crop the data. This is a quick way to avoid calculating Tensors on the background of the image. # from dipy.segment.mask import median_otsu # maskdata, mask = median_otsu(data, 3, 1, True, vol_idx=range(10, 50), dilate=2) # print('maskdata.shape (%d, %d, %d, %d)' % maskdata.shape) # fit tensor model import dipy.reconst.dti as dti tenmodel = dti.TensorModel(gtab) tenfit = tenmodel.fit(data) # Compute metrics printv('Computing metrics...', param.verbose) # FA from dipy.reconst.dti import fractional_anisotropy nii.data = fractional_anisotropy(tenfit.evals) nii.setFileName(prefix + 'FA.nii.gz') nii.save('float32') # MD from dipy.reconst.dti import mean_diffusivity nii.data = mean_diffusivity(tenfit.evals) nii.setFileName(prefix + 'MD.nii.gz') nii.save('float32') # RD from dipy.reconst.dti import radial_diffusivity nii.data = radial_diffusivity(tenfit.evals) nii.setFileName(prefix + 'RD.nii.gz') nii.save('float32') # AD from dipy.reconst.dti import axial_diffusivity nii.data = axial_diffusivity(tenfit.evals) nii.setFileName(prefix + 'AD.nii.gz') nii.save('float32') return True
def compute_dti(fname_in, fname_bvals, fname_bvecs, prefix): """ Compute DTI. :param fname_in: input 4d file. :param bvals: bvals txt file :param bvecs: bvecs txt file :param prefix: output prefix. Example: "dti_" :return: True/False """ # Open file. from msct_image import Image nii = Image(fname_in) data = nii.data print('data.shape (%d, %d, %d, %d)' % data.shape) # open bvecs/bvals from dipy.io import read_bvals_bvecs bvals, bvecs = read_bvals_bvecs(fname_bvals, fname_bvecs) from dipy.core.gradients import gradient_table gtab = gradient_table(bvals, bvecs) # # mask and crop the data. This is a quick way to avoid calculating Tensors on the background of the image. # from dipy.segment.mask import median_otsu # maskdata, mask = median_otsu(data, 3, 1, True, vol_idx=range(10, 50), dilate=2) # print('maskdata.shape (%d, %d, %d, %d)' % maskdata.shape) # fit tensor model import dipy.reconst.dti as dti tenmodel = dti.TensorModel(gtab) tenfit = tenmodel.fit(data) # Compute metrics printv('Computing metrics...', param.verbose) # FA from dipy.reconst.dti import fractional_anisotropy nii.data = fractional_anisotropy(tenfit.evals) nii.setFileName(prefix+'FA.nii.gz') nii.save('float32') # MD from dipy.reconst.dti import mean_diffusivity nii.data = mean_diffusivity(tenfit.evals) nii.setFileName(prefix+'MD.nii.gz') nii.save('float32') # RD from dipy.reconst.dti import radial_diffusivity nii.data = radial_diffusivity(tenfit.evals) nii.setFileName(prefix+'RD.nii.gz') nii.save('float32') # AD from dipy.reconst.dti import axial_diffusivity nii.data = axial_diffusivity(tenfit.evals) nii.setFileName(prefix+'AD.nii.gz') nii.save('float32') return True
def main(args=None): dim_list = ['x', 'y', 'z', 't'] if not args: args = sys.argv[1:] # Get parser info parser = get_parser() arguments = parser.parse(sys.argv[1:]) fname_in = arguments["-i"] fname_out = arguments["-o"] verbose = int(arguments['-v']) # Build fname_out if fname_out == '': path_in, file_in, ext_in = extract_fname(fname_in) fname_out = path_in + file_in + '_mean' + ext_in # Open file. nii = Image(fname_in) data = nii.data # run command if '-otsu' in arguments: param = arguments['-otsu'] data_out = otsu(data, param) elif '-otsu_adap' in arguments: param = arguments['-otsu_adap'] data_out = otsu_adap(data, param[0], param[1]) elif '-otsu_median' in arguments: param = arguments['-otsu_median'] data_out = otsu_median(data, param[0], param[1]) elif '-thr' in arguments: param = arguments['-thr'] data_out = threshold(data, param) elif '-percent' in arguments: param = arguments['-percent'] data_out = perc(data, param) elif '-mean' in arguments: dim = dim_list.index(arguments['-mean']) data_out = compute_mean(data, dim) elif '-std' in arguments: dim = dim_list.index(arguments['-std']) data_out = compute_std(data, dim) elif '-dilate' in arguments: data_out = dilate(data, arguments['-dilate']) elif '-erode' in arguments: data_out = erode(data, arguments['-dilate']) else: printv('No process applied.', 1, 'warning') return # Write output nii.data = data_out nii.setFileName(fname_out) nii.save() # display message printv('Created file:\n--> ' + fname_out + '\n', verbose, 'info')
def crop_from_mask_with_background(self): from numpy import asarray, einsum image_in = Image(self.input_filename) data_array = asarray(image_in.data) data_mask = asarray(Image(self.mask).data) assert data_array.shape == data_mask.shape # Element-wise matrix multiplication: new_data = None dim = len(data_array.shape) if dim == 3: new_data = einsum('ijk,ijk->ijk', data_mask, data_array) elif dim == 2: new_data = einsum('ij,ij->ij', data_mask, data_array) if self.background != 0: from sct_maths import get_data_or_scalar data_background = get_data_or_scalar(str(self.background), data_array) data_mask_inv = data_mask.max() - data_mask if dim == 3: data_background = einsum('ijk,ijk->ijk', data_mask_inv, data_background) elif dim == 2: data_background = einsum('ij,ij->ij', data_mask_inv, data_background) new_data += data_background # set image out image_in.setFileName(self.output_filename) image_in.data = new_data image_in.save()
def create_label_z(fname_seg, z, value): """ Create a label at coordinates x_center, y_center, z :param fname_seg: segmentation :param z: int :return: fname_label """ fname_label = 'labelz.nii.gz' nii = Image(fname_seg) orientation_origin = nii.change_orientation( 'RPI') # change orientation to RPI nx, ny, nz, nt, px, py, pz, pt = nii.dim # Get dimensions # find x and y coordinates of the centerline at z using center of mass from scipy.ndimage.measurements import center_of_mass x, y = center_of_mass(nii.data[:, :, z]) x, y = int(round(x)), int(round(y)) nii.data[:, :, :] = 0 nii.data[x, y, z] = value # dilate label to prevent it from disappearing due to nearestneighbor interpolation from sct_maths import dilate nii.data = dilate(nii.data, [3]) nii.setFileName(fname_label) nii.change_orientation( orientation_origin) # put back in original orientation nii.save() return fname_label
def main(args = None): dim_list = ['x', 'y', 'z', 't'] if not args: args = sys.argv[1:] # Get parser info parser = get_parser() arguments = parser.parse(sys.argv[1:]) fname_in = arguments["-i"] fname_out = arguments["-o"] verbose = int(arguments['-v']) # Build fname_out if fname_out == '': path_in, file_in, ext_in = extract_fname(fname_in) fname_out = path_in+file_in+'_mean'+ext_in # Open file. nii = Image(fname_in) data = nii.data # run command if '-otsu' in arguments: param = arguments['-otsu'] data_out = otsu(data, param) elif '-otsu_adap' in arguments: param = arguments['-otsu_adap'] data_out = otsu_adap(data, param[0], param[1]) elif '-otsu_median' in arguments: param = arguments['-otsu_median'] data_out = otsu_median(data, param[0], param[1]) elif '-thr' in arguments: param = arguments['-thr'] data_out = threshold(data, param) elif '-percent' in arguments: param = arguments['-percent'] data_out = perc(data, param) elif '-mean' in arguments: dim = dim_list.index(arguments['-mean']) data_out = compute_mean(data, dim) elif '-std' in arguments: dim = dim_list.index(arguments['-std']) data_out = compute_std(data, dim) elif '-dilate' in arguments: data_out = dilate(data, arguments['-dilate']) elif '-erode' in arguments: data_out = erode(data, arguments['-dilate']) else: printv('No process applied.', 1, 'warning') return # Write output nii.data = data_out nii.setFileName(fname_out) nii.save() # display message printv('Created file:\n--> '+fname_out+'\n', verbose, 'info')
def concat_data(fname_in, fname_out, dim): """ Concatenate data :param fname_in: list of file names. :param fname_out: :param dim: dimension: 0, 1, 2, 3. :return: none """ # create empty list list_data = [] # loop across files for i in range(len(fname_in)): # append data to list list_data.append(Image(fname_in[i]).data) # expand dimension of all elements in the list if necessary if dim > list_data[0].ndim - 1: list_data = [expand_dims(i, dim) for i in list_data] # concatenate try: data_concat = concatenate(list_data, axis=dim) except Exception as e: sct.printv( '\nERROR: Concatenation on line {}'.format( sys.exc_info()[-1].tb_lineno) + '\n' + str(e) + '\n', 1, 'error') # write file im = Image(fname_in[0]) im.data = data_concat im.setFileName(fname_out) im.save()
def concat_data(fname_in, fname_out, dim): """ Concatenate data :param fname_in: list of file names. :param fname_out: :param dim: dimension: 0, 1, 2, 3. :return: none """ # create empty list list_data = [] # loop across files for i in range(len(fname_in)): # append data to list list_data.append(Image(fname_in[i]).data) # expand dimension of all elements in the list if necessary if dim > list_data[0].ndim-1: list_data = [expand_dims(i, dim) for i in list_data] # concatenate try: data_concat = concatenate(list_data, axis=dim) except Exception as e: sct.printv('\nERROR: Concatenation on line {}'.format(sys.exc_info()[-1].tb_lineno)+'\n'+str(e)+'\n', 1, 'error') # write file im = Image(fname_in[0]) im.data = data_concat im.setFileName(fname_out) im.save()
def validation(self): name_ref_gm_seg = sct.extract_fname(self.ref_gm_seg) im_ref_gm_seg = Image('../' + self.ref_gm_seg) res_gm_seg_bin = Image('../' + self.res_names['gm_seg']) res_wm_seg_bin = Image('../' + self.res_names['wm_seg']) sct.run('cp ../' + self.ref_gm_seg + ' ./ref_gm_seg.nii.gz') im_ref_wm_seg = inverse_gmseg_to_wmseg(im_ref_gm_seg, Image('../' + self.sc_seg_fname), 'ref_gm_seg') im_ref_wm_seg.file_name = 'ref_wm_seg' im_ref_wm_seg.ext = '.nii.gz' im_ref_wm_seg.save() if self.param.res_type == 'prob': res_gm_seg_bin.data = np.asarray((res_gm_seg_bin.data >= 0.5).astype(int)) res_wm_seg_bin.data = np.asarray((res_wm_seg_bin.data >= 0.50001).astype(int)) res_gm_seg_bin.path = './' res_gm_seg_bin.file_name = 'res_gm_seg_bin' res_gm_seg_bin.ext = '.nii.gz' res_gm_seg_bin.save() res_wm_seg_bin.path = './' res_wm_seg_bin.file_name = 'res_wm_seg_bin' res_wm_seg_bin.ext = '.nii.gz' res_wm_seg_bin.save() try: status_gm, output_gm = sct.run('sct_dice_coefficient ref_gm_seg.nii.gz res_gm_seg_bin.nii.gz -2d-slices 2', error_exit='warning', raise_exception=True) except Exception: sct.run('c3d res_gm_seg_bin.nii.gz ref_gm_seg.nii.gz -reslice-identity -o ref_in_res_space_gm.nii.gz ') status_gm, output_gm = sct.run('sct_dice_coefficient ref_in_res_space_gm.nii.gz res_gm_seg_bin.nii.gz -2d-slices 2', error_exit='warning') try: status_wm, output_wm = sct.run('sct_dice_coefficient ref_wm_seg.nii.gz res_wm_seg_bin.nii.gz -2d-slices 2', error_exit='warning', raise_exception=True) except Exception: sct.run('c3d res_wm_seg_bin.nii.gz ref_wm_seg.nii.gz -reslice-identity -o ref_in_res_space_wm.nii.gz ') status_wm, output_wm = sct.run('sct_dice_coefficient ref_in_res_space_wm.nii.gz res_wm_seg_bin.nii.gz -2d-slices 2', error_exit='warning') dice_name = 'dice_' + self.param.res_type + '.txt' dice_fic = open('../' + dice_name, 'w') if self.param.res_type == 'prob': dice_fic.write('WARNING : the probabilistic segmentations were binarized with a threshold at 0.5 to compute the dice coefficient \n') dice_fic.write('\n--------------------------------------------------------------\nDice coefficient on the Gray Matter segmentation:\n') dice_fic.write(output_gm) dice_fic.write('\n\n--------------------------------------------------------------\nDice coefficient on the White Matter segmentation:\n') dice_fic.write(output_wm) dice_fic.close() # sct.run(' mv ./' + dice_name + ' ../') return dice_name
def get_minimum_path_nii(fname): from msct_image import Image data=Image(fname) vesselness_data = data.data raw_orient=data.change_orientation() data.data=get_minimum_path(data.data, invert=1) data.change_orientation(raw_orient) data.file_name += '_minimalpath' data.save()
def concat_data(fname_in_list, dim, pixdim=None): """ Concatenate data :param im_in_list: list of images. :param dim: dimension: 0, 1, 2, 3. :param pixdim: pixel resolution to join to image header :return im_out: concatenated image """ # WARNING: calling concat_data in python instead of in command line causes a non understood issue (results are different with both options) from numpy import concatenate, expand_dims dat_list = [] data_concat_list = [] # check if shape of first image is smaller than asked dim to concatenate along # data0 = Image(fname_in_list[0]).data # if len(data0.shape) <= dim: # expand_dim = True # else: # expand_dim = False for i, fname in enumerate(fname_in_list): # if there is more than 100 images to concatenate, then it does it iteratively to avoid memory issue. if i != 0 and i % 100 == 0: data_concat_list.append(concatenate(dat_list, axis=dim)) im = Image(fname) dat = im.data # if image shape is smaller than asked dim, then expand dim if len(dat.shape) <= dim: dat = expand_dims(dat, dim) dat_list = [dat] del im del dat else: im = Image(fname) dat = im.data # if image shape is smaller than asked dim, then expand dim if len(dat.shape) <= dim: dat = expand_dims(dat, dim) dat_list.append(dat) del im del dat if data_concat_list: data_concat_list.append(concatenate(dat_list, axis=dim)) data_concat = concatenate(data_concat_list, axis=dim) else: data_concat = concatenate(dat_list, axis=dim) # write file im_out = Image(fname_in_list[0]).copy() im_out.data = data_concat im_out.setFileName(im_out.file_name + '_concat' + im_out.ext) if pixdim is not None: im_out.hdr['pixdim'] = pixdim return im_out
def get_minimum_path_nii(fname): from msct_image import Image data = Image(fname) vesselness_data = data.data raw_orient = data.change_orientation() result, J1, J2 = get_minimum_path(data.data, invert=1) data.data = result data.change_orientation(raw_orient) data.file_name += '_minimalpath' data.save()
def concat_data(fname_in_list, dim, pixdim=None): """ Concatenate data :param im_in_list: list of images. :param dim: dimension: 0, 1, 2, 3. :param pixdim: pixel resolution to join to image header :return im_out: concatenated image """ # WARNING: calling concat_data in python instead of in command line causes a non understood issue (results are different with both options) from numpy import concatenate, expand_dims, squeeze dat_list = [] data_concat_list = [] # check if shape of first image is smaller than asked dim to concatenate along data0 = Image(fname_in_list[0]).data if len(data0.shape) <= dim: expand_dim = True else: expand_dim = False for i, fname in enumerate(fname_in_list): # if there is more than 100 images to concatenate, then it does it iteratively to avoid memory issue. if i != 0 and i % 100 == 0: data_concat_list.append(concatenate(dat_list, axis=dim)) im = Image(fname) dat = im.data if expand_dim: dat = expand_dims(dat, dim) dat_list = [dat] del im del dat else: im = Image(fname) dat = im.data if expand_dim: dat = expand_dims(dat, dim) dat_list.append(dat) del im del dat if data_concat_list: data_concat_list.append(concatenate(dat_list, axis=dim)) data_concat = concatenate(data_concat_list, axis=dim) else: data_concat = concatenate(dat_list, axis=dim) # write file im_out = Image(fname_in_list[0]).copy() im_out.data = data_concat im_out.setFileName(im_out.file_name+'_concat'+im_out.ext) if pixdim is not None: im_out.hdr['pixdim'] = pixdim return im_out
def copy_header(fname_src, fname_dest): """ Copy header :param fname_src: source file name :param fname_dest: destination file name :return: """ nii_src = Image(fname_src) data_dest = Image(fname_dest).data nii_src.setFileName(fname_dest) nii_src.data = data_dest nii_src.save()
def execute(self): """ This method executes the symmetry detection :return: returns the symmetry data """ img = Image(self.input_image) raw_orientation = img.change_orientation() data = np.squeeze(img.data) dim = data.shape section_length = dim[1] / self.nb_sections result = np.zeros(dim) for i in range(0, self.nb_sections): if (i + 1) * section_length > dim[1]: y_length = (i + 1) * section_length - ( (i + 1) * section_length - dim[1]) result[:, i * section_length:i * section_length + y_length, :] = symmetry_detector_right_left( data[:, i * section_length:i * section_length + y_length, :], cropped_xy=self.crop_xy) sym = symmetry_detector_right_left( data[:, i * section_length:(i + 1) * section_length, :], cropped_xy=self.crop_xy) result[:, i * section_length:(i + 1) * section_length, :] = sym result_image = Image(img) if len(result_image.data) == 4: result_image.data = result[:, :, :, np.newaxis] else: result_image.data = result result_image.change_orientation(raw_orientation) return result_image.data
def output_debug_file(self, img, data, file_name): """ This method writes a nifti file that corresponds to a step in the algorithm for easy debug. The new nifti file uses the header from the the image passed as parameter :param data: data to be written to file :param file_name: filename... :return: None """ if self.verbose == 2: current_folder = os.getcwd() # os.chdir(self.path_tmp) try: img = Image(img) img.data = data img.change_orientation(self.raw_orientation) img.file_name = file_name img.save() except Exception, e: print e
def post_processing_volume_wise(fname_in): """Post processing function.""" im_in = Image(fname_in) data_in = im_in.data.astype(np.int) data_in = _remove_blobs(data_in) zz_zeros = [ zz for zz in range(im_in.dim[2]) if 1 not in list(np.unique(data_in[:, :, zz])) ] zz_holes = _remove_extrem_holes(zz_zeros, im_in.dim[2] - 1, 0) # filling z_holes, i.e. interpolate for z_slice not segmented im_in.data = _fill_z_holes(zz_holes, data_in, im_in.dim[6]) if len(zz_holes) else data_in im_in.setFileName(fname_in) im_in.save() del im_in
def output_debug_file(self, img, data, file_name): """ This method writes a nifti file that corresponds to a step in the algorithm for easy debug. The new nifti file uses the header from the the image passed as parameter :param data: data to be written to file :param file_name: filename... :return: None """ if self.produce_output: current_folder = os.getcwd() os.chdir(self.debug_folder) try: img = Image(img) img.data = data img.change_orientation(self.raw_orientation) img.file_name = file_name img.save() except Exception, e: print e os.chdir(current_folder)
def label_discs(fname_seg_labeled, verbose=1): """ Label discs from labaled_segmentation :param fname_seg_labeld: fname of the labeled segmentation :param verbose: :return: """ # open labeled segmentation im_seg_labeled = Image(fname_seg_labeled) orientation_native = im_seg_labeled.change_orientation('RPI') nx, ny, nz = im_seg_labeled.dim[0], im_seg_labeled.dim[ 1], im_seg_labeled.dim[2] data_disc = np.zeros([nx, ny, nz]) vertebral_level_previous = np.max(im_seg_labeled.data) # loop across z for iz in range(nz): # get 2d slice slice = im_seg_labeled.data[:, :, iz] # check if at least one voxel is non-zero if np.any(slice): slice_one = np.copy(slice) # set all non-zero values to 1 slice_one[slice.nonzero()] = 1 # compute center of mass cx, cy = [ int(x) for x in np.round(center_of_mass(slice_one)).tolist() ] # retrieve vertebral level vertebral_level = slice[cx, cy] # if smaller than previous level, then labeled as a disc if vertebral_level < vertebral_level_previous: # label disc # sct.printv('iz='+iz+', disc='+vertebral_level) data_disc[cx, cy, iz] = vertebral_level # update variable vertebral_level_previous = vertebral_level # save disc labeled file im_seg_labeled.file_name += '_disc' im_seg_labeled.data = data_disc im_seg_labeled.change_orientation(orientation_native) im_seg_labeled.save()
def label_discs(fname_seg_labeled, verbose=1): """ Label discs from labaled_segmentation :param fname_seg_labeld: fname of the labeled segmentation :param verbose: :return: """ # open labeled segmentation im_seg_labeled = Image(fname_seg_labeled) orientation_native = im_seg_labeled.change_orientation('RPI') nx, ny, nz = im_seg_labeled.dim[0], im_seg_labeled.dim[1], im_seg_labeled.dim[2] data_disc = np.zeros([nx, ny, nz]) vertebral_level_previous = np.max(im_seg_labeled.data) # loop across z for iz in range(nz): # get 2d slice slice = im_seg_labeled.data[:, :, iz] # check if at least one voxel is non-zero if np.any(slice): slice_one = np.copy(slice) # set all non-zero values to 1 slice_one[slice.nonzero()] = 1 # compute center of mass cx, cy = [int(x) for x in np.round(center_of_mass(slice_one)).tolist()] # retrieve vertebral level vertebral_level = slice[cx, cy] # if smaller than previous level, then labeled as a disc if vertebral_level < vertebral_level_previous: # label disc # print 'iz='+iz+', disc='+vertebral_level data_disc[cx, cy, iz] = vertebral_level # update variable vertebral_level_previous = vertebral_level # save disc labeled file im_seg_labeled.file_name += '_disc' im_seg_labeled.data = data_disc im_seg_labeled.change_orientation(orientation_native) im_seg_labeled.save()
def create_label_z(fname_seg, z, value): """ Create a label at coordinates x_center, y_center, z :param fname_seg: segmentation :param z: int :return: fname_label """ fname_label = 'labelz.nii.gz' nii = Image(fname_seg) orientation_origin = nii.change_orientation('RPI') # change orientation to RPI nx, ny, nz, nt, px, py, pz, pt = nii.dim # Get dimensions # find x and y coordinates of the centerline at z using center of mass from scipy.ndimage.measurements import center_of_mass x, y = center_of_mass(nii.data[:, :, z]) x, y = int(round(x)), int(round(y)) nii.data[:, :, :] = 0 nii.data[x, y, z] = value # dilate label to prevent it from disappearing due to nearestneighbor interpolation from sct_maths import dilate nii.data = dilate(nii.data, [3]) nii.setFileName(fname_label) nii.change_orientation(orientation_origin) # put back in original orientation nii.save() return fname_label
def main(): # Initialization fname_data = '' suffix_out = '_crop' remove_temp_files = param.remove_temp_files verbose = param.verbose fsloutput = 'export FSLOUTPUTTYPE=NIFTI; ' # for faster processing, all outputs are in NIFTI remove_temp_files = param.remove_temp_files # Parameters for debug mode if param.debug: print '\n*** WARNING: DEBUG MODE ON ***\n' fname_data = path_sct+'/testing/data/errsm_23/t2/t2.nii.gz' remove_temp_files = 0 else: # Check input parameters try: opts, args = getopt.getopt(sys.argv[1:],'hi:r:v:') except getopt.GetoptError: usage() if not opts: usage() for opt, arg in opts: if opt == '-h': usage() elif opt in ('-i'): fname_data = arg elif opt in ('-r'): remove_temp_files = int(arg) elif opt in ('-v'): verbose = int(arg) # display usage if a mandatory argument is not provided if fname_data == '': usage() # 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) # print arguments print '\nCheck parameters:' print ' data ................... '+fname_data print # 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 # create temporary folder path_tmp = 'tmp.'+time.strftime("%y%m%d%H%M%S")+'/' sct.run('mkdir '+path_tmp) # copy files into tmp folder sct.run('isct_c3d '+fname_data+' -o '+path_tmp+'data.nii') # go to tmp folder os.chdir(path_tmp) # change orientation sct.printv('\nChange orientation to RPI...', verbose) set_orientation('data.nii', 'RPI', '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 to parent folder os.chdir('..') sct.printv('\nGenerate output files...', verbose) sct.generate_output_file(path_tmp+'data_rpi_crop.nii', path_out+file_out+ext_out) # Remove temporary files if remove_temp_files == 1: print('\nRemove temporary files...') sct.run('rm -rf '+path_tmp) # to view results print '\nDone! To view results, type:' print 'fslview '+path_out+file_out+ext_out+' &' print
def create_mask(): fsloutput = "export FSLOUTPUTTYPE=NIFTI; " # for faster processing, all outputs are in NIFTI # display usage if a mandatory argument is not provided if param.fname_data == "" or param.method == "": sct.printv("\nERROR: All mandatory arguments are not provided. See usage (add -h).\n", 1, "error") # parse argument for method method_list = param.method.replace(" ", "").split(",") # remove spaces and parse with comma # method_list = param.method.split(',') # parse with comma method_type = method_list[0] # check existence of method type if not method_type in param.method_list: sct.printv( "\nERROR in " + os.path.basename(__file__) + ': Method "' + method_type + '" is not recognized. See usage (add -h).\n', 1, "error", ) # check method val if not method_type == "center": method_val = method_list[1] del method_list # check existence of shape if not param.shape in param.shape_list: sct.printv( "\nERROR in " + os.path.basename(__file__) + ': Shape "' + param.shape + '" is not recognized. 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) if method_type == "centerline": sct.check_file_exist(method_val, param.verbose) # check if orientation is RPI sct.printv("\nCheck if orientation is RPI...", param.verbose) status, output = sct.run("sct_orientation -i " + param.fname_data) if not output == "RPI": sct.printv( "\nERROR in " + os.path.basename(__file__) + ": Orientation of input image should be RPI. Use sct_orientation to put your image in RPI.\n", 1, "error", ) # display input parameters sct.printv("\nInput parameters:", param.verbose) sct.printv(" data .................." + param.fname_data, param.verbose) sct.printv(" method ................" + method_type, param.verbose) # Extract path/file/extension path_data, file_data, ext_data = sct.extract_fname(param.fname_data) # Get output folder and file name if param.fname_out == "": param.fname_out = param.file_prefix + file_data + ext_data # fname_out = os.path.abspath(path_out+file_out+ext_out) # 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) convert(param.fname_data, path_tmp + "data.nii") # sct.run('cp '+param.fname_data+' '+path_tmp+'data'+ext_data, param.verbose) if method_type == "centerline": convert(method_val, path_tmp + "centerline.nii.gz") # sct.run('isct_c3d '+method_val+' -o '+path_tmp+'/centerline.nii.gz') # go to tmp folder os.chdir(path_tmp) # 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) # in case user input 4d data if nt != 1: sct.printv( "WARNING in " + os.path.basename(__file__) + ": Input image is 4d but output mask will 3D.", param.verbose, "warning", ) # extract first volume to have 3d reference nii = Image("data.nii") data3d = nii.data[:, :, :, 0] nii.data = data3d nii.save() if method_type == "coord": # parse to get coordinate coord = map(int, method_val.split("x")) if method_type == "point": # get file name fname_point = method_val # extract coordinate of point sct.printv("\nExtract coordinate of point...", param.verbose) status, output = sct.run("sct_label_utils -i " + fname_point + " -t display-voxel", param.verbose) # parse to get coordinate coord = output[output.find("Position=") + 10 : -17].split(",") if method_type == "center": # set coordinate at center of FOV coord = round(float(nx) / 2), round(float(ny) / 2) if method_type == "centerline": # get name of centerline from user argument fname_centerline = "centerline.nii.gz" else: # generate volume with line along Z at coordinates 'coord' sct.printv("\nCreate line...", param.verbose) fname_centerline = create_line("data.nii", coord, nz) # create mask sct.printv("\nCreate mask...", param.verbose) centerline = nibabel.load(fname_centerline) # open centerline hdr = centerline.get_header() # get header hdr.set_data_dtype("uint8") # set imagetype to uint8 data_centerline = centerline.get_data() # get centerline z_centerline = [iz for iz in range(0, nz, 1) if data_centerline[:, :, iz].any()] nz = len(z_centerline) # get center of mass of the centerline cx = [0] * nz cy = [0] * nz for iz in range(0, nz, 1): cx[iz], cy[iz] = ndimage.measurements.center_of_mass(numpy.array(data_centerline[:, :, z_centerline[iz]])) # create 2d masks file_mask = "data_mask" for iz in range(nz): center = numpy.array([cx[iz], cy[iz]]) mask2d = create_mask2d(center, param.shape, param.size, nx, ny) # Write NIFTI volumes img = nibabel.Nifti1Image(mask2d, None, hdr) nibabel.save(img, (file_mask + str(iz) + ".nii")) # merge along Z # cmd = 'fslmerge -z mask ' cmd = "sct_concat_data -dim z -o mask.nii.gz -i " for iz in range(nz): cmd = cmd + file_mask + str(iz) + ".nii," # remove ',' at the end of the string cmd = cmd[:-1] status, output = sct.run(cmd, param.verbose) # copy geometry copy_header("data.nii", "mask.nii.gz") # come back to parent folder os.chdir("..") # Generate output files sct.printv("\nGenerate output files...", param.verbose) sct.generate_output_file(path_tmp + "mask.nii.gz", param.fname_out) # Remove temporary files if param.remove_tmp_files == 1: sct.printv("\nRemove temporary files...", param.verbose) 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_data + " " + param.fname_out + " -l Red -t 0.5 &", param.verbose, "info") print
def create_mask(): fsloutput = 'export FSLOUTPUTTYPE=NIFTI; ' # for faster processing, all outputs are in NIFTI # parse argument for method method_type = param.process[0] # check method val if not method_type == 'center': method_val = param.process[1] # check existence of input files if method_type == 'centerline': sct.check_file_exist(method_val, param.verbose) # check if orientation is RPI sct.printv('\nCheck if orientation is RPI...', param.verbose) ori = get_orientation(param.fname_data, filename=True) if not ori == 'RPI': sct.printv('\nERROR in '+os.path.basename(__file__)+': Orientation of input image should be RPI. Use sct_image -setorient to put your image in RPI.\n', 1, 'error') # Extract path/file/extension path_data, file_data, ext_data = sct.extract_fname(param.fname_data) # Get output folder and file name if param.fname_out == '': param.fname_out = param.file_prefix+file_data+ext_data #fname_out = os.path.abspath(path_out+file_out+ext_out) # 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 sct.printv('\nCopying input data to tmp folder and convert to nii...', param.verbose) convert(param.fname_data, path_tmp+'data.nii') # sct.run('cp '+param.fname_data+' '+path_tmp+'data'+ext_data, param.verbose) if method_type == 'centerline': convert(method_val, path_tmp+'centerline.nii.gz') # go to tmp folder os.chdir(path_tmp) # 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) # in case user input 4d data if nt != 1: sct.printv('WARNING in '+os.path.basename(__file__)+': Input image is 4d but output mask will 3D.', param.verbose, 'warning') # extract first volume to have 3d reference nii = Image('data.nii') data3d = nii.data[:,:,:,0] nii.data = data3d nii.save() if method_type == 'coord': # parse to get coordinate coord = map(int, method_val.split('x')) if method_type == 'point': # get file name fname_point = method_val # extract coordinate of point sct.printv('\nExtract coordinate of point...', param.verbose) status, output = sct.run('sct_label_utils -i '+fname_point+' -p display-voxel', param.verbose) # parse to get coordinate coord = output[output.find('Position=')+10:-17].split(',') if method_type == 'center': # set coordinate at center of FOV coord = round(float(nx)/2), round(float(ny)/2) if method_type == 'centerline': # get name of centerline from user argument fname_centerline = 'centerline.nii.gz' else: # generate volume with line along Z at coordinates 'coord' sct.printv('\nCreate line...', param.verbose) fname_centerline = create_line('data.nii', coord, nz) # create mask sct.printv('\nCreate mask...', param.verbose) centerline = nibabel.load(fname_centerline) # open centerline hdr = centerline.get_header() # get header hdr.set_data_dtype('uint8') # set imagetype to uint8 data_centerline = centerline.get_data() # get centerline z_centerline = [iz for iz in range(0, nz, 1) if data_centerline[:, :, iz].any()] nz = len(z_centerline) # get center of mass of the centerline cx = [0] * nz cy = [0] * nz for iz in range(0, nz, 1): cx[iz], cy[iz] = ndimage.measurements.center_of_mass(numpy.array(data_centerline[:, :, z_centerline[iz]])) # create 2d masks file_mask = 'data_mask' for iz in range(nz): center = numpy.array([cx[iz], cy[iz]]) mask2d = create_mask2d(center, param.shape, param.size, nx, ny, param.even) # Write NIFTI volumes img = nibabel.Nifti1Image(mask2d, None, hdr) nibabel.save(img, (file_mask+str(iz)+'.nii')) # merge along Z # cmd = 'fslmerge -z mask ' im_list = [] for iz in range(nz): im_list.append(Image(file_mask+str(iz)+'.nii')) im_out = concat_data(im_list, 2) im_out.setFileName('mask.nii.gz') im_out.save() # copy geometry im_dat = Image('data.nii') im_mask = Image('mask.nii.gz') im_mask = copy_header(im_dat, im_mask) im_mask.save() # come back to parent folder os.chdir('..') # Generate output files sct.printv('\nGenerate output files...', param.verbose) sct.generate_output_file(path_tmp+'mask.nii.gz', param.fname_out) # Remove temporary files if param.remove_tmp_files == 1: sct.printv('\nRemove temporary files...', param.verbose) sct.run('rm -rf '+path_tmp, param.verbose, error_exit='warning') # to view results sct.printv('\nDone! To view results, type:', param.verbose) sct.printv('fslview '+param.fname_data+' '+param.fname_out+' -l Red -t 0.5 &', param.verbose, 'info') print
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 main(args=None): # Initialization # fname_anat = '' # fname_centerline = '' sigma = 3 # default value of the standard deviation for the Gaussian smoothing (in terms of number of voxels) # remove_temp_files = param.remove_temp_files # verbose = param.verbose start_time = time.time() parser = get_parser() arguments = parser.parse(sys.argv[1:]) fname_anat = arguments['-i'] fname_centerline = arguments['-s'] if '-smooth' in arguments: sigma = arguments['-smooth'] if '-r' in arguments: remove_temp_files = int(arguments['-r']) if '-v' in arguments: verbose = int(arguments['-v']) # Display arguments print '\nCheck input arguments...' print ' Volume to smooth .................. ' + fname_anat print ' Centerline ........................ ' + fname_centerline print ' Sigma (mm) ........................ '+str(sigma) print ' Verbose ........................... '+str(verbose) # Check that input is 3D: from msct_image import Image nx, ny, nz, nt, px, py, pz, pt = Image(fname_anat).dim dim = 4 # by default, will be adjusted later if nt == 1: dim = 3 if nz == 1: dim = 2 if dim == 4: sct.printv('WARNING: the input image is 4D, please split your image to 3D before smoothing spinalcord using :\n' 'sct_image -i '+fname_anat+' -split t -o '+fname_anat, verbose, 'warning') sct.printv('4D images not supported, aborting ...', verbose, 'error') # Extract path/file/extension path_anat, file_anat, ext_anat = sct.extract_fname(fname_anat) path_centerline, file_centerline, ext_centerline = sct.extract_fname(fname_centerline) # create temporary folder sct.printv('\nCreate temporary folder...', verbose) path_tmp = sct.slash_at_the_end('tmp.'+time.strftime("%y%m%d%H%M%S"), 1) sct.run('mkdir '+path_tmp, verbose) # Copying input data to tmp folder sct.printv('\nCopying input data to tmp folder and convert to nii...', verbose) sct.run('cp '+fname_anat+' '+path_tmp+'anat'+ext_anat, verbose) sct.run('cp '+fname_centerline+' '+path_tmp+'centerline'+ext_centerline, verbose) # go to tmp folder os.chdir(path_tmp) # convert to nii format convert('anat'+ext_anat, 'anat.nii') convert('centerline'+ext_centerline, 'centerline.nii') # Change orientation of the input image into RPI print '\nOrient input volume to RPI orientation...' fname_anat_rpi = set_orientation('anat.nii', 'RPI', filename=True) move(fname_anat_rpi, 'anat_rpi.nii') # Change orientation of the input image into RPI print '\nOrient centerline to RPI orientation...' fname_centerline_rpi = set_orientation('centerline.nii', 'RPI', filename=True) move(fname_centerline_rpi, 'centerline_rpi.nii') # Straighten the spinal cord # straighten segmentation sct.printv('\nStraighten the spinal cord using centerline/segmentation...', verbose) # check if warp_curve2straight and warp_straight2curve already exist (i.e. no need to do it another time) if os.path.isfile('../warp_curve2straight.nii.gz') and os.path.isfile('../warp_straight2curve.nii.gz') and os.path.isfile('../straight_ref.nii.gz'): # if they exist, copy them into current folder sct.printv('WARNING: Straightening was already run previously. Copying warping fields...', verbose, 'warning') shutil.copy('../warp_curve2straight.nii.gz', 'warp_curve2straight.nii.gz') shutil.copy('../warp_straight2curve.nii.gz', 'warp_straight2curve.nii.gz') shutil.copy('../straight_ref.nii.gz', 'straight_ref.nii.gz') # apply straightening sct.run('sct_apply_transfo -i anat_rpi.nii -w warp_curve2straight.nii.gz -d straight_ref.nii.gz -o anat_rpi_straight.nii -x spline', verbose) else: sct.run('sct_straighten_spinalcord -i anat_rpi.nii -s centerline_rpi.nii -qc 0 -x spline', verbose) # Smooth the straightened image along z print '\nSmooth the straightened image along z...' sct.run('sct_maths -i anat_rpi_straight.nii -smooth 0,0,'+str(sigma)+' -o anat_rpi_straight_smooth.nii', verbose) # Apply the reversed warping field to get back the curved spinal cord print '\nApply the reversed warping field to get back the curved spinal cord...' sct.run('sct_apply_transfo -i anat_rpi_straight_smooth.nii -o anat_rpi_straight_smooth_curved.nii -d anat.nii -w warp_straight2curve.nii.gz -x spline', verbose) # replace zeroed voxels by original image (issue #937) sct.printv('\nReplace zeroed voxels by original image...', verbose) nii_smooth = Image('anat_rpi_straight_smooth_curved.nii') data_smooth = nii_smooth.data data_input = Image('anat.nii').data indzero = np.where(data_smooth == 0) data_smooth[indzero] = data_input[indzero] nii_smooth.data = data_smooth nii_smooth.setFileName('anat_rpi_straight_smooth_curved_nonzero.nii') nii_smooth.save() # come back to parent folder os.chdir('..') # Generate output file print '\nGenerate output file...' sct.generate_output_file(path_tmp+'/anat_rpi_straight_smooth_curved_nonzero.nii', file_anat+'_smooth'+ext_anat) # Remove temporary files if remove_temp_files == 1: print('\nRemove temporary files...') sct.run('rm -rf '+path_tmp) # Display elapsed time elapsed_time = time.time() - start_time print '\nFinished! Elapsed time: '+str(int(round(elapsed_time)))+'s\n' # to view results sct.printv('Done! To view results, type:', verbose) sct.printv('fslview '+file_anat+' '+file_anat+'_smooth &\n', verbose, 'info')
def main(): # create temporary folder sct.printv('\nCreate temporary folder...', verbose, 'normal') path_tmp = 'tmp.'+time.strftime("%y%m%d%H%M%S")+'/' sct.run('mkdir '+path_tmp) target = 'target.nii.gz' target_seg = 'target_seg.nii.gz' anat = 'anat.nii.gz' anat_seg = 'anat_seg.nii.gz' warp_template2anat = 'warp_template2anat.nii.gz' sct.run('cp '+multimodal_reg_param.anat+' '+path_tmp+anat) sct.run('cp '+multimodal_reg_param.target+' '+path_tmp+target) sct.run('cp '+multimodal_reg_param.anat_seg+' '+path_tmp+anat_seg) sct.run('cp '+multimodal_reg_param.target_seg+' '+path_tmp+target_seg) sct.run('cp '+multimodal_reg_param.warp_template2anat+' '+path_tmp+warp_template2anat) os.chdir(path_tmp) # registration of the template to the target warp_anat2target, warp_target2anat, label_original = reg_multimodal_warp(anat, target, anat_seg, target_seg, warp_template2anat, multimodal_reg_param) # segmentation of the gray matter gm_seg_param.res_type = 'binary' wm_fname, gm_fname = segment_gm(target_fname=target, sc_seg_fname=target_seg, path_to_label=label_original, param=gm_seg_param) wm_seg_out = sct.extract_fname(multimodal_reg_param.target)[1]+'_wm_seg.nii.gz' gm_seg_out = sct.extract_fname(multimodal_reg_param.target)[1]+'_gm_seg.nii.gz' sct.run('cp '+wm_fname+' ../'+wm_seg_out) sct.run('cp '+gm_fname+' ../'+gm_seg_out) # registration of the template WM to the automatic Wm segmentation wm_reg_param.fname_fixed = wm_fname wm_reg_param.fname_moving = label_original + '/template/MNI-Poly-AMU_WM.nii.gz' wm_reg_param.fname_seg_fixed = target_seg wm_reg_param.fname_seg_moving = label_original + '/template/MNI-Poly-AMU_cord.nii.gz' if gm_seg_param.res_type == 'binary': # binarize template WM template_wm = Image(wm_reg_param.fname_moving) template_wm.data = (template_wm.data > 0.5).astype(int) template_wm.save() warp, inverse_warp = wm_registration(wm_reg_param) warp_anat2target_corrected = 'warp_'+sct.extract_fname(multimodal_reg_param.anat)[1]+'2'+sct.extract_fname(multimodal_reg_param.target)[1]+'_corrected_wm.nii.gz' warp_target2anat_corrected = 'warp_'+sct.extract_fname(multimodal_reg_param.target)[1]+'2'+sct.extract_fname(multimodal_reg_param.anat)[1]+'_corrected_wm.nii.gz' sct.run('sct_concat_transfo -w '+warp_anat2target+','+warp+' -d '+target+' -o '+warp_anat2target_corrected) sct.run('sct_concat_transfo -w '+inverse_warp+','+warp_target2anat+' -d '+anat+' -o '+warp_target2anat_corrected) target_reg = sct.extract_fname(multimodal_reg_param.target)[1]+'_reg_corrected.nii.gz' anat_reg = sct.extract_fname(multimodal_reg_param.anat)[1]+'_reg_corrected.nii.gz' sct.run('sct_apply_transfo -i '+target+' -d '+anat+' -w '+warp_target2anat_corrected+' -o '+target_reg) sct.run('sct_apply_transfo -i '+anat+' -d '+target+' -w '+warp_anat2target_corrected+' -o '+anat_reg) sct.run('cp '+target_reg+' ../'+target_reg) sct.run('cp '+anat_reg+' ../'+anat_reg) sct.run('cp '+warp_anat2target_corrected+' ../'+warp_anat2target_corrected) sct.run('cp '+warp_target2anat_corrected+' ../'+warp_target2anat_corrected) sct.printv('Done!\n' 'You can warp the template to the target using the following command lines:\n' 'sct_concat_transfo -w '+multimodal_reg_param.warp_template2anat+','+warp_anat2target_corrected+' -d '+multimodal_reg_param.target+' -o warp_template2'+sct.extract_fname(multimodal_reg_param.target)[1]+'.nii.gz\n' 'sct_warp_template -d '+multimodal_reg_param.target+' -w warp_template2'+sct.extract_fname(multimodal_reg_param.target)[1]+'.nii.gz', verbose, 'info') os.chdir('..') if remove: sct.printv('\nRemove temporary files...', verbose, 'normal') sct.run("rm -rf "+path_tmp)
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 # create temporary folder path_tmp = 'tmp.' + time.strftime("%y%m%d%H%M%S") + '/' sct.run('mkdir ' + path_tmp) # 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, path_tmp + 'data.nii') # go to tmp folder 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 to parent folder os.chdir('..') sct.printv('\nGenerate output files...', verbose) sct.generate_output_file(path_tmp + 'data_rpi_crop.nii', path_out + file_out + ext_out) # Remove temporary files if remove_temp_files == 1: sct.printv('\nRemove temporary files...') sct.run('rm -rf ' + path_tmp) # to view results sct.printv('\nDone! To view results, type:') sct.printv('fslview ' + path_out + file_out + ext_out + ' &') sct.printv()
def process(self): # preprocessing os.chdir(self.tmp_dir) im_target = Image(self.original_target) im_sc_seg = Image(self.original_sc_seg) self.original_header = im_target.hdr self.original_orientation = im_target.orientation index_x = self.original_orientation.find('R') if 'R' in self.original_orientation else self.original_orientation.find('L') index_y = self.original_orientation.find('P') if 'P' in self.original_orientation else self.original_orientation.find('A') index_z = self.original_orientation.find('I') if 'I' in self.original_orientation else self.original_orientation.find('S') # resampling of the images nx, ny, nz, nt, px, py, pz, pt = im_target.dim pix_dim = [px, py, pz] self.original_px = pix_dim[index_x] self.original_py = pix_dim[index_y] if round(self.original_px, 2) != self.resample_to or round(self.original_py, 2) != self.resample_to: self.t2star = resample_image(self.original_target, npx=self.resample_to, npy=self.resample_to) self.sc_seg = resample_image(self.original_sc_seg, binary=True, npx=self.resample_to, npy=self.resample_to) # denoising (optional) im_target = Image(self.t2star) if self.denoising: from sct_maths import denoise_ornlm im_target.data = denoise_ornlm(im_target.data) im_target.save() self.t2star = im_target.file_name + im_target.ext box_size = int(22.5/self.resample_to) # Pad in case the spinal cord is too close to the edges pad_size = box_size/2 + 2 self.pad = [str(pad_size)]*3 self.pad[index_z] = str(0) t2star_pad = sct.add_suffix(self.t2star, '_pad') sc_seg_pad = sct.add_suffix(self.sc_seg, '_pad') sct.run('sct_image -i '+self.t2star+' -pad '+self.pad[0]+','+self.pad[1]+','+self.pad[2]+' -o '+t2star_pad) sct.run('sct_image -i '+self.sc_seg+' -pad '+self.pad[0]+','+self.pad[1]+','+self.pad[2]+' -o '+sc_seg_pad) self.t2star = t2star_pad self.sc_seg = sc_seg_pad # put data in RPI t2star_rpi = sct.add_suffix(self.t2star, '_RPI') sc_seg_rpi = sct.add_suffix(self.sc_seg, '_RPI') sct.run('sct_image -i '+self.t2star+' -setorient RPI -o '+t2star_rpi) sct.run('sct_image -i '+self.sc_seg+' -setorient RPI -o '+sc_seg_rpi) self.t2star = t2star_rpi self.sc_seg = sc_seg_rpi self.square_mask, self.processed_target = crop_t2_star(self.t2star, self.sc_seg, box_size=box_size) if self.t2 is not None: self.fname_level = compute_level_file(self.t2star, self.sc_seg, self.t2, self.t2_seg, self.t2_landmarks) elif self.fname_level is not None: level_orientation = get_orientation(self.fname_level, filename=True) if level_orientation != 'IRP': self.fname_level = set_orientation(self.fname_level, 'IRP', filename=True) os.chdir('..')
def get_centerline_from_point(input_image, point_file, gap=4, gaussian_kernel=4, remove_tmp_files=1): # Initialization fname_anat = input_image fname_point = point_file slice_gap = gap remove_tmp_files = remove_tmp_files gaussian_kernel = gaussian_kernel start_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 # 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_3d(fname_anat, filename=True) # 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." + 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 im_anat = convert("tmp.anat" + ext_anat, "tmp.anat.nii") im_point = 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..." set_orientation(im_anat, "RPI") im_anat.setFileName("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(im_point, "RPI") im_point.setFileName("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..." im_anat_split_list = split_data(im_anat, 2) file_anat_split = [] for im in im_anat_split_list: file_anat_split.append(im.absolutepath) im.save() im_point_split_list = split_data(im_point, 2) file_point_split = [] for im in im_point_split_list: file_point_split.append(im.absolutepath) im.save() # Extract coordinates of input point 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() # 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 < nz: # 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..." # im_anat_list = [Image(fname) for fname in glob.glob('tmp.anat_orient_fit_z*.nii')] fname_anat_list = glob.glob("tmp.anat_orient_fit_z*.nii") im_anat_concat = concat_data(fname_anat_list, 2) im_anat_concat.setFileName("tmp.anat_orient_fit.nii") im_anat_concat.save() # im_mask_list = [Image(fname) for fname in glob.glob('tmp.mask_orient_fit_z*.nii')] fname_mask_list = glob.glob("tmp.mask_orient_fit_z*.nii") im_mask_concat = concat_data(fname_mask_list, 2) im_mask_concat.setFileName("tmp.mask_orient_fit.nii") im_mask_concat.save() # im_point_list = [Image(fname) for fname in glob.glob('tmp.point_orient_fit_z*.nii')] fname_point_list = glob.glob("tmp.point_orient_fit_z*.nii") im_point_concat = concat_data(fname_point_list, 2) im_point_concat.setFileName("tmp.point_orient_fit.nii") im_point_concat.save() # Copy header geometry from input data print "\nCopy header geometry from input data..." im_anat = Image("tmp.anat_orient.nii") im_anat_orient_fit = Image("tmp.anat_orient_fit.nii") im_mask_orient_fit = Image("tmp.mask_orient_fit.nii") im_point_orient_fit = Image("tmp.point_orient_fit.nii") im_anat_orient_fit = copy_header(im_anat, im_anat_orient_fit) im_mask_orient_fit = copy_header(im_anat, im_mask_orient_fit) im_point_orient_fit = copy_header(im_anat, im_point_orient_fit) for im in [im_anat_orient_fit, im_mask_orient_fit, im_point_orient_fit]: im.save() # 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 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, error_exit="warning") # 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() - start_time print "\nFinished! \n\tGenerated file: " + fname_output_centerline + "\n\tElapsed time: " + str( int(round(elapsed_time)) ) + "s\n"
def compute_dti(fname_in, fname_bvals, fname_bvecs, prefix, method, file_mask): """ Compute DTI. :param fname_in: input 4d file. :param bvals: bvals txt file :param bvecs: bvecs txt file :param prefix: output prefix. Example: "dti_" :param method: algo for computing dti :return: True/False """ # Open file. from msct_image import Image nii = Image(fname_in) data = nii.data sct.printv('data.shape (%d, %d, %d, %d)' % data.shape) # open bvecs/bvals from dipy.io import read_bvals_bvecs bvals, bvecs = read_bvals_bvecs(fname_bvals, fname_bvecs) from dipy.core.gradients import gradient_table gtab = gradient_table(bvals, bvecs) # mask and crop the data. This is a quick way to avoid calculating Tensors on the background of the image. if not file_mask == '': sct.printv('Open mask file...', param.verbose) # open mask file nii_mask = Image(file_mask) mask = nii_mask.data # fit tensor model sct.printv('Computing tensor using "' + method + '" method...', param.verbose) import dipy.reconst.dti as dti if method == 'standard': tenmodel = dti.TensorModel(gtab) if file_mask == '': tenfit = tenmodel.fit(data) else: tenfit = tenmodel.fit(data, mask) elif method == 'restore': import dipy.denoise.noise_estimate as ne sigma = ne.estimate_sigma(data) dti_restore = dti.TensorModel(gtab, fit_method='RESTORE', sigma=sigma) if file_mask == '': tenfit = dti_restore.fit(data) else: tenfit = dti_restore.fit(data, mask) # Compute metrics sct.printv('Computing metrics...', param.verbose) # FA from dipy.reconst.dti import fractional_anisotropy nii.data = fractional_anisotropy(tenfit.evals) nii.setFileName(prefix + 'FA.nii.gz') nii.save('float32') # MD from dipy.reconst.dti import mean_diffusivity nii.data = mean_diffusivity(tenfit.evals) nii.setFileName(prefix + 'MD.nii.gz') nii.save('float32') # RD from dipy.reconst.dti import radial_diffusivity nii.data = radial_diffusivity(tenfit.evals) nii.setFileName(prefix + 'RD.nii.gz') nii.save('float32') # AD from dipy.reconst.dti import axial_diffusivity nii.data = axial_diffusivity(tenfit.evals) nii.setFileName(prefix + 'AD.nii.gz') nii.save('float32') return True
def main(): # Initialization fname_data = '' suffix_out = '_crop' remove_temp_files = param.remove_temp_files verbose = param.verbose fsloutput = 'export FSLOUTPUTTYPE=NIFTI; ' # for faster processing, all outputs are in NIFTI remove_temp_files = param.remove_temp_files # Parameters for debug mode if param.debug: print '\n*** WARNING: DEBUG MODE ON ***\n' fname_data = path_sct + '/testing/data/errsm_23/t2/t2.nii.gz' remove_temp_files = 0 else: # Check input parameters try: opts, args = getopt.getopt(sys.argv[1:], 'hi:r:v:') except getopt.GetoptError: usage() if not opts: usage() for opt, arg in opts: if opt == '-h': usage() elif opt in ('-i'): fname_data = arg elif opt in ('-r'): remove_temp_files = int(arg) elif opt in ('-v'): verbose = int(arg) # display usage if a mandatory argument is not provided if fname_data == '': usage() # 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) # print arguments print '\nCheck parameters:' print ' data ................... ' + fname_data print # 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 # create temporary folder path_tmp = 'tmp.' + time.strftime("%y%m%d%H%M%S") + '/' sct.run('mkdir ' + path_tmp) # copy files into tmp folder sct.run('isct_c3d ' + fname_data + ' -o ' + path_tmp + 'data.nii') # go to tmp folder os.chdir(path_tmp) # change orientation sct.printv('\nChange orientation to RPI...', verbose) set_orientation('data.nii', 'RPI', '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 to parent folder os.chdir('..') sct.printv('\nGenerate output files...', verbose) sct.generate_output_file(path_tmp + 'data_rpi_crop.nii', path_out + file_out + ext_out) # Remove temporary files if remove_temp_files == 1: print('\nRemove temporary files...') sct.run('rm -rf ' + path_tmp) # to view results print '\nDone! To view results, type:' print 'fslview ' + path_out + file_out + ext_out + ' &' print
def compute_csa(fname_segmentation, verbose, remove_temp_files, step, smoothing_param, figure_fit, file_csa_volume, slices, vert_levels, fname_vertebral_labeling='', algo_fitting = 'hanning', type_window = 'hanning', window_length = 80): # Extract path, file and extension fname_segmentation = os.path.abspath(fname_segmentation) path_data, file_data, ext_data = sct.extract_fname(fname_segmentation) # 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") + '_'+str(randint(1, 1000000)), 1) sct.run('mkdir '+path_tmp, verbose) # Copying input data to tmp folder sct.printv('\nCopying input data to tmp folder and convert to nii...', verbose) sct.run('sct_convert -i '+fname_segmentation+' -o '+path_tmp+'segmentation.nii.gz', verbose) # go to tmp folder os.chdir(path_tmp) # Change orientation of the input segmentation into RPI sct.printv('\nChange orientation to RPI...', verbose) sct.run('sct_image -i segmentation.nii.gz -setorient RPI -o segmentation_RPI.nii.gz', verbose) # Open segmentation volume sct.printv('\nOpen segmentation volume...', verbose) im_seg = Image('segmentation_RPI.nii.gz') data_seg = im_seg.data # hdr_seg = im_seg.hdr # Get size of data sct.printv('\nGet data dimensions...', verbose) nx, ny, nz, nt, px, py, pz, pt = im_seg.dim sct.printv(' ' + str(nx) + ' x ' + str(ny) + ' x ' + str(nz), verbose) # # Extract min and max index in Z direction X, Y, Z = (data_seg > 0).nonzero() min_z_index, max_z_index = min(Z), max(Z) # extract centerline and smooth it x_centerline_fit, y_centerline_fit, z_centerline, x_centerline_deriv, y_centerline_deriv, z_centerline_deriv = smooth_centerline('segmentation_RPI.nii.gz', algo_fitting=algo_fitting, type_window=type_window, window_length=window_length, verbose=verbose) z_centerline_scaled = [x*pz for x in z_centerline] # Compute CSA sct.printv('\nCompute CSA...', verbose) # Empty arrays in which CSA for each z slice will be stored csa = np.zeros(max_z_index-min_z_index+1) for iz in xrange(min_z_index, max_z_index+1): # compute the vector normal to the plane normal = normalize(np.array([x_centerline_deriv[iz-min_z_index], y_centerline_deriv[iz-min_z_index], z_centerline_deriv[iz-min_z_index]])) # compute the angle between the normal vector of the plane and the vector z angle = np.arccos(np.dot(normal, [0, 0, 1])) # compute the number of voxels, assuming the segmentation is coded for partial volume effect between 0 and 1. number_voxels = np.sum(data_seg[:, :, iz]) # compute CSA, by scaling with voxel size (in mm) and adjusting for oblique plane csa[iz-min_z_index] = number_voxels * px * py * np.cos(angle) sct.printv('\nSmooth CSA across slices...', verbose) if smoothing_param: from msct_smooth import smoothing_window sct.printv('.. Hanning window: '+str(smoothing_param)+' mm', verbose) csa_smooth = smoothing_window(csa, window_len=smoothing_param/pz, window='hanning', verbose=0) # display figure if verbose == 2: import matplotlib.pyplot as plt plt.figure() pltx, = plt.plot(z_centerline_scaled, csa, 'bo') pltx_fit, = plt.plot(z_centerline_scaled, csa_smooth, 'r', linewidth=2) plt.title("Cross-sectional area (CSA)") plt.xlabel('z (mm)') plt.ylabel('CSA (mm^2)') plt.legend([pltx, pltx_fit], ['Raw', 'Smoothed']) plt.show() # update variable csa = csa_smooth else: sct.printv('.. No smoothing!', verbose) # Create output text file sct.printv('\nWrite text file...', verbose) file_results = open('csa.txt', 'w') for i in range(min_z_index, max_z_index+1): file_results.write(str(int(i)) + ',' + str(csa[i-min_z_index])+'\n') # Display results sct.printv('z='+str(i-min_z_index)+': '+str(csa[i-min_z_index])+' mm^2', verbose, 'bold') file_results.close() # output volume of csa values sct.printv('\nCreate volume of CSA values...', verbose) data_csa = data_seg.astype(np.float32, copy=False) # loop across slices for iz in range(min_z_index, max_z_index+1): # retrieve seg pixels x_seg, y_seg = (data_csa[:, :, iz] > 0).nonzero() seg = [[x_seg[i],y_seg[i]] for i in range(0, len(x_seg))] # loop across pixels in segmentation for i in seg: # replace value with csa value data_csa[i[0], i[1], iz] = csa[iz-min_z_index] # replace data im_seg.data = data_csa # set original orientation # TODO: FIND ANOTHER WAY!! # im_seg.change_orientation(orientation) --> DOES NOT WORK! # set file name -- use .gz because faster to write im_seg.setFileName('csa_volume_RPI.nii.gz') im_seg.changeType('float32') # save volume im_seg.save() # get orientation of the input data im_seg_original = Image('segmentation.nii.gz') orientation = im_seg_original.orientation sct.run('sct_image -i csa_volume_RPI.nii.gz -setorient '+orientation+' -o '+file_csa_volume) # come back to parent folder os.chdir('..') # Generate output files sct.printv('\nGenerate output files...', verbose) copyfile(path_tmp+'csa.txt', path_data+param.fname_csa) # sct.generate_output_file(path_tmp+'csa.txt', path_data+param.fname_csa) # extension already included in param.fname_csa sct.generate_output_file(path_tmp+file_csa_volume, path_data+file_csa_volume) # extension already included in name_output # average csa across vertebral levels or slices if asked (flag -z or -l) if slices or vert_levels: from sct_extract_metric import save_metrics warning = '' if vert_levels and not fname_vertebral_labeling: sct.printv('\nERROR: Vertebral labeling file is missing. See usage.\n', 1, 'error') elif vert_levels and fname_vertebral_labeling: # from sct_extract_metric import get_slices_matching_with_vertebral_levels sct.printv('\tSelected vertebral levels... '+vert_levels) # convert the vertebral labeling file to RPI orientation im_vertebral_labeling = set_orientation(Image(fname_vertebral_labeling), 'RPI', fname_out=path_tmp+'vertebral_labeling_RPI.nii') # get the slices corresponding to the vertebral levels # slices, vert_levels_list, warning = get_slices_matching_with_vertebral_levels(data_seg, vert_levels, im_vertebral_labeling.data, 1) slices, vert_levels_list, warning = get_slices_matching_with_vertebral_levels_based_centerline(vert_levels, im_vertebral_labeling.data, x_centerline_fit, y_centerline_fit, z_centerline) elif not vert_levels: vert_levels_list = [] sct.printv('Average CSA across slices...', type='info') # parse the selected slices slices_lim = slices.strip().split(':') slices_list = range(int(slices_lim[0]), int(slices_lim[1])+1) CSA_for_selected_slices = [] # Read the file csa.txt and get the CSA for the selected slices with open(path_data+param.fname_csa) as openfile: for line in openfile: line_split = line.strip().split(',') if int(line_split[0]) in slices_list: CSA_for_selected_slices.append(float(line_split[1])) # average the CSA mean_CSA = np.mean(np.asarray(CSA_for_selected_slices)) std_CSA = np.std(np.asarray(CSA_for_selected_slices)) sct.printv('Mean CSA: '+str(mean_CSA)+' +/- '+str(std_CSA)+' mm^2', type='info') # write result into output file save_metrics([0], [file_data], slices, [mean_CSA], [std_CSA], path_data + 'csa_mean.txt', path_data+file_csa_volume, 'nb_voxels x px x py x cos(theta) slice-by-slice (in mm^3)', '', actual_vert=vert_levels_list, warning_vert_levels=warning) # compute volume between the selected slices sct.printv('Compute the volume in between the selected slices...', type='info') nb_vox = np.sum(data_seg[:, :, slices_list]) volume = nb_vox*px*py*pz sct.printv('Volume in between the selected slices: '+str(volume)+' mm^3', type='info') # write result into output file save_metrics([0], [file_data], slices, [volume], [np.nan], path_data + 'volume.txt', path_data+file_data, 'nb_voxels x px x py x pz (in mm^3)', '', actual_vert=vert_levels_list, warning_vert_levels=warning) # Remove temporary files if remove_temp_files: sct.printv('\nRemove temporary files...') sct.run('rm -rf '+path_tmp, error_exit='warning')
def extract_centerline(fname_segmentation, remove_temp_files, verbose = 0, algo_fitting = 'hanning', type_window = 'hanning', window_length = 80): # Extract path, file and extension fname_segmentation = os.path.abspath(fname_segmentation) path_data, file_data, ext_data = sct.extract_fname(fname_segmentation) # 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") + '_'+str(randint(1, 1000000)), 1) sct.run('mkdir '+path_tmp, verbose) # Copying input data to tmp folder sct.printv('\nCopying data to tmp folder...', verbose) sct.run('sct_convert -i '+fname_segmentation+' -o '+path_tmp+'segmentation.nii.gz', verbose) # go to tmp folder os.chdir(path_tmp) # Change orientation of the input centerline into RPI sct.printv('\nOrient centerline to RPI orientation...', verbose) # fname_segmentation_orient = 'segmentation_RPI.nii.gz' # BELOW DOES NOT WORK (JULIEN, 2015-10-17) # im_seg = Image(file_data+ext_data) # set_orientation(im_seg, 'RPI') # im_seg.setFileName(fname_segmentation_orient) # im_seg.save() sct.run('sct_image -i segmentation.nii.gz -setorient RPI -o segmentation_RPI.nii.gz', verbose) # Open segmentation volume sct.printv('\nOpen segmentation volume...', verbose) im_seg = Image('segmentation_RPI.nii.gz') data = im_seg.data # Get size of data sct.printv('\nGet data dimensions...', verbose) nx, ny, nz, nt, px, py, pz, pt = im_seg.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) # # Get dimension # sct.printv('\nGet dimensions...', verbose) # nx, ny, nz, nt, px, py, pz, pt = im_seg.dim # # # Extract orientation of the input segmentation # orientation = get_orientation(im_seg) # sct.printv('\nOrientation of segmentation image: ' + orientation, verbose) # # sct.printv('\nOpen segmentation volume...', verbose) # data = im_seg.data # hdr = im_seg.hdr # Extract min and max index in Z direction X, Y, Z = (data>0).nonzero() min_z_index, max_z_index = min(Z), max(Z) x_centerline = [0 for i in range(0,max_z_index-min_z_index+1)] y_centerline = [0 for i in range(0,max_z_index-min_z_index+1)] z_centerline = [iz for iz in range(min_z_index, max_z_index+1)] # Extract segmentation points and average per slice for iz in range(min_z_index, max_z_index+1): x_seg, y_seg = (data[:,:,iz]>0).nonzero() x_centerline[iz-min_z_index] = np.mean(x_seg) y_centerline[iz-min_z_index] = np.mean(y_seg) for k in range(len(X)): data[X[k], Y[k], Z[k]] = 0 # extract centerline and smooth it x_centerline_fit, y_centerline_fit, z_centerline_fit, x_centerline_deriv, y_centerline_deriv, z_centerline_deriv = smooth_centerline('segmentation_RPI.nii.gz', type_window = type_window, window_length = window_length, algo_fitting = algo_fitting, verbose = verbose) if verbose == 2: import matplotlib.pyplot as plt #Creation of a vector x that takes into account the distance between the labels nz_nonz = len(z_centerline) x_display = [0 for i in range(x_centerline_fit.shape[0])] y_display = [0 for i in range(y_centerline_fit.shape[0])] for i in range(0, nz_nonz, 1): x_display[int(z_centerline[i]-z_centerline[0])] = x_centerline[i] y_display[int(z_centerline[i]-z_centerline[0])] = y_centerline[i] plt.figure(1) plt.subplot(2,1,1) plt.plot(z_centerline_fit, x_display, 'ro') plt.plot(z_centerline_fit, x_centerline_fit) plt.xlabel("Z") plt.ylabel("X") plt.title("x and x_fit coordinates") plt.subplot(2,1,2) plt.plot(z_centerline_fit, y_display, 'ro') plt.plot(z_centerline_fit, y_centerline_fit) plt.xlabel("Z") plt.ylabel("Y") plt.title("y and y_fit coordinates") plt.show() # Create an image with the centerline for iz in range(min_z_index, max_z_index+1): data[round(x_centerline_fit[iz-min_z_index]), round(y_centerline_fit[iz-min_z_index]), iz] = 1 # if index is out of bounds here for hanning: either the segmentation has holes or labels have been added to the file # Write the centerline image in RPI orientation # hdr.set_data_dtype('uint8') # set imagetype to uint8 sct.printv('\nWrite NIFTI volumes...', verbose) im_seg.data = data im_seg.setFileName('centerline_RPI.nii.gz') im_seg.changeType('uint8') im_seg.save() sct.printv('\nSet to original orientation...', verbose) # get orientation of the input data im_seg_original = Image('segmentation.nii.gz') orientation = im_seg_original.orientation sct.run('sct_image -i centerline_RPI.nii.gz -setorient '+orientation+' -o centerline.nii.gz') # create a txt file with the centerline name_output_txt = 'centerline.txt' sct.printv('\nWrite text file...', verbose) file_results = open(name_output_txt, 'w') for i in range(min_z_index, max_z_index+1): file_results.write(str(int(i)) + ' ' + str(x_centerline_fit[i-min_z_index]) + ' ' + str(y_centerline_fit[i-min_z_index]) + '\n') file_results.close() # come back to parent folder os.chdir('..') # Generate output files sct.printv('\nGenerate output files...', verbose) sct.generate_output_file(path_tmp+'centerline.nii.gz', file_data+'_centerline.nii.gz') sct.generate_output_file(path_tmp+'centerline.txt', file_data+'_centerline.txt') # Remove temporary files if remove_temp_files: sct.printv('\nRemove temporary files...', verbose) sct.run('rm -rf '+path_tmp, verbose) return file_data+'_centerline.nii.gz'
zmin_cord = np.min(np.nonzero(zsum)) zmax_cord = np.max(np.nonzero(zsum)) # duplicate WM and GM atlas towards the top and bottom slices to match the cord template # bottom slices for iz in range(zmin_cord, zmin_wm): data_wm[:, :, iz] = data_wm[:, :, zmin_wm] data_gm[:, :, iz] = data_gm[:, :, zmin_wm] # top slices for iz in range(zmax_wm, zmax_cord): data_wm[:, :, iz] = data_wm[:, :, zmax_wm] data_gm[:, :, iz] = data_gm[:, :, zmax_wm] # save modified atlases im_wm.setFileName('wm_ext.nii.gz') im_wm.data = data_wm im_wm.save() im_gm.setFileName('gm_ext.nii.gz') im_gm.data = data_gm im_gm.save() # sum modified wm/gm data_wmgm = data_wm + data_gm # save wm/gm im_wm.setFileName('wmgm_ext.nii.gz') im_wm.data = data_wmgm im_wm.save() # register wmgm --> cord sct.run('cp '+fname_cord+' cord.nii.gz')
def main(args=None): dim_list = ['x', 'y', 'z', 't'] if not args: args = sys.argv[1:] # Get parser info parser = get_parser() arguments = parser.parse(args) fname_in = arguments["-i"] fname_out = arguments["-o"] verbose = int(arguments['-v']) if '-type' in arguments: output_type = arguments['-type'] else: output_type = '' # Open file(s) im = Image(fname_in) data = im.data # 3d or 4d numpy array dim = im.dim # run command if '-otsu' in arguments: param = arguments['-otsu'] data_out = otsu(data, param) elif '-otsu_adap' in arguments: param = arguments['-otsu_adap'] data_out = otsu_adap(data, param[0], param[1]) elif '-otsu_median' in arguments: param = arguments['-otsu_median'] data_out = otsu_median(data, param[0], param[1]) elif '-thr' in arguments: param = arguments['-thr'] data_out = threshold(data, param) elif '-percent' in arguments: param = arguments['-percent'] data_out = perc(data, param) elif '-bin' in arguments: bin_thr = arguments['-bin'] data_out = binarise(data, bin_thr=bin_thr) elif '-add' in arguments: from numpy import sum data2 = get_data_or_scalar(arguments["-add"], data) data_concat = concatenate_along_4th_dimension(data, data2) data_out = sum(data_concat, axis=3) elif '-sub' in arguments: data2 = get_data_or_scalar(arguments['-sub'], data) data_out = data - data2 elif "-laplacian" in arguments: sigmas = arguments["-laplacian"] if len(sigmas) == 1: sigmas = [sigmas for i in range(len(data.shape))] elif len(sigmas) != len(data.shape): printv( parser.usage.generate( error= 'ERROR: -laplacian need the same number of inputs as the number of image dimension OR only one input' )) # adjust sigma based on voxel size sigmas = [sigmas[i] / dim[i + 4] for i in range(3)] # smooth data data_out = laplacian(data, sigmas) elif '-mul' in arguments: from numpy import prod data2 = get_data_or_scalar(arguments["-mul"], data) data_concat = concatenate_along_4th_dimension(data, data2) data_out = prod(data_concat, axis=3) elif '-div' in arguments: from numpy import divide data2 = get_data_or_scalar(arguments["-div"], data) data_out = divide(data, data2) elif '-mean' in arguments: from numpy import mean dim = dim_list.index(arguments['-mean']) if dim + 1 > len( np.shape(data)): # in case input volume is 3d and dim=t data = data[..., np.newaxis] data_out = mean(data, dim) elif '-rms' in arguments: from numpy import mean, sqrt, square dim = dim_list.index(arguments['-rms']) if dim + 1 > len( np.shape(data)): # in case input volume is 3d and dim=t data = data[..., np.newaxis] data_out = sqrt(mean(square(data.astype(float)), dim)) elif '-std' in arguments: from numpy import std dim = dim_list.index(arguments['-std']) if dim + 1 > len( np.shape(data)): # in case input volume is 3d and dim=t data = data[..., np.newaxis] data_out = std(data, dim, ddof=1) elif "-smooth" in arguments: sigmas = arguments["-smooth"] if len(sigmas) == 1: sigmas = [sigmas[0] for i in range(len(data.shape))] elif len(sigmas) != len(data.shape): printv( parser.usage.generate( error= 'ERROR: -smooth need the same number of inputs as the number of image dimension OR only one input' )) # adjust sigma based on voxel size sigmas = [sigmas[i] / dim[i + 4] for i in range(3)] # smooth data data_out = smooth(data, sigmas) elif '-dilate' in arguments: data_out = dilate(data, arguments['-dilate']) elif '-erode' in arguments: data_out = erode(data, arguments['-erode']) elif '-denoise' in arguments: # parse denoising arguments p, b = 1, 5 # default arguments list_denoise = arguments['-denoise'] for i in list_denoise: if 'p' in i: p = int(i.split('=')[1]) if 'b' in i: b = int(i.split('=')[1]) data_out = denoise_nlmeans(data, patch_radius=p, block_radius=b) elif '-symmetrize' in arguments: data_out = (data + data[range(data.shape[0] - 1, -1, -1), :, :]) / float(2) elif '-mi' in arguments: # input 1 = from flag -i --> im # input 2 = from flag -mi im_2 = Image(arguments['-mi']) compute_similarity(im.data, im_2.data, fname_out, metric='mi', verbose=verbose) data_out = None elif '-minorm' in arguments: im_2 = Image(arguments['-minorm']) compute_similarity(im.data, im_2.data, fname_out, metric='minorm', verbose=verbose) data_out = None elif '-corr' in arguments: # input 1 = from flag -i --> im # input 2 = from flag -mi im_2 = Image(arguments['-corr']) compute_similarity(im.data, im_2.data, fname_out, metric='corr', verbose=verbose) data_out = None # if no flag is set else: data_out = None printv( parser.usage.generate( error= 'ERROR: you need to specify an operation to do on the input image' )) if data_out is not None: # Write output nii_out = Image(fname_in) # use header of input file nii_out.data = data_out nii_out.setFileName(fname_out) nii_out.save(type=output_type) # TODO: case of multiple outputs # assert len(data_out) == n_out # if n_in == n_out: # for im_in, d_out, fn_out in zip(nii, data_out, fname_out): # im_in.data = d_out # im_in.setFileName(fn_out) # if "-w" in arguments: # im_in.hdr.set_intent('vector', (), '') # im_in.save() # elif n_out == 1: # nii[0].data = data_out[0] # nii[0].setFileName(fname_out[0]) # if "-w" in arguments: # nii[0].hdr.set_intent('vector', (), '') # nii[0].save() # elif n_out > n_in: # for dat_out, name_out in zip(data_out, fname_out): # im_out = nii[0].copy() # im_out.data = dat_out # im_out.setFileName(name_out) # if "-w" in arguments: # im_out.hdr.set_intent('vector', (), '') # im_out.save() # else: # printv(parser.usage.generate(error='ERROR: not the correct numbers of inputs and outputs')) # display message if data_out is not None: sct.display_viewer_syntax([fname_out]) else: printv('\nDone! File created: ' + fname_out, verbose, 'info')
def register(src, dest, paramreg, param, i_step_str): # initiate default parameters of antsRegistration transformation ants_registration_params = { 'rigid': '', 'affine': '', 'compositeaffine': '', 'similarity': '', 'translation': '', 'bspline': ',10', 'gaussiandisplacementfield': ',3,0', 'bsplinedisplacementfield': ',5,10', 'syn': ',3,0', 'bsplinesyn': ',1,3' } fsloutput = 'export FSLOUTPUTTYPE=NIFTI; ' # for faster processing, all outputs are in NIFTI' # set metricSize if paramreg.steps[i_step_str].metric == 'MI': metricSize = '32' # corresponds to number of bins else: metricSize = '4' # corresponds to radius (for CC, MeanSquares...) # set masking if param.fname_mask: fname_mask = 'mask.nii.gz' masking = '-x mask.nii.gz' else: fname_mask = '' masking = '' if paramreg.steps[i_step_str].algo == 'slicereg': from msct_image import find_zmin_zmax # threshold images (otherwise, automatic crop does not work -- see issue #293) src_th = sct.add_suffix(src, '_th') from msct_image import Image nii = Image(src) data = nii.data data[data < 0.1] = 0 nii.data = data nii.setFileName(src_th) nii.save() # sct.run(fsloutput+'fslmaths '+src+' -thr 0.1 '+src_th, param.verbose) dest_th = sct.add_suffix(dest, '_th') nii = Image(dest) data = nii.data data[data < 0.1] = 0 nii.data = data nii.setFileName(dest_th) nii.save() # sct.run(fsloutput+'fslmaths '+dest+' -thr 0.1 '+dest_th, param.verbose) # find zmin and zmax zmin_src, zmax_src = find_zmin_zmax(src_th) zmin_dest, zmax_dest = find_zmin_zmax(dest_th) zmin_total = max([zmin_src, zmin_dest]) zmax_total = min([zmax_src, zmax_dest]) # crop data src_crop = sct.add_suffix(src, '_crop') sct.run( 'sct_crop_image -i ' + src + ' -o ' + src_crop + ' -dim 2 -start ' + str(zmin_total) + ' -end ' + str(zmax_total), param.verbose) dest_crop = sct.add_suffix(dest, '_crop') sct.run( 'sct_crop_image -i ' + dest + ' -o ' + dest_crop + ' -dim 2 -start ' + str(zmin_total) + ' -end ' + str(zmax_total), param.verbose) # update variables src = src_crop dest = dest_crop # estimate transfo cmd = ( 'isct_antsSliceRegularizedRegistration ' '-t Translation[0.5] ' '-m ' + paramreg.steps[i_step_str].metric + '[' + dest + ',' + src + ',1,' + metricSize + ',Regular,0.2] ' '-p ' + paramreg.steps[i_step_str].poly + ' ' '-i ' + paramreg.steps[i_step_str].iter + ' ' '-f 1 ' '-s ' + paramreg.steps[i_step_str].smooth + ' ' '-v 1 ' # verbose (verbose=2 does not exist, so we force it to 1) '-o [step' + i_step_str + ',' + src + '_regStep' + i_step_str + '.nii] ' # here the warp name is stage10 because antsSliceReg add "Warp" + masking) warp_forward_out = 'step' + i_step_str + 'Warp.nii.gz' warp_inverse_out = 'step' + i_step_str + 'InverseWarp.nii.gz' elif paramreg.steps[i_step_str].algo == 'slicereg2d_pointwise': from msct_register import register_slicereg2d_pointwise warp_forward_out = 'step' + i_step_str + 'Warp.nii.gz' warp_inverse_out = 'step' + i_step_str + 'InverseWarp.nii.gz' register_slicereg2d_pointwise( src, dest, window_length=paramreg.steps[i_step_str].window_length, paramreg=Paramreg(step=paramreg.steps[i_step_str].step, type=paramreg.steps[i_step_str].type, algo='Translation', metric=paramreg.steps[i_step_str].metric, iter=paramreg.steps[i_step_str].iter, shrink=paramreg.steps[i_step_str].shrink, smooth=paramreg.steps[i_step_str].smooth, gradStep=paramreg.steps[i_step_str].gradStep), warp_forward_out=warp_forward_out, warp_inverse_out=warp_inverse_out, factor=param.outlier_factor, verbose=param.verbose) cmd = ('') elif paramreg.steps[i_step_str].algo == 'slicereg2d_translation': from msct_register import register_slicereg2d_translation warp_forward_out = 'step' + i_step_str + 'Warp.nii.gz' warp_inverse_out = 'step' + i_step_str + 'InverseWarp.nii.gz' register_slicereg2d_translation( src, dest, window_length=paramreg.steps[i_step_str].window_length, paramreg=Paramreg(step=paramreg.steps[i_step_str].step, type=paramreg.steps[i_step_str].type, algo='Translation', metric=paramreg.steps[i_step_str].metric, iter=paramreg.steps[i_step_str].iter, shrink=paramreg.steps[i_step_str].shrink, smooth=paramreg.steps[i_step_str].smooth, gradStep=paramreg.steps[i_step_str].gradStep), fname_mask=fname_mask, warp_forward_out=warp_forward_out, warp_inverse_out=warp_inverse_out, factor=param.outlier_factor, remove_temp_files=param.remove_temp_files, verbose=param.verbose, ants_registration_params=ants_registration_params) cmd = ('') elif paramreg.steps[i_step_str].algo == 'slicereg2d_rigid': from msct_register import register_slicereg2d_rigid warp_forward_out = 'step' + i_step_str + 'Warp.nii.gz' warp_inverse_out = 'step' + i_step_str + 'InverseWarp.nii.gz' register_slicereg2d_rigid( src, dest, window_length=paramreg.steps[i_step_str].window_length, paramreg=Paramreg(step=paramreg.steps[i_step_str].step, type=paramreg.steps[i_step_str].type, algo='Rigid', metric=paramreg.steps[i_step_str].metric, iter=paramreg.steps[i_step_str].iter, shrink=paramreg.steps[i_step_str].shrink, smooth=paramreg.steps[i_step_str].smooth, gradStep=paramreg.steps[i_step_str].gradStep), fname_mask=fname_mask, warp_forward_out=warp_forward_out, warp_inverse_out=warp_inverse_out, factor=param.outlier_factor, remove_temp_files=param.remove_temp_files, verbose=param.verbose, ants_registration_params=ants_registration_params) cmd = ('') elif paramreg.steps[i_step_str].algo == 'slicereg2d_affine': from msct_register import register_slicereg2d_affine warp_forward_out = 'step' + i_step_str + 'Warp.nii.gz' warp_inverse_out = 'step' + i_step_str + 'InverseWarp.nii.gz' register_slicereg2d_affine( src, dest, window_length=paramreg.steps[i_step_str].window_length, paramreg=Paramreg(step=paramreg.steps[i_step_str].step, type=paramreg.steps[i_step_str].type, algo='Affine', metric=paramreg.steps[i_step_str].metric, iter=paramreg.steps[i_step_str].iter, shrink=paramreg.steps[i_step_str].shrink, smooth=paramreg.steps[i_step_str].smooth, gradStep=paramreg.steps[i_step_str].gradStep), fname_mask=fname_mask, warp_forward_out=warp_forward_out, warp_inverse_out=warp_inverse_out, factor=param.outlier_factor, remove_temp_files=param.remove_temp_files, verbose=param.verbose, ants_registration_params=ants_registration_params) cmd = ('') elif paramreg.steps[i_step_str].algo == 'slicereg2d_syn': from msct_register import register_slicereg2d_syn warp_forward_out = 'step' + i_step_str + 'Warp.nii.gz' warp_inverse_out = 'step' + i_step_str + 'InverseWarp.nii.gz' register_slicereg2d_syn( src, dest, window_length=paramreg.steps[i_step_str].window_length, paramreg=Paramreg(step=paramreg.steps[i_step_str].step, type=paramreg.steps[i_step_str].type, algo='SyN', metric=paramreg.steps[i_step_str].metric, iter=paramreg.steps[i_step_str].iter, shrink=paramreg.steps[i_step_str].shrink, smooth=paramreg.steps[i_step_str].smooth, gradStep=paramreg.steps[i_step_str].gradStep), fname_mask=fname_mask, warp_forward_out=warp_forward_out, warp_inverse_out=warp_inverse_out, factor=param.outlier_factor, remove_temp_files=param.remove_temp_files, verbose=param.verbose, ants_registration_params=ants_registration_params) cmd = ('') elif paramreg.steps[i_step_str].algo == 'slicereg2d_bsplinesyn': from msct_register import register_slicereg2d_bsplinesyn warp_forward_out = 'step' + i_step_str + 'Warp.nii.gz' warp_inverse_out = 'step' + i_step_str + 'InverseWarp.nii.gz' register_slicereg2d_bsplinesyn( src, dest, window_length=paramreg.steps[i_step_str].window_length, paramreg=Paramreg(step=paramreg.steps[i_step_str].step, type=paramreg.steps[i_step_str].type, algo='BSplineSyN', metric=paramreg.steps[i_step_str].metric, iter=paramreg.steps[i_step_str].iter, shrink=paramreg.steps[i_step_str].shrink, smooth=paramreg.steps[i_step_str].smooth, gradStep=paramreg.steps[i_step_str].gradStep), fname_mask=fname_mask, warp_forward_out=warp_forward_out, warp_inverse_out=warp_inverse_out, factor=param.outlier_factor, remove_temp_files=param.remove_temp_files, verbose=param.verbose, ants_registration_params=ants_registration_params) cmd = ('') elif paramreg.steps[i_step_str].algo.lower() in ants_registration_params: from msct_image import pad_image # Pad the destination image (because ants doesn't deform the extremities) # N.B. no need to pad if iter = 0 if not paramreg.steps[i_step_str].iter == '0': dest_pad = sct.add_suffix(dest, '_pad') pad_image(dest, dest_pad, param.padding) dest = dest_pad cmd = ( 'isct_antsRegistration ' '--dimensionality 3 ' '--transform ' + paramreg.steps[i_step_str].algo + '[' + paramreg.steps[i_step_str].gradStep + ants_registration_params[paramreg.steps[i_step_str].algo.lower()] + '] ' '--metric ' + paramreg.steps[i_step_str].metric + '[' + dest + ',' + src + ',1,' + metricSize + '] ' '--convergence ' + paramreg.steps[i_step_str].iter + ' ' '--shrink-factors ' + paramreg.steps[i_step_str].shrink + ' ' '--smoothing-sigmas ' + paramreg.steps[i_step_str].smooth + 'mm ' '--restrict-deformation 1x1x0 ' '--output [step' + i_step_str + ',' + src + '_regStep' + i_step_str + '.nii] ' '--interpolation BSpline[3] ' + masking) if param.verbose >= 1: cmd += ' --verbose 1' if paramreg.steps[i_step_str].algo in ['rigid', 'affine']: warp_forward_out = 'step' + i_step_str + '0GenericAffine.mat' warp_inverse_out = '-step' + i_step_str + '0GenericAffine.mat' else: warp_forward_out = 'step' + i_step_str + '0Warp.nii.gz' warp_inverse_out = 'step' + i_step_str + '0InverseWarp.nii.gz' else: sct.printv( '\nERROR: algo ' + paramreg.steps[i_step_str].algo + ' does not exist. Exit program\n', 1, 'error') # run registration status, output = sct.run(cmd, param.verbose) if os.path.isfile(warp_forward_out): # rename warping fields if paramreg.steps[i_step_str].algo in ['rigid', 'affine']: warp_forward = 'warp_forward_' + i_step_str + '.mat' os.rename(warp_forward_out, warp_forward) warp_inverse = '-warp_forward_' + i_step_str + '.mat' else: warp_forward = 'warp_forward_' + i_step_str + '.nii.gz' warp_inverse = 'warp_inverse_' + i_step_str + '.nii.gz' os.rename(warp_forward_out, warp_forward) os.rename(warp_inverse_out, warp_inverse) else: sct.printv(output, 1, 'error') sct.printv('\nERROR: ANTs failed. Exit program.\n', 1, 'error') return warp_forward, warp_inverse
def main(args=None): # Initialization # fname_anat = '' # fname_centerline = '' sigma = 3 # default value of the standard deviation for the Gaussian smoothing (in terms of number of voxels) # remove_temp_files = param.remove_temp_files # verbose = param.verbose start_time = time.time() parser = get_parser() arguments = parser.parse(sys.argv[1:]) fname_anat = arguments['-i'] fname_centerline = arguments['-s'] if '-smooth' in arguments: sigma = arguments['-smooth'] if '-r' in arguments: remove_temp_files = int(arguments['-r']) if '-v' in arguments: verbose = int(arguments['-v']) # Display arguments sct.printv('\nCheck input arguments...') sct.printv(' Volume to smooth .................. ' + fname_anat) sct.printv(' Centerline ........................ ' + fname_centerline) sct.printv(' Sigma (mm) ........................ ' + str(sigma)) sct.printv(' Verbose ........................... ' + str(verbose)) # Check that input is 3D: from msct_image import Image nx, ny, nz, nt, px, py, pz, pt = Image(fname_anat).dim dim = 4 # by default, will be adjusted later if nt == 1: dim = 3 if nz == 1: dim = 2 if dim == 4: sct.printv( 'WARNING: the input image is 4D, please split your image to 3D before smoothing spinalcord using :\n' 'sct_image -i ' + fname_anat + ' -split t -o ' + fname_anat, verbose, 'warning') sct.printv('4D images not supported, aborting ...', verbose, 'error') # Extract path/file/extension path_anat, file_anat, ext_anat = sct.extract_fname(fname_anat) path_centerline, file_centerline, ext_centerline = sct.extract_fname( fname_centerline) # create temporary folder sct.printv('\nCreate temporary folder...', verbose) path_tmp = sct.slash_at_the_end('tmp.' + time.strftime("%y%m%d%H%M%S"), 1) sct.run('mkdir ' + path_tmp, verbose) # Copying input data to tmp folder sct.printv('\nCopying input data to tmp folder and convert to nii...', verbose) sct.run('cp ' + fname_anat + ' ' + path_tmp + 'anat' + ext_anat, verbose) sct.run( 'cp ' + fname_centerline + ' ' + path_tmp + 'centerline' + ext_centerline, verbose) # go to tmp folder os.chdir(path_tmp) # convert to nii format convert('anat' + ext_anat, 'anat.nii') convert('centerline' + ext_centerline, 'centerline.nii') # Change orientation of the input image into RPI sct.printv('\nOrient input volume to RPI orientation...') fname_anat_rpi = set_orientation('anat.nii', 'RPI', filename=True) move(fname_anat_rpi, 'anat_rpi.nii') # Change orientation of the input image into RPI sct.printv('\nOrient centerline to RPI orientation...') fname_centerline_rpi = set_orientation('centerline.nii', 'RPI', filename=True) move(fname_centerline_rpi, 'centerline_rpi.nii') # Straighten the spinal cord # straighten segmentation sct.printv('\nStraighten the spinal cord using centerline/segmentation...', verbose) # check if warp_curve2straight and warp_straight2curve already exist (i.e. no need to do it another time) if os.path.isfile('../warp_curve2straight.nii.gz') and os.path.isfile( '../warp_straight2curve.nii.gz') and os.path.isfile( '../straight_ref.nii.gz'): # if they exist, copy them into current folder sct.printv( 'WARNING: Straightening was already run previously. Copying warping fields...', verbose, 'warning') shutil.copy('../warp_curve2straight.nii.gz', 'warp_curve2straight.nii.gz') shutil.copy('../warp_straight2curve.nii.gz', 'warp_straight2curve.nii.gz') shutil.copy('../straight_ref.nii.gz', 'straight_ref.nii.gz') # apply straightening sct.run( 'sct_apply_transfo -i anat_rpi.nii -w warp_curve2straight.nii.gz -d straight_ref.nii.gz -o anat_rpi_straight.nii -x spline', verbose) else: sct.run( 'sct_straighten_spinalcord -i anat_rpi.nii -s centerline_rpi.nii -qc 0 -x spline', verbose) # Smooth the straightened image along z sct.printv('\nSmooth the straightened image along z...') sct.run( 'sct_maths -i anat_rpi_straight.nii -smooth 0,0,' + str(sigma) + ' -o anat_rpi_straight_smooth.nii', verbose) # Apply the reversed warping field to get back the curved spinal cord sct.printv( '\nApply the reversed warping field to get back the curved spinal cord...' ) sct.run( 'sct_apply_transfo -i anat_rpi_straight_smooth.nii -o anat_rpi_straight_smooth_curved.nii -d anat.nii -w warp_straight2curve.nii.gz -x spline', verbose) # replace zeroed voxels by original image (issue #937) sct.printv('\nReplace zeroed voxels by original image...', verbose) nii_smooth = Image('anat_rpi_straight_smooth_curved.nii') data_smooth = nii_smooth.data data_input = Image('anat.nii').data indzero = np.where(data_smooth == 0) data_smooth[indzero] = data_input[indzero] nii_smooth.data = data_smooth nii_smooth.setFileName('anat_rpi_straight_smooth_curved_nonzero.nii') nii_smooth.save() # come back to parent folder os.chdir('..') # Generate output file sct.printv('\nGenerate output file...') sct.generate_output_file( path_tmp + '/anat_rpi_straight_smooth_curved_nonzero.nii', file_anat + '_smooth' + ext_anat) # Remove temporary files if remove_temp_files == 1: sct.printv('\nRemove temporary files...') 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\n') # to view results sct.printv('Done! To view results, type:', verbose) sct.printv('fslview ' + file_anat + ' ' + file_anat + '_smooth &\n', verbose, 'info')
def register(src, dest, paramreg, param, i_step_str): # initiate default parameters of antsRegistration transformation ants_registration_params = { 'rigid': '', 'affine': '', 'compositeaffine': '', 'similarity': '', 'translation': '', 'bspline': ',10', 'gaussiandisplacementfield': ',3,0', 'bsplinedisplacementfield': ',5,10', 'syn': ',3,0', 'bsplinesyn': ',1,3' } output = '' # default output if problem # display arguments sct.printv('Registration parameters:', param.verbose) sct.printv(' type ........... ' + paramreg.steps[i_step_str].type, param.verbose) sct.printv(' algo ........... ' + paramreg.steps[i_step_str].algo, param.verbose) sct.printv(' slicewise ...... ' + paramreg.steps[i_step_str].slicewise, param.verbose) sct.printv(' metric ......... ' + paramreg.steps[i_step_str].metric, param.verbose) sct.printv(' iter ........... ' + paramreg.steps[i_step_str].iter, param.verbose) sct.printv(' smooth ......... ' + paramreg.steps[i_step_str].smooth, param.verbose) sct.printv(' laplacian ...... ' + paramreg.steps[i_step_str].laplacian, param.verbose) sct.printv(' shrink ......... ' + paramreg.steps[i_step_str].shrink, param.verbose) sct.printv(' gradStep ....... ' + paramreg.steps[i_step_str].gradStep, param.verbose) sct.printv(' deformation .... ' + paramreg.steps[i_step_str].deformation, param.verbose) sct.printv(' init ........... ' + paramreg.steps[i_step_str].init, param.verbose) sct.printv(' poly ........... ' + paramreg.steps[i_step_str].poly, param.verbose) sct.printv(' dof ............ ' + paramreg.steps[i_step_str].dof, param.verbose) sct.printv(' smoothWarpXY ... ' + paramreg.steps[i_step_str].smoothWarpXY, param.verbose) # set metricSize if paramreg.steps[i_step_str].metric == 'MI': metricSize = '32' # corresponds to number of bins else: metricSize = '4' # corresponds to radius (for CC, MeanSquares...) # set masking if param.fname_mask: fname_mask = 'mask.nii.gz' masking = '-x mask.nii.gz' else: fname_mask = '' masking = '' if paramreg.steps[i_step_str].algo == 'slicereg': # check if user used type=label if paramreg.steps[i_step_str].type == 'label': sct.printv( '\nERROR: this algo is not compatible with type=label. Please use type=im or type=seg', 1, 'error') else: from msct_image import find_zmin_zmax # threshold images (otherwise, automatic crop does not work -- see issue #293) src_th = sct.add_suffix(src, '_th') from msct_image import Image nii = Image(src) data = nii.data data[data < 0.1] = 0 nii.data = data nii.setFileName(src_th) nii.save() # sct.run(fsloutput+'fslmaths '+src+' -thr 0.1 '+src_th, param.verbose) dest_th = sct.add_suffix(dest, '_th') nii = Image(dest) data = nii.data data[data < 0.1] = 0 nii.data = data nii.setFileName(dest_th) nii.save() # sct.run(fsloutput+'fslmaths '+dest+' -thr 0.1 '+dest_th, param.verbose) # find zmin and zmax zmin_src, zmax_src = find_zmin_zmax(src_th) zmin_dest, zmax_dest = find_zmin_zmax(dest_th) zmin_total = max([zmin_src, zmin_dest]) zmax_total = min([zmax_src, zmax_dest]) # crop data src_crop = sct.add_suffix(src, '_crop') sct.run( 'sct_crop_image -i ' + src + ' -o ' + src_crop + ' -dim 2 -start ' + str(zmin_total) + ' -end ' + str(zmax_total), param.verbose) dest_crop = sct.add_suffix(dest, '_crop') sct.run( 'sct_crop_image -i ' + dest + ' -o ' + dest_crop + ' -dim 2 -start ' + str(zmin_total) + ' -end ' + str(zmax_total), param.verbose) # update variables src = src_crop dest = dest_crop scr_regStep = sct.add_suffix(src, '_regStep' + i_step_str) # estimate transfo cmd = ( 'isct_antsSliceRegularizedRegistration ' '-t Translation[' + paramreg.steps[i_step_str].gradStep + '] ' '-m ' + paramreg.steps[i_step_str].metric + '[' + dest + ',' + src + ',1,' + metricSize + ',Regular,0.2] ' '-p ' + paramreg.steps[i_step_str].poly + ' ' '-i ' + paramreg.steps[i_step_str].iter + ' ' '-f ' + paramreg.steps[i_step_str].shrink + ' ' '-s ' + paramreg.steps[i_step_str].smooth + ' ' '-v 1 ' # verbose (verbose=2 does not exist, so we force it to 1) '-o [step' + i_step_str + ',' + scr_regStep + '] ' # here the warp name is stage10 because antsSliceReg add "Warp" + masking) warp_forward_out = 'step' + i_step_str + 'Warp.nii.gz' warp_inverse_out = 'step' + i_step_str + 'InverseWarp.nii.gz' # run command status, output = sct.run(cmd, param.verbose) # ANTS 3d elif paramreg.steps[i_step_str].algo.lower( ) in ants_registration_params and paramreg.steps[ i_step_str].slicewise == '0': # make sure type!=label. If type==label, this will be addressed later in the code. if not paramreg.steps[i_step_str].type == 'label': # Pad the destination image (because ants doesn't deform the extremities) # N.B. no need to pad if iter = 0 if not paramreg.steps[i_step_str].iter == '0': dest_pad = sct.add_suffix(dest, '_pad') sct.run('sct_image -i ' + dest + ' -o ' + dest_pad + ' -pad 0,0,' + str(param.padding)) dest = dest_pad # apply Laplacian filter if not paramreg.steps[i_step_str].laplacian == '0': sct.printv('\nApply Laplacian filter', param.verbose) sct.run('sct_maths -i ' + src + ' -laplacian ' + paramreg.steps[i_step_str].laplacian + ',' + paramreg.steps[i_step_str].laplacian + ',0 -o ' + sct.add_suffix(src, '_laplacian')) sct.run('sct_maths -i ' + dest + ' -laplacian ' + paramreg.steps[i_step_str].laplacian + ',' + paramreg.steps[i_step_str].laplacian + ',0 -o ' + sct.add_suffix(dest, '_laplacian')) src = sct.add_suffix(src, '_laplacian') dest = sct.add_suffix(dest, '_laplacian') # Estimate transformation sct.printv('\nEstimate transformation', param.verbose) scr_regStep = sct.add_suffix(src, '_regStep' + i_step_str) cmd = ('isct_antsRegistration ' '--dimensionality 3 ' '--transform ' + paramreg.steps[i_step_str].algo + '[' + paramreg.steps[i_step_str].gradStep + ants_registration_params[ paramreg.steps[i_step_str].algo.lower()] + '] ' '--metric ' + paramreg.steps[i_step_str].metric + '[' + dest + ',' + src + ',1,' + metricSize + '] ' '--convergence ' + paramreg.steps[i_step_str].iter + ' ' '--shrink-factors ' + paramreg.steps[i_step_str].shrink + ' ' '--smoothing-sigmas ' + paramreg.steps[i_step_str].smooth + 'mm ' '--restrict-deformation ' + paramreg.steps[i_step_str].deformation + ' ' '--output [step' + i_step_str + ',' + scr_regStep + '] ' '--interpolation BSpline[3] ' '--verbose 1 ' + masking) # add init translation if not paramreg.steps[i_step_str].init == '': init_dict = { 'geometric': '0', 'centermass': '1', 'origin': '2' } cmd += ' -r [' + dest + ',' + src + ',' + init_dict[ paramreg.steps[i_step_str].init] + ']' # run command status, output = sct.run(cmd, param.verbose) # get appropriate file name for transformation if paramreg.steps[i_step_str].algo in [ 'rigid', 'affine', 'translation' ]: warp_forward_out = 'step' + i_step_str + '0GenericAffine.mat' warp_inverse_out = '-step' + i_step_str + '0GenericAffine.mat' else: warp_forward_out = 'step' + i_step_str + '0Warp.nii.gz' warp_inverse_out = 'step' + i_step_str + '0InverseWarp.nii.gz' # ANTS 2d elif paramreg.steps[i_step_str].algo.lower( ) in ants_registration_params and paramreg.steps[ i_step_str].slicewise == '1': # make sure type!=label. If type==label, this will be addressed later in the code. if not paramreg.steps[i_step_str].type == 'label': from msct_register import register_slicewise # if shrink!=1, force it to be 1 (otherwise, it generates a wrong 3d warping field). TODO: fix that! if not paramreg.steps[i_step_str].shrink == '1': sct.printv( '\nWARNING: when using slicewise with SyN or BSplineSyN, shrink factor needs to be one. Forcing shrink=1.', 1, 'warning') paramreg.steps[i_step_str].shrink = '1' warp_forward_out = 'step' + i_step_str + 'Warp.nii.gz' warp_inverse_out = 'step' + i_step_str + 'InverseWarp.nii.gz' register_slicewise( src, dest, paramreg=paramreg.steps[i_step_str], fname_mask=fname_mask, warp_forward_out=warp_forward_out, warp_inverse_out=warp_inverse_out, ants_registration_params=ants_registration_params, path_qc=param.path_qc, verbose=param.verbose) # slice-wise transfo elif paramreg.steps[i_step_str].algo in [ 'centermass', 'centermassrot', 'columnwise' ]: # if type=im, sends warning if paramreg.steps[i_step_str].type == 'im': sct.printv( '\nWARNING: algo ' + paramreg.steps[i_step_str].algo + ' should be used with type=seg.\n', 1, 'warning') # if type=label, exit with error elif paramreg.steps[i_step_str].type == 'label': sct.printv( '\nERROR: this algo is not compatible with type=label. Please use type=im or type=seg', 1, 'error') # check if user provided a mask-- if so, inform it will be ignored if not fname_mask == '': sct.printv( '\nWARNING: algo ' + paramreg.steps[i_step_str].algo + ' will ignore the provided mask.\n', 1, 'warning') # smooth data if not paramreg.steps[i_step_str].smooth == '0': sct.printv('\nSmooth data', param.verbose) sct.run('sct_maths -i ' + src + ' -smooth ' + paramreg.steps[i_step_str].smooth + ',' + paramreg.steps[i_step_str].smooth + ',0 -o ' + sct.add_suffix(src, '_smooth')) sct.run('sct_maths -i ' + dest + ' -smooth ' + paramreg.steps[i_step_str].smooth + ',' + paramreg.steps[i_step_str].smooth + ',0 -o ' + sct.add_suffix(dest, '_smooth')) src = sct.add_suffix(src, '_smooth') dest = sct.add_suffix(dest, '_smooth') from msct_register import register_slicewise warp_forward_out = 'step' + i_step_str + 'Warp.nii.gz' warp_inverse_out = 'step' + i_step_str + 'InverseWarp.nii.gz' register_slicewise(src, dest, paramreg=paramreg.steps[i_step_str], fname_mask=fname_mask, warp_forward_out=warp_forward_out, warp_inverse_out=warp_inverse_out, ants_registration_params=ants_registration_params, path_qc=param.path_qc, verbose=param.verbose) else: sct.printv( '\nERROR: algo ' + paramreg.steps[i_step_str].algo + ' does not exist. Exit program\n', 1, 'error') # landmark-based registration if paramreg.steps[i_step_str].type in ['label']: # check if user specified ilabel and dlabel # TODO warp_forward_out = 'step' + i_step_str + '0GenericAffine.txt' warp_inverse_out = '-step' + i_step_str + '0GenericAffine.txt' from msct_register_landmarks import register_landmarks register_landmarks(src, dest, paramreg.steps[i_step_str].dof, fname_affine=warp_forward_out, verbose=param.verbose, path_qc=param.path_qc) if not os.path.isfile(warp_forward_out): # no forward warping field for rigid and affine sct.printv( '\nERROR: file ' + warp_forward_out + ' doesn\'t exist (or is not a file).\n' + output + '\nERROR: ANTs failed. Exit program.\n', 1, 'error') elif not os.path.isfile( warp_inverse_out) and paramreg.steps[i_step_str].algo not in [ 'rigid', 'affine', 'translation' ] and paramreg.steps[i_step_str].type not in ['label']: # no inverse warping field for rigid and affine sct.printv( '\nERROR: file ' + warp_inverse_out + ' doesn\'t exist (or is not a file).\n' + output + '\nERROR: ANTs failed. Exit program.\n', 1, 'error') else: # rename warping fields if (paramreg.steps[i_step_str].algo.lower() in ['rigid', 'affine', 'translation'] and paramreg.steps[i_step_str].slicewise == '0'): # if ANTs is used with affine/rigid --> outputs .mat file warp_forward = 'warp_forward_' + i_step_str + '.mat' os.rename(warp_forward_out, warp_forward) warp_inverse = '-warp_forward_' + i_step_str + '.mat' elif paramreg.steps[i_step_str].type in ['label']: # if label-based registration is used --> outputs .txt file warp_forward = 'warp_forward_' + i_step_str + '.txt' os.rename(warp_forward_out, warp_forward) warp_inverse = '-warp_forward_' + i_step_str + '.txt' else: warp_forward = 'warp_forward_' + i_step_str + '.nii.gz' warp_inverse = 'warp_inverse_' + i_step_str + '.nii.gz' os.rename(warp_forward_out, warp_forward) os.rename(warp_inverse_out, warp_inverse) return warp_forward, warp_inverse
#!/usr/bin/env python # change type of template data import os import commands import sys from shutil import move # Get path of the toolbox status, path_sct = commands.getstatusoutput('echo $SCT_DIR') # Append path that contains scripts, to be able to load modules sys.path.append(path_sct + '/scripts') from msct_image import Image import sct_utils as sct path_template = '/Users/julien/data/PAM50/template' folder_PAM50 = 'PAM50/template/' os.chdir(path_template) sct.create_folder(folder_PAM50) for file_template in ['MNI-Poly-AMU_T1.nii.gz', 'MNI-Poly-AMU_T2.nii.gz', 'MNI-Poly-AMU_T2star.nii.gz']: im = Image(file_template) # remove negative values data = im.data data[data<0] = 0 im.data = data im.changeType('uint16') file_new = file_template.replace('MNI-Poly-AMU', 'PAM50') im.setFileName(file_new) im.save() # move to folder move(file_new, folder_PAM50+file_new)
def wm_registration(param, smooth=False, init=False): path, fixed_name, ext = sct.extract_fname(param.fname_fixed) path_moving, moving_name, ext = sct.extract_fname(param.fname_moving) path, fixed_seg_name, ext = sct.extract_fname(param.fname_seg_fixed) path_moving_seg, moving_seg_name, ext = sct.extract_fname(param.fname_seg_moving) # cropping in x & y directions fixed_name_temp = fixed_name + "_crop" cmd = "sct_crop_image -i " + fixed_name + ext + " -o " + fixed_name_temp + ext + " -m " + fixed_seg_name + ext + " -shift 5,5 -dim 0,1" sct.run(cmd) fixed_name = fixed_name_temp fixed_seg_name_temp = fixed_seg_name+"_crop" sct.run("sct_crop_image -i " + fixed_seg_name + ext + " -o " + fixed_seg_name_temp + ext + " -m " + fixed_seg_name + ext + " -shift 5,5 -dim 0,1") fixed_seg_name = fixed_seg_name_temp # padding the images moving_name_pad = moving_name+"_pad" fixed_name_pad = fixed_name+"_pad" sct.run('sct_maths -i '+path_moving+moving_name+ext+' -o '+moving_name_pad+ext+' -pad 0,0,'+str(param.padding)) sct.run('sct_maths -i '+fixed_name+ext+' -o '+fixed_name_pad+ext+' -pad 0,0,'+str(param.padding)) moving_name = moving_name_pad fixed_name = fixed_name_pad moving_seg_name_pad = moving_seg_name+"_pad" sct.run('sct_maths -i '+path_moving_seg+moving_seg_name+ext+' -o '+moving_seg_name_pad+ext+' -pad 0,0,'+str(param.padding)) moving_seg_name = moving_seg_name_pad fixed_seg_name_pad = fixed_seg_name+"_pad" sct.run('sct_maths -i '+fixed_seg_name+ext+' -o '+fixed_seg_name_pad+ext+' -pad 0,0,'+str(param.padding)) fixed_seg_name = fixed_seg_name_pad if param.metric == 'MeanSquares': # offset old_min = 0 old_max = 1 new_min = 100 new_max = 200 fixed_im = Image(fixed_name+ext) fixed_im.data = (fixed_im.data - old_min)*(new_max - new_min)/(old_max - old_min) + new_min fixed_im.save() moving_im = Image(moving_name+ext) moving_im.data = (moving_im.data - old_min)*(new_max - new_min)/(old_max - old_min) + new_min moving_im.save() if smooth: # smoothing the images to register sct.printv('\nSmoothing the images...', verbose, 'normal') fixed_smooth = fixed_name+'_smooth' moving_smooth = moving_name+'_smooth' sct.run('sct_maths -i '+fixed_name+ext+' -smooth 1 -o '+fixed_smooth+ext) sct.run('sct_maths -i '+moving_name+ext+' -smooth 1 -o '+moving_smooth+ext) fixed_name = fixed_smooth moving_name = moving_smooth # registration of the gray matter sct.printv('\nDeforming the image...', verbose, 'normal') moving_name_reg = moving_name+"_deformed" param_multimodal_reg = 'step=1,type=seg,algo=slicereg,metric=MeanSquares:step=2,type=im,algo=bsplinesyn,metric=MeanSquares,iter=5,shrink=2' if param.transformation == 'BSplineSyN': transfo_params = ',3,0' elif param.transformation == 'SyN': # SyN gives bad results... transfo_params = ',1,1' else: transfo_params = '' cmd = 'sct_register_multimodal -i '+moving_name+ext+' -d '+fixed_name+ext+' -iseg '+moving_seg_name+ext+' -dseg '+fixed_seg_name+ext+' -p '+param_multimodal_reg+' -o '+moving_name_reg ext_multimodal = '.nii' ''' cmd = 'isct_antsRegistration --dimensionality 3 --interpolation '+param.interpolation+' --transform '+param.transformation+'['+param.gradient_step+transfo_params+'] --metric '+param.metric+'['+fixed_name+ext+','+moving_name+ext+',1,4] --output ['+moving_name_reg+','+moving_name_reg+ext+'] --convergence '+param.iteration+' --shrink-factors 1x1 --smoothing-sigmas 0x0 ' if init: # initialize the transformation using the intensity cmd += ' -r ['+fixed_name+ext+','+moving_name+ext+',1] ' cmd += " --masks ["+fixed_seg_name+ext+","+moving_seg_name + ext + "]" # cmd += " -m ["+fixed_seg_name+".nii,"+moving_seg_name+".nii]" ''' sct.run(cmd) if init: # transform the .mat warping field into a nifti file: warp0_mat = moving_name_reg+'0GenericAffine.mat' warp0, warp0_inv = transform_mat_to_warp(warp0_mat, moving_name_reg+ext, fixed_name+ext) if param.transformation == 'Affine': warp_tot = warp0 inverse_warp_tot = warp0_inv else: warp1 = moving_name_reg+'1Warp.nii.gz' warp1_inv = moving_name_reg+'1InverseWarp.nii.gz' # Concatenate the warping fields from the 2 steps into a warp total and an inverse warp_tot = moving_name_reg+'_warp_tot'+ext inverse_warp_tot = moving_name_reg+'_inverse_warp_tot'+ext sct.run('sct_concat_transfo -w '+warp0+','+warp1+' -d '+fixed_name+ext+' -o '+warp_tot) sct.run('sct_concat_transfo -w '+warp1_inv+','+warp0_inv+' -d '+moving_name+ext+' -o '+inverse_warp_tot) else: warp_tot = moving_name_reg+'0Warp.nii.gz' inverse_warp_tot = moving_name_reg+'0InverseWarp.nii.gz' if param.metric == 'MeanSquares': # removing offset fixed_im = Image(fixed_name+ext) fixed_im.data = (fixed_im.data - new_min)*(old_max - old_min)/(new_max - new_min) + old_min fixed_im.save() moving_im = Image(moving_name_reg+ext_multimodal) moving_im.data = (moving_im.data - new_min)*(old_max - old_min)/(new_max - new_min) + old_min moving_im.save() # un-padding the images moving_name_unpad = moving_name_reg+"_unpadded" fixed_name_unpad = fixed_name+"_unpadded" sct.run("sct_crop_image -i "+moving_name_reg+ext+" -dim 2 -start "+str(int(param.padding))+" -end -"+param.padding+" -o "+moving_name_unpad+ext) sct.run("sct_crop_image -i "+fixed_name+ext+" -dim 2 -start "+str(int(param.padding))+" -end -"+param.padding+" -o "+fixed_name_unpad+ext) ''' # warp_tot = moving_name_reg+"0Warp.nii.gz" # inverse_warp_tot = moving_name_reg+"0InverseWarp.nii.gz" warp_unpad = sct.add_suffix(warp_tot, '_unpad') # moving_name_reg+"0Warp_unpad.nii.gz" inverse_warp_unpad = sct.add_suffix(inverse_warp_tot, '_unpad') # moving_name_reg+"0InverseWarp_unpad.nii.gz" sct.run("sct_crop_image -i "+warp_tot+" -dim 2 -start "+str(int(param.padding))+" -end -"+param.padding+" -o "+warp_unpad) sct.run("sct_crop_image -i "+inverse_warp_tot+" -dim 2 -start "+str(int(param.padding))+" -end -"+param.padding+" -o "+inverse_warp_unpad) ''' path_output, file_output, ext_output = sct.extract_fname(param.fname_output) warp_output = file_output+"_Warp"+ext_output inverse_warp_output = file_output+"_InverseWarp"+ext_output # with multimodal_reg sct.run("mv warp_"+moving_name+"2"+fixed_name+".nii.gz "+warp_output) sct.run("mv warp_"+fixed_name+"2"+moving_name+".nii.gz "+inverse_warp_output) ''' # with antsReg sct.run("mv "+warp_unpad+" "+warp_output) sct.run("mv "+inverse_warp_unpad+" "+inverse_warp_output) ''' moving_name_out = file_output+ext_output # put the result and the reference in the same space using a registration with ANTs with no iteration: sct.run('isct_antsRegistration -d 3 -t Translation[0] -m MI['+fixed_name_unpad+ext+','+moving_name_unpad+ext+',1,16] -o [regAffine,'+moving_name_out+'] -n BSpline[3] -c 0 -f 1 -s 0') return warp_output, inverse_warp_output
def dmri_moco(param): file_data = 'dmri' ext_data = '.nii' file_b0 = 'b0' file_dwi = 'dwi' mat_final = 'mat_final/' file_dwi_group = 'dwi_averaged_groups' # no extension fsloutput = 'export FSLOUTPUTTYPE=NIFTI; ' # for faster processing, all outputs are in NIFTI ext_mat = 'Warp.nii.gz' # warping field # Get dimensions of data sct.printv('\nGet dimensions of data...', param.verbose) nx, ny, nz, nt, px, py, pz, pt = Image(file_data + '.nii').dim sct.printv(' ' + str(nx) + ' x ' + str(ny) + ' x ' + str(nz), param.verbose) # Identify b=0 and DWI images sct.printv('\nIdentify b=0 and DWI images...', param.verbose) index_b0, index_dwi, nb_b0, nb_dwi = identify_b0('bvecs.txt', param.fname_bvals, param.bval_min, param.verbose) # check if dmri and bvecs are the same size if not nb_b0 + nb_dwi == nt: sct.printv( '\nERROR in ' + os.path.basename(__file__) + ': Size of data (' + str(nt) + ') and size of bvecs (' + str(nb_b0 + nb_dwi) + ') are not the same. Check your bvecs file.\n', 1, 'error') sys.exit(2) # Prepare NIFTI (mean/groups...) #=================================================================================================================== # Split into T dimension sct.printv('\nSplit along T dimension...', param.verbose) status, output = sct.run( 'sct_split_data -i ' + file_data + ext_data + ' -dim t -suffix _T', param.verbose) # Merge b=0 images sct.printv('\nMerge b=0...', param.verbose) # cmd = fsloutput + 'fslmerge -t ' + file_b0 # for it in range(nb_b0): # cmd = cmd + ' ' + file_data + '_T' + str(index_b0[it]).zfill(4) cmd = 'sct_concat_data -dim t -o ' + file_b0 + ext_data + ' -i ' for it in range(nb_b0): cmd = cmd + file_data + '_T' + str( index_b0[it]).zfill(4) + ext_data + ',' cmd = cmd[:-1] # remove ',' at the end of the string status, output = sct.run(cmd, param.verbose) sct.printv((' File created: ' + file_b0), param.verbose) # Average b=0 images sct.printv('\nAverage b=0...', param.verbose) file_b0_mean = file_b0 + '_mean' sct.run( 'sct_maths -i ' + file_b0 + '.nii' + ' -o ' + file_b0_mean + '.nii' + ' -mean t', param.verbose) # if not average_data_across_dimension(file_b0+'.nii', file_b0_mean+'.nii', 3): # sct.printv('ERROR in average_data_across_dimension', 1, 'error') # cmd = fsloutput + 'fslmaths ' + file_b0 + ' -Tmean ' + file_b0_mean # status, output = sct.run(cmd, param.verbose) # Number of DWI groups nb_groups = int(math.floor(nb_dwi / param.group_size)) # Generate groups indexes group_indexes = [] for iGroup in range(nb_groups): group_indexes.append(index_dwi[(iGroup * param.group_size):((iGroup + 1) * param.group_size)]) # add the remaining images to the last DWI group nb_remaining = nb_dwi % param.group_size # number of remaining images if nb_remaining > 0: nb_groups += 1 group_indexes.append(index_dwi[len(index_dwi) - nb_remaining:len(index_dwi)]) # DWI groups for iGroup in range(nb_groups): sct.printv('\nDWI group: ' + str((iGroup + 1)) + '/' + str(nb_groups), param.verbose) # get index index_dwi_i = group_indexes[iGroup] nb_dwi_i = len(index_dwi_i) # Merge DW Images sct.printv('Merge DW images...', param.verbose) file_dwi_merge_i = file_dwi + '_' + str(iGroup) cmd = 'sct_concat_data -dim t -o ' + file_dwi_merge_i + ext_data + ' -i ' for it in range(nb_dwi_i): cmd = cmd + file_data + '_T' + str( index_dwi_i[it]).zfill(4) + ext_data + ',' cmd = cmd[:-1] # remove ',' at the end of the string sct.run(cmd, param.verbose) # cmd = fsloutput + 'fslmerge -t ' + file_dwi_merge_i # for it in range(nb_dwi_i): # cmd = cmd +' ' + file_data + '_T' + str(index_dwi_i[it]).zfill(4) # Average DW Images sct.printv('Average DW images...', param.verbose) file_dwi_mean = file_dwi + '_mean_' + str(iGroup) sct.run( 'sct_maths -i ' + file_dwi_merge_i + '.nii' + ' -o ' + file_dwi_mean + '.nii' + ' -mean t', param.verbose) # if not average_data_across_dimension(file_dwi_merge_i+'.nii', file_dwi_mean+'.nii', 3): # sct.printv('ERROR in average_data_across_dimension', 1, 'error') # cmd = fsloutput + 'fslmaths ' + file_dwi_merge_i + ' -Tmean ' + file_dwi_mean # sct.run(cmd, param.verbose) # Merge DWI groups means sct.printv('\nMerging DW files...', param.verbose) # file_dwi_groups_means_merge = 'dwi_averaged_groups' cmd = 'sct_concat_data -dim t -o ' + file_dwi_group + ext_data + ' -i ' for iGroup in range(nb_groups): cmd = cmd + file_dwi + '_mean_' + str(iGroup) + ext_data + ',' cmd = cmd[:-1] # remove ',' at the end of the string sct.run(cmd, param.verbose) # cmd = fsloutput + 'fslmerge -t ' + file_dwi_group # for iGroup in range(nb_groups): # cmd = cmd + ' ' + file_dwi + '_mean_' + str(iGroup) # Average DW Images # TODO: USEFULL ??? sct.printv('\nAveraging all DW images...', param.verbose) fname_dwi_mean = 'dwi_mean' sct.run( 'sct_maths -i ' + file_dwi_group + '.nii' + ' -o ' + file_dwi_group + '_mean.nii' + ' -mean t', param.verbose) # if not average_data_across_dimension(file_dwi_group+'.nii', file_dwi_group+'_mean.nii', 3): # sct.printv('ERROR in average_data_across_dimension', 1, 'error') # sct.run(fsloutput + 'fslmaths ' + file_dwi_group + ' -Tmean ' + file_dwi_group+'_mean', param.verbose) # segment dwi images using otsu algorithm if param.otsu: sct.printv('\nSegment group DWI using OTSU algorithm...', param.verbose) # import module otsu = importlib.import_module('sct_otsu') # get class from module param_otsu = otsu.param() #getattr(otsu, param) param_otsu.fname_data = file_dwi_group + '.nii' param_otsu.threshold = param.otsu param_otsu.file_suffix = '_seg' # run otsu otsu.otsu(param_otsu) file_dwi_group = file_dwi_group + '_seg' # extract first DWI volume as target for registration nii = Image(file_dwi_group + '.nii') data_crop = nii.data[:, :, :, index_dwi[0]:index_dwi[0] + 1] nii.data = data_crop nii.setFileName('target_dwi.nii') nii.save() # START MOCO #=================================================================================================================== # Estimate moco on b0 groups sct.printv( '\n-------------------------------------------------------------------------------', param.verbose) sct.printv(' Estimating motion on b=0 images...', param.verbose) sct.printv( '-------------------------------------------------------------------------------', param.verbose) param_moco = param param_moco.file_data = 'b0' if index_dwi[0] != 0: # If first DWI is not the first volume (most common), then there is a least one b=0 image before. In that case # select it as the target image for registration of all b=0 param_moco.file_target = file_data + '_T' + str( index_b0[index_dwi[0] - 1]).zfill(4) else: # If first DWI is the first volume, then the target b=0 is the first b=0 from the index_b0. param_moco.file_target = file_data + '_T' + str(index_b0[0]).zfill(4) param_moco.path_out = '' param_moco.todo = 'estimate' param_moco.mat_moco = 'mat_b0groups' moco.moco(param_moco) # Estimate moco on dwi groups sct.printv( '\n-------------------------------------------------------------------------------', param.verbose) sct.printv(' Estimating motion on DW images...', param.verbose) sct.printv( '-------------------------------------------------------------------------------', param.verbose) param_moco.file_data = file_dwi_group param_moco.file_target = 'target_dwi' # target is the first DW image (closest to the first b=0) param_moco.path_out = '' #param_moco.todo = 'estimate' param_moco.todo = 'estimate_and_apply' param_moco.mat_moco = 'mat_dwigroups' moco.moco(param_moco) # create final mat folder sct.create_folder(mat_final) # Copy b=0 registration matrices sct.printv('\nCopy b=0 registration matrices...', param.verbose) for it in range(nb_b0): sct.run( 'cp ' + 'mat_b0groups/' + 'mat.T' + str(it) + ext_mat + ' ' + mat_final + 'mat.T' + str(index_b0[it]) + ext_mat, param.verbose) # Copy DWI registration matrices sct.printv('\nCopy DWI registration matrices...', param.verbose) for iGroup in range(nb_groups): for dwi in range(len(group_indexes[iGroup])): sct.run( 'cp ' + 'mat_dwigroups/' + 'mat.T' + str(iGroup) + ext_mat + ' ' + mat_final + 'mat.T' + str(group_indexes[iGroup][dwi]) + ext_mat, param.verbose) # Spline Regularization along T if param.spline_fitting: moco.spline(mat_final, nt, nz, param.verbose, np.array(index_b0), param.plot_graph) # combine Eddy Matrices if param.run_eddy: param.mat_2_combine = 'mat_eddy' param.mat_final = mat_final moco.combine_matrix(param) # Apply moco on all dmri data sct.printv( '\n-------------------------------------------------------------------------------', param.verbose) sct.printv(' Apply moco', param.verbose) sct.printv( '-------------------------------------------------------------------------------', param.verbose) param_moco.file_data = 'dmri' param_moco.file_target = file_dwi + '_mean_' + str( 0) # reference for reslicing into proper coordinate system param_moco.path_out = '' param_moco.mat_moco = mat_final param_moco.todo = 'apply' moco.moco(param_moco) # copy geometric information from header # NB: this is required because WarpImageMultiTransform in 2D mode wrongly sets pixdim(3) to "1". copy_header('dmri.nii', 'dmri_moco.nii') # generate b0_moco_mean and dwi_moco_mean cmd = 'sct_dmri_separate_b0_and_dwi -i dmri' + param.suffix + '.nii -b bvecs.txt -a 1' if not param.fname_bvals == '': cmd = cmd + ' -m ' + param.fname_bvals sct.run(cmd, param.verbose)
def wm_registration(param): path, fixed_name, ext = sct.extract_fname(param.fname_fixed) path_moving, moving_name, ext = sct.extract_fname(param.fname_moving) path, fixed_seg_name, ext = sct.extract_fname(param.fname_seg_fixed) path_moving_seg, moving_seg_name, ext = sct.extract_fname(param.fname_seg_moving) # cropping in x & y directions fixed_name_temp = fixed_name + "_crop" cmd = "sct_crop_image -i " + fixed_name + ext + " -o " + fixed_name_temp + ext + " -m " + fixed_seg_name + ext + " -shift 10,10 -dim 0,1" sct.run(cmd) fixed_name = fixed_name_temp fixed_seg_name_temp = fixed_name+"_crop" sct.run("sct_crop_image -i " + fixed_seg_name + ext + " -o " + fixed_seg_name_temp + ext + " -m " + fixed_seg_name + ext + " -shift 10,10 -dim 0,1") fixed_seg_name = fixed_seg_name_temp # padding the images moving_name_pad = moving_name+"_pad" fixed_name_pad = fixed_name+"_pad" sct.run("c3d "+path_moving+moving_name+ext+" -pad 0x0x"+param.padding+"vox 0x0x"+param.padding+"vox 0 -o "+moving_name_pad+ext) sct.run("c3d "+fixed_name+ext+" -pad 0x0x"+param.padding+"vox 0x0x"+param.padding+"vox 0 -o "+fixed_name_pad+ext) moving_name = moving_name_pad fixed_name = fixed_name_pad moving_seg_name_pad = moving_seg_name+"_pad" sct.run("c3d "+path_moving_seg+moving_seg_name+ext+" -pad 0x0x"+param.padding+"vox 0x0x"+param.padding+"vox 0 -o "+moving_seg_name_pad+ext) moving_seg_name = moving_seg_name_pad fixed_seg_name_pad = fixed_seg_name+"_pad" sct.run("c3d "+fixed_seg_name+ext+" -pad 0x0x"+param.padding+"vox 0x0x"+param.padding+"vox 0 -o "+fixed_seg_name_pad+ext) fixed_seg_name = fixed_seg_name_pad # offset old_min = 0 old_max = 1 new_min = 100 new_max = 200 fixed_im = Image(fixed_name+ext) fixed_im.data = (fixed_im.data - old_min)*(new_max - new_min)/(old_max - old_min) + new_min fixed_im.save() moving_im = Image(moving_name+ext) moving_im.data = (moving_im.data - old_min)*(new_max - new_min)/(old_max - old_min) + new_min moving_im.save() # registration of the gray matter sct.printv('\nDeforming the image...', reg_param.verbose, 'normal') moving_name_reg = moving_name+"_deformed" if param.transformation == 'BSplineSyN': transfo_params = ',3,0' elif param.transforlation == 'SyN': # SyN gives bad results... transfo_params = ',1,1' else: transfo_params = '' cmd = 'isct_antsRegistration --dimensionality 3 --interpolation '+param.interpolation+' --transform '+param.transformation+'['+param.gradient_step+transfo_params+'] --metric '+param.metric+'['+fixed_name+ext+','+moving_name+ext+',1,4] --output ['+moving_name_reg+','+moving_name_reg+ext+'] --convergence '+param.iteration+' --shrink-factors 2x1 --smoothing-sigmas 0x0 ' cmd += " --masks ["+fixed_seg_name+ext+","+moving_seg_name + ext + "]" # cmd += " -m ["+fixed_seg_name+".nii,"+moving_seg_name+".nii]" sct.run(cmd) moving_name = moving_name_reg # removing offset fixed_im = Image(fixed_name+ext) fixed_im.data = (fixed_im.data - new_min)*(old_max - old_min)/(new_max - new_min) + old_min fixed_im.save() moving_im = Image(moving_name+ext) moving_im.data = (moving_im.data - new_min)*(old_max - old_min)/(new_max - new_min) + old_min moving_im.save() # un-padding the images moving_name_unpad = moving_name+"_unpadded" sct.run("sct_crop_image -i "+moving_name+ext+" -dim 2 -start "+str(int(param.padding)-1)+" -end -"+param.padding+" -o "+moving_name_unpad+ext) path_output, file_output, ext_output = sct.extract_fname(param.fname_output) warp_output = file_output+"0Warp"+ext_output inverse_warp_output = file_output+"0InverseWarp"+ext_output sct.run("mv "+moving_name+"0Warp.nii.gz "+warp_output) sct.run("mv "+moving_name+"0InverseWarp.nii.gz "+inverse_warp_output) moving_name = moving_name_unpad moving_name_out = file_output+ext_output sct.run("c3d "+fixed_name+ext+" "+moving_name+ext+" -reslice-identity -o "+moving_name_out+ext) return warp_output, inverse_warp_output
def create_mask(): fsloutput = 'export FSLOUTPUTTYPE=NIFTI; ' # for faster processing, all outputs are in NIFTI # parse argument for method method_type = param.process[0] # check method val if not method_type == 'center': method_val = param.process[1] # check existence of input files if method_type == 'centerline': sct.check_file_exist(method_val, param.verbose) # Extract path/file/extension path_data, file_data, ext_data = sct.extract_fname(param.fname_data) # Get output folder and file name if param.fname_out == '': param.fname_out = param.file_prefix+file_data+ext_data # create temporary folder sct.printv('\nCreate temporary folder...', param.verbose) path_tmp = sct.tmp_create(param.verbose) # )sct.slash_at_the_end('tmp.'+time.strftime("%y%m%d%H%M%S"), 1) # sct.run('mkdir '+path_tmp, param.verbose) sct.printv('\nCheck orientation...', param.verbose) orientation_input = get_orientation(Image(param.fname_data)) sct.printv('.. '+orientation_input, param.verbose) reorient_coordinates = False # copy input data to tmp folder convert(param.fname_data, path_tmp+'data.nii') if method_type == 'centerline': convert(method_val, path_tmp+'centerline.nii.gz') if method_type == 'point': convert(method_val, path_tmp+'point.nii.gz') # go to tmp folder os.chdir(path_tmp) # reorient to RPI sct.printv('\nReorient to RPI...', param.verbose) # if not orientation_input == 'RPI': sct.run('sct_image -i data.nii -o data_RPI.nii -setorient RPI -v 0', verbose=False) if method_type == 'centerline': sct.run('sct_image -i centerline.nii.gz -o centerline_RPI.nii.gz -setorient RPI -v 0', verbose=False) if method_type == 'point': sct.run('sct_image -i point.nii.gz -o point_RPI.nii.gz -setorient RPI -v 0', verbose=False) # # if method_type == 'centerline': # orientation_centerline = get_orientation_3d(method_val, filename=True) # if not orientation_centerline == 'RPI': # sct.run('sct_image -i ' + method_val + ' -o ' + path_tmp + 'centerline.nii.gz' + ' -setorient RPI -v 0', verbose=False) # else: # convert(method_val, path_tmp+'centerline.nii.gz') # Get dimensions of data sct.printv('\nGet dimensions of data...', param.verbose) nx, ny, nz, nt, px, py, pz, pt = Image('data_RPI.nii').dim sct.printv(' ' + str(nx) + ' x ' + str(ny) + ' x ' + str(nz)+ ' x ' + str(nt), param.verbose) # in case user input 4d data if nt != 1: sct.printv('WARNING in '+os.path.basename(__file__)+': Input image is 4d but output mask will 3D.', param.verbose, 'warning') # extract first volume to have 3d reference nii = Image('data_RPI.nii') data3d = nii.data[:,:,:,0] nii.data = data3d nii.save() if method_type == 'coord': # parse to get coordinate coord = map(int, method_val.split('x')) if method_type == 'point': # get file name fname_point = method_val # extract coordinate of point sct.printv('\nExtract coordinate of point...', param.verbose) # TODO: change this way to remove dependence to sct.run. ProcessLabels.display_voxel returns list of coordinates status, output = sct.run('sct_label_utils -i point_RPI.nii.gz -display', param.verbose) # parse to get coordinate coord = output[output.find('Position=')+10:-17].split(',') if method_type == 'center': # set coordinate at center of FOV coord = round(float(nx)/2), round(float(ny)/2) if method_type == 'centerline': # get name of centerline from user argument fname_centerline = 'centerline_RPI.nii.gz' else: # generate volume with line along Z at coordinates 'coord' sct.printv('\nCreate line...', param.verbose) fname_centerline = create_line('data_RPI.nii', coord, nz) # create mask sct.printv('\nCreate mask...', param.verbose) centerline = nibabel.load(fname_centerline) # open centerline hdr = centerline.get_header() # get header hdr.set_data_dtype('uint8') # set imagetype to uint8 spacing = hdr.structarr['pixdim'] data_centerline = centerline.get_data() # get centerline z_centerline_not_null = [iz for iz in range(0, nz, 1) if data_centerline[:, :, iz].any()] # get center of mass of the centerline cx = [0] * nz cy = [0] * nz for iz in range(0, nz, 1): if iz in z_centerline_not_null: cx[iz], cy[iz] = ndimage.measurements.center_of_mass(numpy.array(data_centerline[:, :, iz])) # create 2d masks file_mask = 'data_mask' for iz in range(nz): if iz not in z_centerline_not_null: # write an empty nifty volume img = nibabel.Nifti1Image(data_centerline[:, :, iz], None, hdr) nibabel.save(img, (file_mask + str(iz) + '.nii')) else: center = numpy.array([cx[iz], cy[iz]]) mask2d = create_mask2d(center, param.shape, param.size, nx, ny, even=param.even, spacing=spacing) # Write NIFTI volumes img = nibabel.Nifti1Image(mask2d, None, hdr) nibabel.save(img, (file_mask+str(iz)+'.nii')) # merge along Z # cmd = 'fslmerge -z mask ' # CHANGE THAT CAN IMPACT SPEED: # related to issue #755, we cannot open more than 256 files at one time. # to solve this issue, we do not open more than 100 files ''' im_list = [] im_temp = [] for iz in range(nz_not_null): if iz != 0 and iz % 100 == 0: im_temp.append(concat_data(im_list, 2)) im_list = [Image(file_mask + str(iz) + '.nii')] else: im_list.append(Image(file_mask+str(iz)+'.nii')) if im_temp: im_temp.append(concat_data(im_list, 2)) im_out = concat_data(im_temp, 2, no_expand=True) else: im_out = concat_data(im_list, 2) ''' fname_list = [file_mask + str(iz) + '.nii' for iz in range(nz)] im_out = concat_data(fname_list, dim=2) im_out.setFileName('mask_RPI.nii.gz') im_out.save() # reorient if necessary # if not orientation_input == 'RPI': sct.run('sct_image -i mask_RPI.nii.gz -o mask.nii.gz -setorient ' + orientation_input, param.verbose) # copy header input --> mask im_dat = Image('data.nii') im_mask = Image('mask.nii.gz') im_mask = copy_header(im_dat, im_mask) im_mask.save() # come back to parent folder os.chdir('..') # Generate output files sct.printv('\nGenerate output files...', param.verbose) sct.generate_output_file(path_tmp+'mask.nii.gz', param.fname_out) # Remove temporary files if param.remove_tmp_files == 1: sct.printv('\nRemove temporary files...', param.verbose) sct.run('rm -rf '+path_tmp, param.verbose, error_exit='warning') # to view results sct.printv('\nDone! To view results, type:', param.verbose) sct.printv('fslview '+param.fname_data+' '+param.fname_out+' -l Red -t 0.5 &', param.verbose, 'info') print
def execute(self): print 'Execution of the SCAD algorithm in ' + str(os.getcwd()) original_name = self.input_image.file_name vesselness_file_name = "imageVesselNessFilter.nii.gz" raw_file_name = "raw.nii" self.setup_debug_folder() if self.debug: import matplotlib.pyplot as plt # import for debug purposes # create tmp and copy input path_tmp = self.create_temporary_path() conv.convert(self.input_image.absolutepath, path_tmp + raw_file_name) if self.vesselness_provided: sct.run('cp ' + vesselness_file_name + ' ' + path_tmp + vesselness_file_name) os.chdir(path_tmp) # get input image information img = Image(raw_file_name) # save original orientation and change image to RPI self.raw_orientation = img.change_orientation() # get body symmetry if self.enable_symmetry: from msct_image import change_data_orientation sym = SymmetryDetector(raw_file_name, self.contrast, crop_xy=0) self.raw_symmetry = sym.execute() img.change_orientation(self.raw_orientation) self.output_debug_file(img, self.raw_symmetry, "body_symmetry") img.change_orientation() # vesselness filter if not self.vesselness_provided: sct.run('isct_vesselness -i ' + raw_file_name + ' -t ' + self._contrast + " -radius " + str(self.spinalcord_radius)) # load vesselness filter data and perform minimum path on it img = Image(vesselness_file_name) self.output_debug_file(img, img.data, "Vesselness_Filter") img.change_orientation() self.minimum_path_data, self.J1_min_path, self.J2_min_path = get_minimum_path( img.data, invert=1, debug=1) self.output_debug_file(img, self.minimum_path_data, "minimal_path") self.output_debug_file(img, self.J1_min_path, "J1_minimal_path") self.output_debug_file(img, self.J2_min_path, "J2_minimal_path") # Apply an exponent to the minimum path self.minimum_path_powered = np.power(self.minimum_path_data, self.minimum_path_exponent) self.output_debug_file( img, self.minimum_path_powered, "minimal_path_power_" + str(self.minimum_path_exponent)) # Saving in Image since smooth_minimal_path needs pixel dimensions img.data = self.minimum_path_powered # smooth resulting minimal path self.smoothed_min_path = smooth_minimal_path(img) self.output_debug_file(img, self.smoothed_min_path.data, "minimal_path_smooth") # normalise symmetry values between 0 and 1 if self.enable_symmetry: normalised_symmetry = normalize_array_histogram(self.raw_symmetry) self.output_debug_file(img, self.smoothed_min_path.data, "minimal_path_smooth") # multiply normalised symmetry data with the minimum path result from msct_image import change_data_orientation self.spine_detect_data = np.multiply( self.smoothed_min_path.data, change_data_orientation( np.power(normalised_symmetry, self.symmetry_exponent), self.raw_orientation, "RPI")) self.output_debug_file(img, self.spine_detect_data, "symmetry_x_min_path") # extract the centerline from the minimal path image self.centerline_with_outliers = get_centerline( self.spine_detect_data, self.spine_detect_data.shape) else: # extract the centerline from the minimal path image self.centerline_with_outliers = get_centerline( self.smoothed_min_path.data, self.smoothed_min_path.data.shape) self.output_debug_file(img, self.centerline_with_outliers, "centerline_with_outliers") # saving centerline with outliers to have img.data = self.centerline_with_outliers img.change_orientation() img.file_name = "centerline_with_outliers" img.save() # use a b-spline to smooth out the centerline x, y, z, dx, dy, dz = smooth_centerline( "centerline_with_outliers.nii.gz") # save the centerline nx, ny, nz, nt, px, py, pz, pt = img.dim img.data = np.zeros((nx, ny, nz)) for i in range(0, np.size(x) - 1): img.data[int(x[i]), int(y[i]), int(z[i])] = 1 self.output_debug_file(img, img.data, "centerline") img.change_orientation(self.raw_orientation) img.file_name = "centerline" img.save() # copy back centerline os.chdir('../') conv.convert(path_tmp + img.file_name + img.ext, self.output_filename) if self.rm_tmp_file == 1: import shutil shutil.rmtree(path_tmp) print "To view the output with FSL :" sct.printv( "fslview " + self.input_image.absolutepath + " " + self.output_filename + " -l Red", self.verbose, "info")
def execute(self): print 'Execution of the SCAD algorithm in '+str(os.getcwd()) original_name = self.input_image.file_name vesselness_file_name = "imageVesselNessFilter.nii.gz" raw_file_name = "raw.nii" self.setup_debug_folder() if self.debug: import matplotlib.pyplot as plt # import for debug purposes # create tmp and copy input path_tmp = self.create_temporary_path() conv.convert(self.input_image.absolutepath, path_tmp+raw_file_name) if self.vesselness_provided: sct.run('cp '+vesselness_file_name+' '+path_tmp+vesselness_file_name) os.chdir(path_tmp) # get input image information img = Image(raw_file_name) # save original orientation and change image to RPI self.raw_orientation = img.change_orientation() # get body symmetry if self.enable_symmetry: from msct_image import change_data_orientation sym = SymmetryDetector(raw_file_name, self.contrast, crop_xy=0) self.raw_symmetry = sym.execute() img.change_orientation(self.raw_orientation) self.output_debug_file(img, self.raw_symmetry, "body_symmetry") img.change_orientation() # vesselness filter if not self.vesselness_provided: sct.run('sct_vesselness -i '+raw_file_name+' -t ' + self._contrast+" -radius "+str(self.spinalcord_radius)) # load vesselness filter data and perform minimum path on it img = Image(vesselness_file_name) img.change_orientation() self.minimum_path_data, self.J1_min_path, self.J2_min_path = get_minimum_path(img.data, invert=1, debug=1) self.output_debug_file(img, self.minimum_path_data, "minimal_path") self.output_debug_file(img, self.J1_min_path, "J1_minimal_path") self.output_debug_file(img, self.J2_min_path, "J2_minimal_path") # Apply an exponent to the minimum path self.minimum_path_powered = np.power(self.minimum_path_data, self.minimum_path_exponent) self.output_debug_file(img, self.minimum_path_powered, "minimal_path_power_"+str(self.minimum_path_exponent)) # Saving in Image since smooth_minimal_path needs pixel dimensions img.data = self.minimum_path_powered # smooth resulting minimal path self.smoothed_min_path = smooth_minimal_path(img) self.output_debug_file(img, self.smoothed_min_path.data, "minimal_path_smooth") # normalise symmetry values between 0 and 1 if self.enable_symmetry: normalised_symmetry = normalize_array_histogram(self.raw_symmetry) self.output_debug_file(img, self.smoothed_min_path.data, "minimal_path_smooth") # multiply normalised symmetry data with the minimum path result from msct_image import change_data_orientation self.spine_detect_data = np.multiply(self.smoothed_min_path.data, change_data_orientation(np.power(normalised_symmetry, self.symmetry_exponent), self.raw_orientation, "RPI")) self.output_debug_file(img, self.spine_detect_data, "symmetry_x_min_path") # extract the centerline from the minimal path image self.centerline_with_outliers = get_centerline(self.spine_detect_data, self.spine_detect_data.shape) else: # extract the centerline from the minimal path image self.centerline_with_outliers = get_centerline(self.smoothed_min_path.data, self.smoothed_min_path.data.shape) self.output_debug_file(img, self.centerline_with_outliers, "centerline_with_outliers") # saving centerline with outliers to have img.data = self.centerline_with_outliers img.change_orientation() img.file_name = "centerline_with_outliers" img.save() # use a b-spline to smooth out the centerline x, y, z, dx, dy, dz = smooth_centerline("centerline_with_outliers.nii.gz") # save the centerline nx, ny, nz, nt, px, py, pz, pt = img.dim img.data = np.zeros((nx, ny, nz)) for i in range(0, np.size(x)-1): img.data[int(x[i]), int(y[i]), int(z[i])] = 1 self.output_debug_file(img, img.data, "centerline") img.change_orientation(self.raw_orientation) img.file_name = "centerline" img.save() # copy back centerline os.chdir('../') conv.convert(path_tmp+img.file_name+img.ext, self.output_filename) if self.rm_tmp_file == 1: import shutil shutil.rmtree(path_tmp)
def generate_initial_template_space(dataset_info, points_average_centerline, position_template_disks): """ This function generates the initial template space, on which all images will be registered. :param points_average_centerline: list of points (x, y, z) of the average spinal cord and brainstem centerline :param position_template_disks: index of intervertebral disks along the template centerline :return: """ # initializing variables path_template = dataset_info['path_template'] x_size_of_template_space, y_size_of_template_space = 201, 201 spacing = 0.5 # creating template space size_template_z = int(abs(points_average_centerline[0][2] - points_average_centerline[-1][2]) / spacing) + 15 template_space = Image([x_size_of_template_space, y_size_of_template_space, size_template_z]) template_space.data = np.zeros((x_size_of_template_space, y_size_of_template_space, size_template_z)) template_space.hdr.set_data_dtype('float32') origin = [points_average_centerline[-1][0] + x_size_of_template_space * spacing / 2.0, points_average_centerline[-1][1] - y_size_of_template_space * spacing / 2.0, (points_average_centerline[-1][2] - spacing)] template_space.hdr.as_analyze_map()['dim'] = [3.0, x_size_of_template_space, y_size_of_template_space, size_template_z, 1.0, 1.0, 1.0, 1.0] template_space.hdr.as_analyze_map()['qoffset_x'] = origin[0] template_space.hdr.as_analyze_map()['qoffset_y'] = origin[1] template_space.hdr.as_analyze_map()['qoffset_z'] = origin[2] template_space.hdr.as_analyze_map()['srow_x'][-1] = origin[0] template_space.hdr.as_analyze_map()['srow_y'][-1] = origin[1] template_space.hdr.as_analyze_map()['srow_z'][-1] = origin[2] template_space.hdr.as_analyze_map()['srow_x'][0] = -spacing template_space.hdr.as_analyze_map()['srow_y'][1] = spacing template_space.hdr.as_analyze_map()['srow_z'][2] = spacing template_space.hdr.set_sform(template_space.hdr.get_sform()) template_space.hdr.set_qform(template_space.hdr.get_sform()) template_space.setFileName(path_template + 'template_space.nii.gz') template_space.save(type='uint8') # generate template centerline as an image image_centerline = template_space.copy() for coord in points_average_centerline: coord_pix = image_centerline.transfo_phys2pix([coord])[0] if 0 <= coord_pix[0] < image_centerline.data.shape[0] and 0 <= coord_pix[1] < image_centerline.data.shape[1] and 0 <= coord_pix[2] < image_centerline.data.shape[2]: image_centerline.data[int(coord_pix[0]), int(coord_pix[1]), int(coord_pix[2])] = 1 image_centerline.setFileName(path_template + 'template_centerline.nii.gz') image_centerline.save(type='float32') # generate template disks position coord_physical = [] image_disks = template_space.copy() for disk in position_template_disks: label = labels_regions[disk] coord = position_template_disks[disk] coord_pix = image_disks.transfo_phys2pix([coord])[0] coord = coord.tolist() coord.append(label) coord_physical.append(coord) if 0 <= coord_pix[0] < image_disks.data.shape[0] and 0 <= coord_pix[1] < image_disks.data.shape[1] and 0 <= coord_pix[2] < image_disks.data.shape[2]: image_disks.data[int(coord_pix[0]), int(coord_pix[1]), int(coord_pix[2])] = label else: sct.printv(str(coord_pix)) sct.printv('ERROR: the disk label ' + str(disk) + ' is not in the template image.') image_disks.setFileName(path_template + 'template_disks.nii.gz') image_disks.save(type='uint8') # generate template centerline as a npz file x_centerline_fit, y_centerline_fit, z_centerline, x_centerline_deriv, y_centerline_deriv, z_centerline_deriv = smooth_centerline( path_template + 'template_centerline.nii.gz', algo_fitting='nurbs', verbose=0, nurbs_pts_number=4000, all_slices=False, phys_coordinates=True, remove_outliers=True) centerline_template = Centerline(x_centerline_fit, y_centerline_fit, z_centerline, x_centerline_deriv, y_centerline_deriv, z_centerline_deriv) centerline_template.compute_vertebral_distribution(coord_physical) centerline_template.save_centerline(fname_output=path_template + 'template_centerline')
def compute_dti(fname_in, fname_bvals, fname_bvecs, prefix, method, file_mask): """ Compute DTI. :param fname_in: input 4d file. :param bvals: bvals txt file :param bvecs: bvecs txt file :param prefix: output prefix. Example: "dti_" :param method: algo for computing dti :return: True/False """ # Open file. from msct_image import Image nii = Image(fname_in) data = nii.data print('data.shape (%d, %d, %d, %d)' % data.shape) # open bvecs/bvals from dipy.io import read_bvals_bvecs bvals, bvecs = read_bvals_bvecs(fname_bvals, fname_bvecs) from dipy.core.gradients import gradient_table gtab = gradient_table(bvals, bvecs) # mask and crop the data. This is a quick way to avoid calculating Tensors on the background of the image. if not file_mask == '': printv('Open mask file...', param.verbose) # open mask file nii_mask = Image(file_mask) mask = nii_mask.data # fit tensor model printv('Computing tensor using "'+method+'" method...', param.verbose) import dipy.reconst.dti as dti if method == 'standard': tenmodel = dti.TensorModel(gtab) if file_mask == '': tenfit = tenmodel.fit(data) else: tenfit = tenmodel.fit(data, mask) elif method == 'restore': import dipy.denoise.noise_estimate as ne sigma = ne.estimate_sigma(data) dti_restore = dti.TensorModel(gtab, fit_method='RESTORE', sigma=sigma) if file_mask == '': tenfit = dti_restore.fit(data) else: tenfit = dti_restore.fit(data, mask) # Compute metrics printv('Computing metrics...', param.verbose) # FA from dipy.reconst.dti import fractional_anisotropy nii.data = fractional_anisotropy(tenfit.evals) nii.setFileName(prefix+'FA.nii.gz') nii.save('float32') # MD from dipy.reconst.dti import mean_diffusivity nii.data = mean_diffusivity(tenfit.evals) nii.setFileName(prefix+'MD.nii.gz') nii.save('float32') # RD from dipy.reconst.dti import radial_diffusivity nii.data = radial_diffusivity(tenfit.evals) nii.setFileName(prefix+'RD.nii.gz') nii.save('float32') # AD from dipy.reconst.dti import axial_diffusivity nii.data = axial_diffusivity(tenfit.evals) nii.setFileName(prefix+'AD.nii.gz') nii.save('float32') return True
def register(src, dest, paramreg, param, i_step_str): # initiate default parameters of antsRegistration transformation ants_registration_params = {'rigid': '', 'affine': '', 'compositeaffine': '', 'similarity': '', 'translation': '', 'bspline': ',10', 'gaussiandisplacementfield': ',3,0', 'bsplinedisplacementfield': ',5,10', 'syn': ',3,0', 'bsplinesyn': ',1,3'} output = '' # default output if problem # display arguments sct.printv('Registration parameters:', param.verbose) sct.printv(' type ........... '+paramreg.steps[i_step_str].type, param.verbose) sct.printv(' algo ........... '+paramreg.steps[i_step_str].algo, param.verbose) sct.printv(' slicewise ...... '+paramreg.steps[i_step_str].slicewise, param.verbose) sct.printv(' metric ......... '+paramreg.steps[i_step_str].metric, param.verbose) sct.printv(' iter ........... '+paramreg.steps[i_step_str].iter, param.verbose) sct.printv(' smooth ......... '+paramreg.steps[i_step_str].smooth, param.verbose) sct.printv(' laplacian ...... '+paramreg.steps[i_step_str].laplacian, param.verbose) sct.printv(' shrink ......... '+paramreg.steps[i_step_str].shrink, param.verbose) sct.printv(' gradStep ....... '+paramreg.steps[i_step_str].gradStep, param.verbose) sct.printv(' init ........... '+paramreg.steps[i_step_str].init, param.verbose) sct.printv(' poly ........... '+paramreg.steps[i_step_str].poly, param.verbose) sct.printv(' dof ............ '+paramreg.steps[i_step_str].dof, param.verbose) sct.printv(' smoothWarpXY ... '+paramreg.steps[i_step_str].smoothWarpXY, param.verbose) # set metricSize if paramreg.steps[i_step_str].metric == 'MI': metricSize = '32' # corresponds to number of bins else: metricSize = '4' # corresponds to radius (for CC, MeanSquares...) # set masking if param.fname_mask: fname_mask = 'mask.nii.gz' masking = '-x mask.nii.gz' else: fname_mask = '' masking = '' if paramreg.steps[i_step_str].algo == 'slicereg': # check if user used type=label if paramreg.steps[i_step_str].type == 'label': sct.printv('\nERROR: this algo is not compatible with type=label. Please use type=im or type=seg', 1, 'error') else: from msct_image import find_zmin_zmax # threshold images (otherwise, automatic crop does not work -- see issue #293) src_th = sct.add_suffix(src, '_th') from msct_image import Image nii = Image(src) data = nii.data data[data < 0.1] = 0 nii.data = data nii.setFileName(src_th) nii.save() # sct.run(fsloutput+'fslmaths '+src+' -thr 0.1 '+src_th, param.verbose) dest_th = sct.add_suffix(dest, '_th') nii = Image(dest) data = nii.data data[data < 0.1] = 0 nii.data = data nii.setFileName(dest_th) nii.save() # sct.run(fsloutput+'fslmaths '+dest+' -thr 0.1 '+dest_th, param.verbose) # find zmin and zmax zmin_src, zmax_src = find_zmin_zmax(src_th) zmin_dest, zmax_dest = find_zmin_zmax(dest_th) zmin_total = max([zmin_src, zmin_dest]) zmax_total = min([zmax_src, zmax_dest]) # crop data src_crop = sct.add_suffix(src, '_crop') sct.run('sct_crop_image -i '+src+' -o '+src_crop+' -dim 2 -start '+str(zmin_total)+' -end '+str(zmax_total), param.verbose) dest_crop = sct.add_suffix(dest, '_crop') sct.run('sct_crop_image -i '+dest+' -o '+dest_crop+' -dim 2 -start '+str(zmin_total)+' -end '+str(zmax_total), param.verbose) # update variables src = src_crop dest = dest_crop scr_regStep = sct.add_suffix(src, '_regStep'+i_step_str) # estimate transfo cmd = ('isct_antsSliceRegularizedRegistration ' '-t Translation[0.5] ' '-m '+paramreg.steps[i_step_str].metric+'['+dest+','+src+',1,'+metricSize+',Regular,0.2] ' '-p '+paramreg.steps[i_step_str].poly+' ' '-i '+paramreg.steps[i_step_str].iter+' ' '-f 1 ' '-s '+paramreg.steps[i_step_str].smooth+' ' '-v 1 ' # verbose (verbose=2 does not exist, so we force it to 1) '-o [step'+i_step_str+','+scr_regStep+'] ' # here the warp name is stage10 because antsSliceReg add "Warp" +masking) warp_forward_out = 'step'+i_step_str+'Warp.nii.gz' warp_inverse_out = 'step'+i_step_str+'InverseWarp.nii.gz' # run command status, output = sct.run(cmd, param.verbose) # ANTS 3d elif paramreg.steps[i_step_str].algo.lower() in ants_registration_params and paramreg.steps[i_step_str].slicewise == '0': # make sure type!=label. If type==label, this will be addressed later in the code. if not paramreg.steps[i_step_str].type == 'label': # Pad the destination image (because ants doesn't deform the extremities) # N.B. no need to pad if iter = 0 if not paramreg.steps[i_step_str].iter == '0': dest_pad = sct.add_suffix(dest, '_pad') sct.run('sct_image -i '+dest+' -o '+dest_pad+' -pad 0,0,'+str(param.padding)) dest = dest_pad # apply Laplacian filter if not paramreg.steps[i_step_str].laplacian == '0': sct.printv('\nApply Laplacian filter', param.verbose) sct.run('sct_maths -i '+src+' -laplacian '+paramreg.steps[i_step_str].laplacian+','+paramreg.steps[i_step_str].laplacian+',0 -o '+sct.add_suffix(src, '_laplacian')) sct.run('sct_maths -i '+dest+' -laplacian '+paramreg.steps[i_step_str].laplacian+','+paramreg.steps[i_step_str].laplacian+',0 -o '+sct.add_suffix(dest, '_laplacian')) src = sct.add_suffix(src, '_laplacian') dest = sct.add_suffix(dest, '_laplacian') # Estimate transformation sct.printv('\nEstimate transformation', param.verbose) scr_regStep = sct.add_suffix(src, '_regStep' + i_step_str) cmd = ('isct_antsRegistration ' '--dimensionality 3 ' '--transform '+paramreg.steps[i_step_str].algo+'['+paramreg.steps[i_step_str].gradStep + ants_registration_params[paramreg.steps[i_step_str].algo.lower()]+'] ' '--metric '+paramreg.steps[i_step_str].metric+'['+dest+','+src+',1,'+metricSize+'] ' '--convergence '+paramreg.steps[i_step_str].iter+' ' '--shrink-factors '+paramreg.steps[i_step_str].shrink+' ' '--smoothing-sigmas '+paramreg.steps[i_step_str].smooth+'mm ' '--restrict-deformation 1x1x0 ' '--output [step'+i_step_str+','+scr_regStep+'] ' '--interpolation BSpline[3] ' +masking) # add verbose if param.verbose >= 1: cmd += ' --verbose 1' # add init translation if not paramreg.steps[i_step_str].init == '': init_dict = {'geometric': '0', 'centermass': '1', 'origin': '2'} cmd += ' -r ['+dest+','+src+','+init_dict[paramreg.steps[i_step_str].init]+']' # run command status, output = sct.run(cmd, param.verbose) # get appropriate file name for transformation if paramreg.steps[i_step_str].algo in ['rigid', 'affine', 'translation']: warp_forward_out = 'step'+i_step_str+'0GenericAffine.mat' warp_inverse_out = '-step'+i_step_str+'0GenericAffine.mat' else: warp_forward_out = 'step'+i_step_str+'0Warp.nii.gz' warp_inverse_out = 'step'+i_step_str+'0InverseWarp.nii.gz' # ANTS 2d elif paramreg.steps[i_step_str].algo.lower() in ants_registration_params and paramreg.steps[i_step_str].slicewise == '1': # make sure type!=label. If type==label, this will be addressed later in the code. if not paramreg.steps[i_step_str].type == 'label': from msct_register import register_slicewise # if shrink!=1, force it to be 1 (otherwise, it generates a wrong 3d warping field). TODO: fix that! if not paramreg.steps[i_step_str].shrink == '1': sct.printv('\nWARNING: when using slicewise with SyN or BSplineSyN, shrink factor needs to be one. Forcing shrink=1.', 1, 'warning') paramreg.steps[i_step_str].shrink = '1' warp_forward_out = 'step'+i_step_str + 'Warp.nii.gz' warp_inverse_out = 'step'+i_step_str + 'InverseWarp.nii.gz' register_slicewise(src, dest, paramreg=paramreg.steps[i_step_str], fname_mask=fname_mask, warp_forward_out=warp_forward_out, warp_inverse_out=warp_inverse_out, ants_registration_params=ants_registration_params, path_qc=param.path_qc, verbose=param.verbose) # slice-wise transfo elif paramreg.steps[i_step_str].algo in ['centermass', 'centermassrot', 'columnwise']: # if type=im, sends warning if paramreg.steps[i_step_str].type == 'im': sct.printv('\nWARNING: algo '+paramreg.steps[i_step_str].algo+' should be used with type=seg.\n', 1, 'warning') # if type=label, exit with error elif paramreg.steps[i_step_str].type == 'label': sct.printv('\nERROR: this algo is not compatible with type=label. Please use type=im or type=seg', 1, 'error') # check if user provided a mask-- if so, inform it will be ignored if not fname_mask == '': sct.printv('\nWARNING: algo '+paramreg.steps[i_step_str].algo+' will ignore the provided mask.\n', 1, 'warning') # smooth data if not paramreg.steps[i_step_str].smooth == '0': sct.printv('\nSmooth data', param.verbose) sct.run('sct_maths -i '+src+' -smooth '+paramreg.steps[i_step_str].smooth+','+paramreg.steps[i_step_str].smooth+',0 -o '+sct.add_suffix(src, '_smooth')) sct.run('sct_maths -i '+dest+' -smooth '+paramreg.steps[i_step_str].smooth+','+paramreg.steps[i_step_str].smooth+',0 -o '+sct.add_suffix(dest, '_smooth')) src = sct.add_suffix(src, '_smooth') dest = sct.add_suffix(dest, '_smooth') from msct_register import register_slicewise warp_forward_out = 'step'+i_step_str + 'Warp.nii.gz' warp_inverse_out = 'step'+i_step_str + 'InverseWarp.nii.gz' register_slicewise(src, dest, paramreg=paramreg.steps[i_step_str], fname_mask=fname_mask, warp_forward_out=warp_forward_out, warp_inverse_out=warp_inverse_out, ants_registration_params=ants_registration_params, path_qc=param.path_qc, verbose=param.verbose) else: sct.printv('\nERROR: algo '+paramreg.steps[i_step_str].algo+' does not exist. Exit program\n', 1, 'error') # landmark-based registration if paramreg.steps[i_step_str].type in ['label']: # check if user specified ilabel and dlabel # TODO warp_forward_out = 'step' + i_step_str + '0GenericAffine.txt' warp_inverse_out = '-step' + i_step_str + '0GenericAffine.txt' from msct_register_landmarks import register_landmarks register_landmarks(src, dest, paramreg.steps[i_step_str].dof, fname_affine=warp_forward_out, verbose=param.verbose, path_qc=param.path_qc) if not os.path.isfile(warp_forward_out): # no forward warping field for rigid and affine sct.printv('\nERROR: file '+warp_forward_out+' doesn\'t exist (or is not a file).\n' + output + '\nERROR: ANTs failed. Exit program.\n', 1, 'error') elif not os.path.isfile(warp_inverse_out) and paramreg.steps[i_step_str].algo not in ['rigid', 'affine', 'translation'] and paramreg.steps[i_step_str].type not in ['label']: # no inverse warping field for rigid and affine sct.printv('\nERROR: file '+warp_inverse_out+' doesn\'t exist (or is not a file).\n' + output + '\nERROR: ANTs failed. Exit program.\n', 1, 'error') else: # rename warping fields if (paramreg.steps[i_step_str].algo.lower() in ['rigid', 'affine', 'translation'] and paramreg.steps[i_step_str].slicewise == '0'): # if ANTs is used with affine/rigid --> outputs .mat file warp_forward = 'warp_forward_'+i_step_str+'.mat' os.rename(warp_forward_out, warp_forward) warp_inverse = '-warp_forward_'+i_step_str+'.mat' elif paramreg.steps[i_step_str].type in ['label']: # if label-based registration is used --> outputs .txt file warp_forward = 'warp_forward_'+i_step_str+'.txt' os.rename(warp_forward_out, warp_forward) warp_inverse = '-warp_forward_'+i_step_str+'.txt' else: warp_forward = 'warp_forward_'+i_step_str+'.nii.gz' warp_inverse = 'warp_inverse_'+i_step_str+'.nii.gz' os.rename(warp_forward_out, warp_forward) os.rename(warp_inverse_out, warp_inverse) return warp_forward, warp_inverse
def main(args=None): # Initialization # fname_anat = '' # fname_centerline = '' sigma = 3 # default value of the standard deviation for the Gaussian smoothing (in terms of number of voxels) # remove_temp_files = param.remove_temp_files # verbose = param.verbose start_time = time.time() parser = get_parser() arguments = parser.parse(sys.argv[1:]) fname_anat = arguments['-i'] fname_centerline = arguments['-s'] if '-smooth' in arguments: sigma = arguments['-smooth'] if '-r' in arguments: remove_temp_files = int(arguments['-r']) if '-v' in arguments: verbose = int(arguments['-v']) # Display arguments sct.printv('\nCheck input arguments...') sct.printv(' Volume to smooth .................. ' + fname_anat) sct.printv(' Centerline ........................ ' + fname_centerline) sct.printv(' Sigma (mm) ........................ ' + str(sigma)) sct.printv(' Verbose ........................... ' + str(verbose)) # Check that input is 3D: from msct_image import Image nx, ny, nz, nt, px, py, pz, pt = Image(fname_anat).dim dim = 4 # by default, will be adjusted later if nt == 1: dim = 3 if nz == 1: dim = 2 if dim == 4: sct.printv('WARNING: the input image is 4D, please split your image to 3D before smoothing spinalcord using :\n' 'sct_image -i ' + fname_anat + ' -split t -o ' + fname_anat, verbose, 'warning') sct.printv('4D images not supported, aborting ...', verbose, 'error') # Extract path/file/extension path_anat, file_anat, ext_anat = sct.extract_fname(fname_anat) path_centerline, file_centerline, ext_centerline = sct.extract_fname(fname_centerline) path_tmp = sct.tmp_create(basename="smooth_spinalcord", verbose=verbose) # Copying input data to tmp folder sct.printv('\nCopying input data to tmp folder and convert to nii...', verbose) sct.copy(fname_anat, os.path.join(path_tmp, "anat" + ext_anat)) sct.copy(fname_centerline, os.path.join(path_tmp, "centerline" + ext_centerline)) # go to tmp folder curdir = os.getcwd() os.chdir(path_tmp) # convert to nii format convert('anat' + ext_anat, 'anat.nii') convert('centerline' + ext_centerline, 'centerline.nii') # Change orientation of the input image into RPI sct.printv('\nOrient input volume to RPI orientation...') fname_anat_rpi = set_orientation('anat.nii', 'RPI', filename=True) shutil.move(fname_anat_rpi, 'anat_rpi.nii') # Change orientation of the input image into RPI sct.printv('\nOrient centerline to RPI orientation...') fname_centerline_rpi = set_orientation('centerline.nii', 'RPI', filename=True) shutil.move(fname_centerline_rpi, 'centerline_rpi.nii') # Straighten the spinal cord # straighten segmentation sct.printv('\nStraighten the spinal cord using centerline/segmentation...', verbose) cache_sig = sct.cache_signature( input_files=["anat_rpi.nii", "centerline_rpi.nii"], input_params={"x": "spline"}, ) cachefile = os.path.join(curdir, "straightening.cache") if sct.cache_valid(cachefile, cache_sig) and os.path.isfile(os.path.join(curdir, 'warp_curve2straight.nii.gz')) and os.path.isfile(os.path.join(curdir, 'warp_straight2curve.nii.gz')) and os.path.isfile(os.path.join(curdir, 'straight_ref.nii.gz')): # if they exist, copy them into current folder sct.printv('Reusing existing warping field which seems to be valid', verbose, 'warning') sct.copy(os.path.join(curdir, 'warp_curve2straight.nii.gz'), 'warp_curve2straight.nii.gz') sct.copy(os.path.join(curdir, 'warp_straight2curve.nii.gz'), 'warp_straight2curve.nii.gz') sct.copy(os.path.join(curdir, 'straight_ref.nii.gz'), 'straight_ref.nii.gz') # apply straightening sct.run(['sct_apply_transfo', '-i', 'anat_rpi.nii', '-w', 'warp_curve2straight.nii.gz', '-d', 'straight_ref.nii.gz', '-o', 'anat_rpi_straight.nii', '-x', 'spline'], verbose) else: sct.run(['sct_straighten_spinalcord', '-i', 'anat_rpi.nii', '-s', 'centerline_rpi.nii', '-x', 'spline'], verbose) sct.cache_save(cachefile, cache_sig) # Smooth the straightened image along z sct.printv('\nSmooth the straightened image along z...') sct.run(['sct_maths', '-i', 'anat_rpi_straight.nii', '-smooth', '0,0,' + str(sigma), '-o', 'anat_rpi_straight_smooth.nii'], verbose) # Apply the reversed warping field to get back the curved spinal cord sct.printv('\nApply the reversed warping field to get back the curved spinal cord...') sct.run(['sct_apply_transfo', '-i', 'anat_rpi_straight_smooth.nii', '-o', 'anat_rpi_straight_smooth_curved.nii', '-d', 'anat.nii', '-w', 'warp_straight2curve.nii.gz', '-x', 'spline'], verbose) # replace zeroed voxels by original image (issue #937) sct.printv('\nReplace zeroed voxels by original image...', verbose) nii_smooth = Image('anat_rpi_straight_smooth_curved.nii') data_smooth = nii_smooth.data data_input = Image('anat.nii').data indzero = np.where(data_smooth == 0) data_smooth[indzero] = data_input[indzero] nii_smooth.data = data_smooth nii_smooth.setFileName('anat_rpi_straight_smooth_curved_nonzero.nii') nii_smooth.save() # come back os.chdir(curdir) # Generate output file sct.printv('\nGenerate output file...') sct.generate_output_file(os.path.join(path_tmp, "anat_rpi_straight_smooth_curved_nonzero.nii"), file_anat + '_smooth' + ext_anat) # Remove temporary files if remove_temp_files == 1: sct.printv('\nRemove temporary files...') sct.rmtree(path_tmp) # Display elapsed time elapsed_time = time.time() - start_time sct.printv('\nFinished! Elapsed time: ' + str(int(round(elapsed_time))) + 's\n') sct.display_viewer_syntax([file_anat, file_anat + '_smooth'], verbose=verbose)
import os import commands import sys from shutil import move # Get path of the toolbox status, path_sct = commands.getstatusoutput('echo $SCT_DIR') # Append path that contains scripts, to be able to load modules sys.path.append(path_sct + '/scripts') from msct_image import Image import sct_utils as sct path_template = '/Users/julien/data/PAM50/template' folder_PAM50 = 'PAM50/template/' os.chdir(path_template) sct.create_folder(folder_PAM50) for file_template in [ 'MNI-Poly-AMU_T1.nii.gz', 'MNI-Poly-AMU_T2.nii.gz', 'MNI-Poly-AMU_T2star.nii.gz' ]: im = Image(file_template) # remove negative values data = im.data data[data < 0] = 0 im.data = data im.changeType('uint16') file_new = file_template.replace('MNI-Poly-AMU', 'PAM50') im.setFileName(file_new) im.save() # move to folder move(file_new, folder_PAM50 + file_new)
def execute(self): print 'Execution of the SCAD algorithm' vesselness_file_name = "imageVesselNessFilter.nii.gz" raw_file_name = "raw.nii" if self.debug: import matplotlib.pyplot as plt # import for debug purposes # create tmp and copy input path_tmp = sct.tmp_create() sct.tmp_copy_nifti(self.input_image.absolutepath, path_tmp, raw_file_name) if self.vesselness_provided: sct.run('cp '+vesselness_file_name+' '+path_tmp+vesselness_file_name) os.chdir(path_tmp) # get input image information img = Image(raw_file_name) # save original orientation and change image to RPI self.raw_orientation = img.change_orientation() # get body symmetry sym = SymmetryDetector(raw_file_name, self.contrast, crop_xy=1) self.raw_symmetry = sym.execute() # vesselness filter if not self.vesselness_provided: sct.run('sct_vesselness -i '+raw_file_name+' -t ' + self._contrast) # load vesselness filter data and perform minimum path on it img = Image(vesselness_file_name) raw_orientation = img.change_orientation() self.minimum_path_data, self.J1_min_path, self.J2_min_path = get_minimum_path(img.data, invert=1, debug=1, smooth_factor=1) # Apply an exponent to the minimum path self.minimum_path_powered = np.power(self.minimum_path_data, self.minimum_path_exponent) # Saving in Image since smooth_minimal_path needs pixel dimensions img.data = self.minimum_path_powered # smooth resulting minimal path self.smoothed_min_path = smooth_minimal_path(img) # normalise symmetry values between 0 and 1 normalised_symmetry = equalize_array_histogram(self.raw_symmetry) # multiply normalised symmetry data with the minimum path result self.spine_detect_data = np.multiply(self.smoothed_min_path.data, normalised_symmetry) # extract the centerline from the minimal path image centerline_with_outliers = get_centerline(self.spine_detect_data, self.spine_detect_data.shape) img.data = centerline_with_outliers img.change_orientation() img.file_name = "centerline_with_outliers" img.save() # use a b-spline to smooth out the centerline x, y, z, dx, dy, dz = smooth_centerline("centerline_with_outliers.nii.gz") # save the centerline centerline_dim = img.dim img.data = np.zeros(centerline_dim) for i in range(0, np.size(x)-1): img.data[int(x[i]), int(y[i]), int(z[i])] = 1 img.change_orientation(raw_orientation) img.file_name = "centerline" img.save() # copy back centerline os.chdir('../') sct.tmp_copy_nifti(path_tmp + 'centerline.nii.gz',self.input_image.path,self.input_image.file_name+'_centerline'+self.input_image.ext) if self.rm_tmp_file == 1: import shutil shutil.rmtree(path_tmp) if self.produce_output: self.produce_output_files()
def dmri_moco(param): file_data = 'dmri' ext_data = '.nii' file_b0 = 'b0' file_dwi = 'dwi' mat_final = 'mat_final/' file_dwi_group = 'dwi_averaged_groups' # no extension fsloutput = 'export FSLOUTPUTTYPE=NIFTI; ' # for faster processing, all outputs are in NIFTI ext_mat = 'Warp.nii.gz' # warping field # Get dimensions of data sct.printv('\nGet dimensions of data...', param.verbose) nx, ny, nz, nt, px, py, pz, pt = Image(file_data+'.nii').dim sct.printv(' ' + str(nx) + ' x ' + str(ny) + ' x ' + str(nz), param.verbose) # Identify b=0 and DWI images sct.printv('\nIdentify b=0 and DWI images...', param.verbose) index_b0, index_dwi, nb_b0, nb_dwi = identify_b0('bvecs.txt', param.fname_bvals, param.bval_min, param.verbose) # check if dmri and bvecs are the same size if not nb_b0 + nb_dwi == nt: sct.printv('\nERROR in '+os.path.basename(__file__)+': Size of data ('+str(nt)+') and size of bvecs ('+str(nb_b0+nb_dwi)+') are not the same. Check your bvecs file.\n', 1, 'error') sys.exit(2) # Prepare NIFTI (mean/groups...) #=================================================================================================================== # Split into T dimension sct.printv('\nSplit along T dimension...', param.verbose) status, output = sct.run('sct_split_data -i ' + file_data + ext_data + ' -dim t -suffix _T', param.verbose) # Merge b=0 images sct.printv('\nMerge b=0...', param.verbose) # cmd = fsloutput + 'fslmerge -t ' + file_b0 # for it in range(nb_b0): # cmd = cmd + ' ' + file_data + '_T' + str(index_b0[it]).zfill(4) cmd = 'sct_concat_data -dim t -o ' + file_b0 + ext_data + ' -i ' for it in range(nb_b0): cmd = cmd + file_data + '_T' + str(index_b0[it]).zfill(4) + ext_data + ',' cmd = cmd[:-1] # remove ',' at the end of the string status, output = sct.run(cmd, param.verbose) sct.printv((' File created: ' + file_b0), param.verbose) # Average b=0 images sct.printv('\nAverage b=0...', param.verbose) file_b0_mean = file_b0+'_mean' sct.run('sct_maths -i '+file_b0+'.nii'+' -o '+file_b0_mean+'.nii'+' -mean t', param.verbose) # if not average_data_across_dimension(file_b0+'.nii', file_b0_mean+'.nii', 3): # sct.printv('ERROR in average_data_across_dimension', 1, 'error') # cmd = fsloutput + 'fslmaths ' + file_b0 + ' -Tmean ' + file_b0_mean # status, output = sct.run(cmd, param.verbose) # Number of DWI groups nb_groups = int(math.floor(nb_dwi/param.group_size)) # Generate groups indexes group_indexes = [] for iGroup in range(nb_groups): group_indexes.append(index_dwi[(iGroup*param.group_size):((iGroup+1)*param.group_size)]) # add the remaining images to the last DWI group nb_remaining = nb_dwi%param.group_size # number of remaining images if nb_remaining > 0: nb_groups += 1 group_indexes.append(index_dwi[len(index_dwi)-nb_remaining:len(index_dwi)]) # DWI groups for iGroup in range(nb_groups): sct.printv('\nDWI group: ' +str((iGroup+1))+'/'+str(nb_groups), param.verbose) # get index index_dwi_i = group_indexes[iGroup] nb_dwi_i = len(index_dwi_i) # Merge DW Images sct.printv('Merge DW images...', param.verbose) file_dwi_merge_i = file_dwi + '_' + str(iGroup) cmd = 'sct_concat_data -dim t -o ' + file_dwi_merge_i + ext_data + ' -i ' for it in range(nb_dwi_i): cmd = cmd + file_data + '_T' + str(index_dwi_i[it]).zfill(4) + ext_data + ',' cmd = cmd[:-1] # remove ',' at the end of the string sct.run(cmd, param.verbose) # cmd = fsloutput + 'fslmerge -t ' + file_dwi_merge_i # for it in range(nb_dwi_i): # cmd = cmd +' ' + file_data + '_T' + str(index_dwi_i[it]).zfill(4) # Average DW Images sct.printv('Average DW images...', param.verbose) file_dwi_mean = file_dwi + '_mean_' + str(iGroup) sct.run('sct_maths -i '+file_dwi_merge_i+'.nii'+' -o '+file_dwi_mean+'.nii'+' -mean t', param.verbose) # if not average_data_across_dimension(file_dwi_merge_i+'.nii', file_dwi_mean+'.nii', 3): # sct.printv('ERROR in average_data_across_dimension', 1, 'error') # cmd = fsloutput + 'fslmaths ' + file_dwi_merge_i + ' -Tmean ' + file_dwi_mean # sct.run(cmd, param.verbose) # Merge DWI groups means sct.printv('\nMerging DW files...', param.verbose) # file_dwi_groups_means_merge = 'dwi_averaged_groups' cmd = 'sct_concat_data -dim t -o ' + file_dwi_group + ext_data + ' -i ' for iGroup in range(nb_groups): cmd = cmd + file_dwi + '_mean_' + str(iGroup) + ext_data + ',' cmd = cmd[:-1] # remove ',' at the end of the string sct.run(cmd, param.verbose) # cmd = fsloutput + 'fslmerge -t ' + file_dwi_group # for iGroup in range(nb_groups): # cmd = cmd + ' ' + file_dwi + '_mean_' + str(iGroup) # Average DW Images # TODO: USEFULL ??? sct.printv('\nAveraging all DW images...', param.verbose) fname_dwi_mean = 'dwi_mean' sct.run('sct_maths -i '+file_dwi_group+'.nii'+' -o '+file_dwi_group+'_mean.nii'+' -mean t', param.verbose) # if not average_data_across_dimension(file_dwi_group+'.nii', file_dwi_group+'_mean.nii', 3): # sct.printv('ERROR in average_data_across_dimension', 1, 'error') # sct.run(fsloutput + 'fslmaths ' + file_dwi_group + ' -Tmean ' + file_dwi_group+'_mean', param.verbose) # segment dwi images using otsu algorithm if param.otsu: sct.printv('\nSegment group DWI using OTSU algorithm...', param.verbose) # import module otsu = importlib.import_module('sct_otsu') # get class from module param_otsu = otsu.param() #getattr(otsu, param) param_otsu.fname_data = file_dwi_group+'.nii' param_otsu.threshold = param.otsu param_otsu.file_suffix = '_seg' # run otsu otsu.otsu(param_otsu) file_dwi_group = file_dwi_group+'_seg' # extract first DWI volume as target for registration nii = Image(file_dwi_group+'.nii') data_crop = nii.data[:, :, :, index_dwi[0]:index_dwi[0]+1] nii.data = data_crop nii.setFileName('target_dwi.nii') nii.save() # START MOCO #=================================================================================================================== # Estimate moco on b0 groups sct.printv('\n-------------------------------------------------------------------------------', param.verbose) sct.printv(' Estimating motion on b=0 images...', param.verbose) sct.printv('-------------------------------------------------------------------------------', param.verbose) param_moco = param param_moco.file_data = 'b0' if index_dwi[0] != 0: # If first DWI is not the first volume (most common), then there is a least one b=0 image before. In that case # select it as the target image for registration of all b=0 param_moco.file_target = file_data + '_T' + str(index_b0[index_dwi[0]-1]).zfill(4) else: # If first DWI is the first volume, then the target b=0 is the first b=0 from the index_b0. param_moco.file_target = file_data + '_T' + str(index_b0[0]).zfill(4) param_moco.path_out = '' param_moco.todo = 'estimate' param_moco.mat_moco = 'mat_b0groups' moco.moco(param_moco) # Estimate moco on dwi groups sct.printv('\n-------------------------------------------------------------------------------', param.verbose) sct.printv(' Estimating motion on DW images...', param.verbose) sct.printv('-------------------------------------------------------------------------------', param.verbose) param_moco.file_data = file_dwi_group param_moco.file_target = 'target_dwi' # target is the first DW image (closest to the first b=0) param_moco.path_out = '' #param_moco.todo = 'estimate' param_moco.todo = 'estimate_and_apply' param_moco.mat_moco = 'mat_dwigroups' moco.moco(param_moco) # create final mat folder sct.create_folder(mat_final) # Copy b=0 registration matrices sct.printv('\nCopy b=0 registration matrices...', param.verbose) for it in range(nb_b0): sct.run('cp '+'mat_b0groups/'+'mat.T'+str(it)+ext_mat+' '+mat_final+'mat.T'+str(index_b0[it])+ext_mat, param.verbose) # Copy DWI registration matrices sct.printv('\nCopy DWI registration matrices...', param.verbose) for iGroup in range(nb_groups): for dwi in range(len(group_indexes[iGroup])): sct.run('cp '+'mat_dwigroups/'+'mat.T'+str(iGroup)+ext_mat+' '+mat_final+'mat.T'+str(group_indexes[iGroup][dwi])+ext_mat, param.verbose) # Spline Regularization along T if param.spline_fitting: moco.spline(mat_final, nt, nz, param.verbose, np.array(index_b0), param.plot_graph) # combine Eddy Matrices if param.run_eddy: param.mat_2_combine = 'mat_eddy' param.mat_final = mat_final moco.combine_matrix(param) # Apply moco on all dmri data sct.printv('\n-------------------------------------------------------------------------------', param.verbose) sct.printv(' Apply moco', param.verbose) sct.printv('-------------------------------------------------------------------------------', param.verbose) param_moco.file_data = 'dmri' param_moco.file_target = file_dwi+'_mean_'+str(0) # reference for reslicing into proper coordinate system param_moco.path_out = '' param_moco.mat_moco = mat_final param_moco.todo = 'apply' moco.moco(param_moco) # copy geometric information from header # NB: this is required because WarpImageMultiTransform in 2D mode wrongly sets pixdim(3) to "1". copy_header('dmri.nii', 'dmri_moco.nii') # generate b0_moco_mean and dwi_moco_mean cmd = 'sct_dmri_separate_b0_and_dwi -i dmri'+param.suffix+'.nii -b bvecs.txt -a 1' if not param.fname_bvals == '': cmd = cmd+' -m '+param.fname_bvals sct.run(cmd, param.verbose)
def create_mask(): fsloutput = 'export FSLOUTPUTTYPE=NIFTI; ' # for faster processing, all outputs are in NIFTI # display usage if a mandatory argument is not provided if param.fname_data == '' or param.method == '': sct.printv('\nERROR: All mandatory arguments are not provided. See usage (add -h).\n', 1, 'error') # parse argument for method method_list = param.method.replace(' ', '').split(',') # remove spaces and parse with comma # method_list = param.method.split(',') # parse with comma method_type = method_list[0] # check existence of method type if not method_type in param.method_list: sct.printv('\nERROR in '+os.path.basename(__file__)+': Method "'+method_type+'" is not recognized. See usage (add -h).\n', 1, 'error') # check method val if not method_type == 'center': method_val = method_list[1] del method_list # check existence of shape if not param.shape in param.shape_list: sct.printv('\nERROR in '+os.path.basename(__file__)+': Shape "'+param.shape+'" is not recognized. 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) if method_type == 'centerline': sct.check_file_exist(method_val, param.verbose) # check if orientation is RPI sct.printv('\nCheck if orientation is RPI...', param.verbose) status, output = sct.run('sct_orientation -i '+param.fname_data) if not output == 'RPI': sct.printv('\nERROR in '+os.path.basename(__file__)+': Orientation of input image should be RPI. Use sct_orientation to put your image in RPI.\n', 1, 'error') # display input parameters sct.printv('\nInput parameters:', param.verbose) sct.printv(' data ..................'+param.fname_data, param.verbose) sct.printv(' method ................'+method_type, param.verbose) # Extract path/file/extension path_data, file_data, ext_data = sct.extract_fname(param.fname_data) # Get output folder and file name if param.fname_out == '': param.fname_out = param.file_prefix+file_data+ext_data #fname_out = os.path.abspath(path_out+file_out+ext_out) # 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) convert(param.fname_data, path_tmp+'data.nii') # sct.run('cp '+param.fname_data+' '+path_tmp+'data'+ext_data, param.verbose) if method_type == 'centerline': convert(method_val, path_tmp+'centerline.nii.gz') # sct.run('isct_c3d '+method_val+' -o '+path_tmp+'/centerline.nii.gz') # go to tmp folder os.chdir(path_tmp) # 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) # in case user input 4d data if nt != 1: sct.printv('WARNING in '+os.path.basename(__file__)+': Input image is 4d but output mask will 3D.', param.verbose, 'warning') # extract first volume to have 3d reference nii = Image('data.nii') data3d = nii.data[:,:,:,0] nii.data = data3d nii.save() if method_type == 'coord': # parse to get coordinate coord = map(int, method_val.split('x')) if method_type == 'point': # get file name fname_point = method_val # extract coordinate of point sct.printv('\nExtract coordinate of point...', param.verbose) status, output = sct.run('sct_label_utils -i '+fname_point+' -t display-voxel', param.verbose) # parse to get coordinate coord = output[output.find('Position=')+10:-17].split(',') if method_type == 'center': # set coordinate at center of FOV coord = round(float(nx)/2), round(float(ny)/2) if method_type == 'centerline': # get name of centerline from user argument fname_centerline = 'centerline.nii.gz' else: # generate volume with line along Z at coordinates 'coord' sct.printv('\nCreate line...', param.verbose) fname_centerline = create_line('data.nii', coord, nz) # create mask sct.printv('\nCreate mask...', param.verbose) centerline = nibabel.load(fname_centerline) # open centerline hdr = centerline.get_header() # get header hdr.set_data_dtype('uint8') # set imagetype to uint8 data_centerline = centerline.get_data() # get centerline z_centerline = [iz for iz in range(0, nz, 1) if data_centerline[:, :, iz].any()] nz = len(z_centerline) # get center of mass of the centerline cx = [0] * nz cy = [0] * nz for iz in range(0, nz, 1): cx[iz], cy[iz] = ndimage.measurements.center_of_mass(numpy.array(data_centerline[:, :, z_centerline[iz]])) # create 2d masks file_mask = 'data_mask' for iz in range(nz): center = numpy.array([cx[iz], cy[iz]]) mask2d = create_mask2d(center, param.shape, param.size, nx, ny) # Write NIFTI volumes img = nibabel.Nifti1Image(mask2d, None, hdr) nibabel.save(img, (file_mask+str(iz)+'.nii')) # merge along Z # cmd = 'fslmerge -z mask ' cmd = 'sct_concat_data -dim z -o mask.nii.gz -i ' for iz in range(nz): cmd = cmd + file_mask+str(iz)+'.nii,' # remove ',' at the end of the string cmd = cmd[:-1] status, output = sct.run(cmd, param.verbose) # copy geometry copy_header('data.nii', 'mask.nii.gz') # come back to parent folder os.chdir('..') # Generate output files sct.printv('\nGenerate output files...', param.verbose) sct.generate_output_file(path_tmp+'mask.nii.gz', param.fname_out) # Remove temporary files if param.remove_tmp_files == 1: sct.printv('\nRemove temporary files...', param.verbose) 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_data+' '+param.fname_out+' -l Red -t 0.5 &', param.verbose, 'info') print
def create_mask(): fsloutput = 'export FSLOUTPUTTYPE=NIFTI; ' # for faster processing, all outputs are in NIFTI # parse argument for method method_type = param.process[0] # check method val if not method_type == 'center': method_val = param.process[1] # check existence of input files if method_type == 'centerline': sct.check_file_exist(method_val, param.verbose) # Extract path/file/extension path_data, file_data, ext_data = sct.extract_fname(param.fname_data) # Get output folder and file name if param.fname_out == '': param.fname_out = param.file_prefix + file_data + ext_data # create temporary folder sct.printv('\nCreate temporary folder...', param.verbose) path_tmp = sct.tmp_create(param.verbose) # )sct.slash_at_the_end('tmp.'+time.strftime("%y%m%d%H%M%S"), 1) # sct.run('mkdir '+path_tmp, param.verbose) sct.printv('\nCheck orientation...', param.verbose) orientation_input = get_orientation(Image(param.fname_data)) sct.printv('.. ' + orientation_input, param.verbose) reorient_coordinates = False # copy input data to tmp folder convert(param.fname_data, path_tmp + 'data.nii') if method_type == 'centerline': convert(method_val, path_tmp + 'centerline.nii.gz') if method_type == 'point': convert(method_val, path_tmp + 'point.nii.gz') # go to tmp folder os.chdir(path_tmp) # reorient to RPI sct.printv('\nReorient to RPI...', param.verbose) # if not orientation_input == 'RPI': sct.run('sct_image -i data.nii -o data_RPI.nii -setorient RPI -v 0', verbose=False) if method_type == 'centerline': sct.run( 'sct_image -i centerline.nii.gz -o centerline_RPI.nii.gz -setorient RPI -v 0', verbose=False) if method_type == 'point': sct.run( 'sct_image -i point.nii.gz -o point_RPI.nii.gz -setorient RPI -v 0', verbose=False) # # if method_type == 'centerline': # orientation_centerline = get_orientation_3d(method_val, filename=True) # if not orientation_centerline == 'RPI': # sct.run('sct_image -i ' + method_val + ' -o ' + path_tmp + 'centerline.nii.gz' + ' -setorient RPI -v 0', verbose=False) # else: # convert(method_val, path_tmp+'centerline.nii.gz') # Get dimensions of data sct.printv('\nGet dimensions of data...', param.verbose) nx, ny, nz, nt, px, py, pz, pt = Image('data_RPI.nii').dim sct.printv( ' ' + str(nx) + ' x ' + str(ny) + ' x ' + str(nz) + ' x ' + str(nt), param.verbose) # in case user input 4d data if nt != 1: sct.printv( 'WARNING in ' + os.path.basename(__file__) + ': Input image is 4d but output mask will 3D.', param.verbose, 'warning') # extract first volume to have 3d reference nii = Image('data_RPI.nii') data3d = nii.data[:, :, :, 0] nii.data = data3d nii.save() if method_type == 'coord': # parse to get coordinate coord = map(int, method_val.split('x')) if method_type == 'point': # get file name fname_point = method_val # extract coordinate of point sct.printv('\nExtract coordinate of point...', param.verbose) # TODO: change this way to remove dependence to sct.run. ProcessLabels.display_voxel returns list of coordinates status, output = sct.run( 'sct_label_utils -i point_RPI.nii.gz -display', param.verbose) # parse to get coordinate coord = output[output.find('Position=') + 10:-17].split(',') if method_type == 'center': # set coordinate at center of FOV coord = round(float(nx) / 2), round(float(ny) / 2) if method_type == 'centerline': # get name of centerline from user argument fname_centerline = 'centerline_RPI.nii.gz' else: # generate volume with line along Z at coordinates 'coord' sct.printv('\nCreate line...', param.verbose) fname_centerline = create_line('data_RPI.nii', coord, nz) # create mask sct.printv('\nCreate mask...', param.verbose) centerline = nibabel.load(fname_centerline) # open centerline hdr = centerline.get_header() # get header hdr.set_data_dtype('uint8') # set imagetype to uint8 spacing = hdr.structarr['pixdim'] data_centerline = centerline.get_data() # get centerline # if data is 2D, reshape with empty third dimension if len(data_centerline.shape) == 2: data_centerline_shape = list(data_centerline.shape) data_centerline_shape.append(1) data_centerline = data_centerline.reshape(data_centerline_shape) z_centerline_not_null = [ iz for iz in range(0, nz, 1) if data_centerline[:, :, iz].any() ] # get center of mass of the centerline cx = [0] * nz cy = [0] * nz for iz in range(0, nz, 1): if iz in z_centerline_not_null: cx[iz], cy[iz] = ndimage.measurements.center_of_mass( numpy.array(data_centerline[:, :, iz])) # create 2d masks file_mask = 'data_mask' for iz in range(nz): if iz not in z_centerline_not_null: # write an empty nifty volume img = nibabel.Nifti1Image(data_centerline[:, :, iz], None, hdr) nibabel.save(img, (file_mask + str(iz) + '.nii')) else: center = numpy.array([cx[iz], cy[iz]]) mask2d = create_mask2d(center, param.shape, param.size, nx, ny, even=param.even, spacing=spacing) # Write NIFTI volumes img = nibabel.Nifti1Image(mask2d, None, hdr) nibabel.save(img, (file_mask + str(iz) + '.nii')) # merge along Z # cmd = 'fslmerge -z mask ' # CHANGE THAT CAN IMPACT SPEED: # related to issue #755, we cannot open more than 256 files at one time. # to solve this issue, we do not open more than 100 files ''' im_list = [] im_temp = [] for iz in range(nz_not_null): if iz != 0 and iz % 100 == 0: im_temp.append(concat_data(im_list, 2)) im_list = [Image(file_mask + str(iz) + '.nii')] else: im_list.append(Image(file_mask+str(iz)+'.nii')) if im_temp: im_temp.append(concat_data(im_list, 2)) im_out = concat_data(im_temp, 2, no_expand=True) else: im_out = concat_data(im_list, 2) ''' fname_list = [file_mask + str(iz) + '.nii' for iz in range(nz)] im_out = concat_data(fname_list, dim=2) im_out.setFileName('mask_RPI.nii.gz') im_out.save() # reorient if necessary # if not orientation_input == 'RPI': sct.run( 'sct_image -i mask_RPI.nii.gz -o mask.nii.gz -setorient ' + orientation_input, param.verbose) # copy header input --> mask im_dat = Image('data.nii') im_mask = Image('mask.nii.gz') im_mask = copy_header(im_dat, im_mask) im_mask.save() # come back to parent folder os.chdir('..') # Generate output files sct.printv('\nGenerate output files...', param.verbose) sct.generate_output_file(path_tmp + 'mask.nii.gz', param.fname_out) # Remove temporary files if param.remove_tmp_files == 1: sct.printv('\nRemove temporary files...', param.verbose) sct.run('rm -rf ' + path_tmp, param.verbose, error_exit='warning') # to view results sct.printv('\nDone! To view results, type:', param.verbose) sct.printv( 'fslview ' + param.fname_data + ' ' + param.fname_out + ' -l Red -t 0.5 &', param.verbose, 'info') print
def main(args = None): dim_list = ['x', 'y', 'z', 't'] if not args: args = sys.argv[1:] # Get parser info parser = get_parser() arguments = parser.parse(args) fname_in = arguments["-i"] fname_out = arguments["-o"] verbose = int(arguments['-v']) # Open file(s) im = Image(fname_in) data = im.data # 3d or 4d numpy array dim = im.dim # run command if '-otsu' in arguments: param = arguments['-otsu'] data_out = otsu(data, param) elif '-otsu_adap' in arguments: param = arguments['-otsu_adap'] data_out = otsu_adap(data, param[0], param[1]) elif '-otsu_median' in arguments: param = arguments['-otsu_median'] data_out = otsu_median(data, param[0], param[1]) elif '-thr' in arguments: param = arguments['-thr'] data_out = threshold(data, param) elif '-percent' in arguments: param = arguments['-percent'] data_out = perc(data, param) elif '-bin' in arguments: bin_thr = arguments['-bin'] data_out = binarise(data, bin_thr=bin_thr) elif '-add' in arguments: from numpy import sum data2 = get_data_or_scalar(arguments["-add"], data) data_concat = concatenate_along_4th_dimension(data, data2) data_out = sum(data_concat, axis=3) elif '-sub' in arguments: data2 = get_data_or_scalar(arguments['-sub'], data) data_out = data - data2 elif "-laplacian" in arguments: sigmas = arguments["-laplacian"] if len(sigmas) == 1: sigmas = [sigmas for i in range(len(data.shape))] elif len(sigmas) != len(data.shape): printv(parser.usage.generate(error='ERROR: -laplacian need the same number of inputs as the number of image dimension OR only one input')) # adjust sigma based on voxel size sigmas = [sigmas[i] / dim[i+4] for i in range(3)] # smooth data data_out = laplacian(data, sigmas) elif '-mul' in arguments: from numpy import prod data2 = get_data_or_scalar(arguments["-mul"], data) data_concat = concatenate_along_4th_dimension(data, data2) data_out = prod(data_concat, axis=3) elif '-div' in arguments: from numpy import divide data2 = get_data_or_scalar(arguments["-div"], data) data_out = divide(data, data2) elif '-mean' in arguments: from numpy import mean dim = dim_list.index(arguments['-mean']) if dim+1 > len(np.shape(data)): # in case input volume is 3d and dim=t data = data[..., np.newaxis] data_out = mean(data, dim) elif '-std' in arguments: from numpy import std dim = dim_list.index(arguments['-std']) if dim+1 > len(np.shape(data)): # in case input volume is 3d and dim=t data = data[..., np.newaxis] data_out = std(data, dim) elif "-smooth" in arguments: sigmas = arguments["-smooth"] if len(sigmas) == 1: sigmas = [sigmas[0] for i in range(len(data.shape))] elif len(sigmas) != len(data.shape): printv(parser.usage.generate(error='ERROR: -smooth need the same number of inputs as the number of image dimension OR only one input')) # adjust sigma based on voxel size sigmas = [sigmas[i] / dim[i+4] for i in range(3)] # smooth data data_out = smooth(data, sigmas) elif '-dilate' in arguments: data_out = dilate(data, arguments['-dilate']) elif '-erode' in arguments: data_out = erode(data, arguments['-erode']) elif '-denoise' in arguments: # parse denoising arguments p, b = 1, 5 # default arguments list_denoise = arguments['-denoise'] for i in list_denoise: if 'p' in i: p = int(i.split('=')[1]) if 'b' in i: b = int(i.split('=')[1]) data_out = denoise_nlmeans(data, patch_radius=p, block_radius=b) elif '-symmetrize' in arguments: data_out = (data + data[range(data.shape[0]-1, -1, -1), :, :]) / float(2) elif '-mi' in arguments: # input 1 = from flag -i --> im # input 2 = from flag -mi im_2 = Image(arguments['-mi']) compute_similarity(im.data, im_2.data, fname_out, metric='mi', verbose=verbose) data_out=None elif '-corr' in arguments: # input 1 = from flag -i --> im # input 2 = from flag -mi im_2 = Image(arguments['-corr']) compute_similarity(im.data, im_2.data, fname_out, metric='corr', verbose=verbose) data_out=None # if no flag is set else: data_out = None printv(parser.usage.generate(error='ERROR: you need to specify an operation to do on the input image')) if data_out is not None: # Write output nii_out = Image(fname_in) # use header of input file nii_out.data = data_out nii_out.setFileName(fname_out) nii_out.save() # TODO: case of multiple outputs # assert len(data_out) == n_out # if n_in == n_out: # for im_in, d_out, fn_out in zip(nii, data_out, fname_out): # im_in.data = d_out # im_in.setFileName(fn_out) # if "-w" in arguments: # im_in.hdr.set_intent('vector', (), '') # im_in.save() # elif n_out == 1: # nii[0].data = data_out[0] # nii[0].setFileName(fname_out[0]) # if "-w" in arguments: # nii[0].hdr.set_intent('vector', (), '') # nii[0].save() # elif n_out > n_in: # for dat_out, name_out in zip(data_out, fname_out): # im_out = nii[0].copy() # im_out.data = dat_out # im_out.setFileName(name_out) # if "-w" in arguments: # im_out.hdr.set_intent('vector', (), '') # im_out.save() # else: # printv(parser.usage.generate(error='ERROR: not the correct numbers of inputs and outputs')) # display message if data_out is not None: printv('\nDone! To view results, type:', verbose) printv('fslview '+fname_out+' &\n', verbose, 'info') else: printv('\nDone! File created: '+fname_out, verbose, 'info')