def plan_ref(self): """ Generate a plane in the reference space for each label present in the input image """ image_output = Image(self.image_ref, self.verbose) image_output.data *= 0 image_input_neg = Image(self.image_input, self.verbose).copy() image_input_pos = Image(self.image_input, self.verbose).copy() image_input_neg.data *= 0 image_input_pos.data *= 0 X, Y, Z = (self.image_input.data < 0).nonzero() for i in range(len(X)): image_input_neg.data[X[i], Y[i], Z[i]] = -self.image_input.data[ X[i], Y[i], Z[i]] # in order to apply getNonZeroCoordinates X_pos, Y_pos, Z_pos = (self.image_input.data > 0).nonzero() for i in range(len(X_pos)): image_input_pos.data[X_pos[i], Y_pos[i], Z_pos[i]] = self.image_input.data[X_pos[i], Y_pos[i], Z_pos[i]] coordinates_input_neg = image_input_neg.getNonZeroCoordinates() coordinates_input_pos = image_input_pos.getNonZeroCoordinates() image_output.changeType('float32') for coord in coordinates_input_neg: image_output.data[:, :, int( coord.z )] = -coord.value # PB: takes the int value of coord.value for coord in coordinates_input_pos: image_output.data[:, :, int(coord.z)] = coord.value return image_output
def plan_ref(self): """ Generate a plane in the reference space for each label present in the input image """ image_output = Image(self.image_ref, self.verbose) image_output.data *= 0 image_input_neg = Image(self.image_input, self.verbose).copy() image_input_pos = Image(self.image_input, self.verbose).copy() image_input_neg.data *=0 image_input_pos.data *=0 X, Y, Z = (self.image_input.data< 0).nonzero() for i in range(len(X)): image_input_neg.data[X[i], Y[i], Z[i]] = -self.image_input.data[X[i], Y[i], Z[i]] # in order to apply getNonZeroCoordinates X_pos, Y_pos, Z_pos = (self.image_input.data> 0).nonzero() for i in range(len(X_pos)): image_input_pos.data[X_pos[i], Y_pos[i], Z_pos[i]] = self.image_input.data[X_pos[i], Y_pos[i], Z_pos[i]] coordinates_input_neg = image_input_neg.getNonZeroCoordinates() coordinates_input_pos = image_input_pos.getNonZeroCoordinates() image_output.changeType('float32') for coord in coordinates_input_neg: image_output.data[:, :, int(coord.z)] = -coord.value #PB: takes the int value of coord.value for coord in coordinates_input_pos: image_output.data[:, :, int(coord.z)] = coord.value return image_output
def continuous_vertebral_levels(self): """ This function transforms the vertebral levels file from the template into a continuous file. Instead of having integer representing the vertebral level on each slice, a continuous value that represents the position of the slice in the vertebral level coordinate system. The image must be RPI :return: """ im_input = Image(self.image_input, self.verbose) im_output = Image(self.image_input, self.verbose) im_output.data *= 0 # 1. extract vertebral levels from input image # a. extract centerline # b. for each slice, extract corresponding level nx, ny, nz, nt, px, py, pz, pt = im_input.dim from sct_straighten_spinalcord import smooth_centerline x_centerline_fit, y_centerline_fit, z_centerline_fit, x_centerline_deriv, y_centerline_deriv, z_centerline_deriv = smooth_centerline(self.image_input, algo_fitting='nurbs', verbose=0) value_centerline = np.array([im_input.data[int(x_centerline_fit[it]), int(y_centerline_fit[it]), int(z_centerline_fit[it])] for it in range(len(z_centerline_fit))]) # 2. compute distance for each vertebral level --> Di for i being the vertebral levels vertebral_levels = {} for slice_image, level in enumerate(value_centerline): if level not in vertebral_levels: vertebral_levels[level] = slice_image length_levels = {} for level in vertebral_levels: indexes_slice = np.where(value_centerline == level) length_levels[level] = np.sum([math.sqrt(((x_centerline_fit[indexes_slice[0][index_slice + 1]] - x_centerline_fit[indexes_slice[0][index_slice]])*px)**2 + ((y_centerline_fit[indexes_slice[0][index_slice + 1]] - y_centerline_fit[indexes_slice[0][index_slice]])*py)**2 + ((z_centerline_fit[indexes_slice[0][index_slice + 1]] - z_centerline_fit[indexes_slice[0][index_slice]])*pz)**2) for index_slice in range(len(indexes_slice[0]) - 1)]) # 2. for each slice: # a. identify corresponding vertebral level --> i # b. calculate distance of slice from upper vertebral level --> d # c. compute relative distance in the vertebral level coordinate system --> d/Di continuous_values = {} for it, iz in enumerate(z_centerline_fit): level = value_centerline[it] indexes_slice = np.where(value_centerline == level) indexes_slice = indexes_slice[0][indexes_slice[0] >= it] distance_from_level = np.sum([math.sqrt(((x_centerline_fit[indexes_slice[index_slice + 1]] - x_centerline_fit[indexes_slice[index_slice]]) * px * px) ** 2 + ((y_centerline_fit[indexes_slice[index_slice + 1]] - y_centerline_fit[indexes_slice[index_slice]]) * py * py) ** 2 + ((z_centerline_fit[indexes_slice[index_slice + 1]] - z_centerline_fit[indexes_slice[index_slice]]) * pz * pz) ** 2) for index_slice in range(len(indexes_slice) - 1)]) continuous_values[iz] = level + 2.0 * distance_from_level / float(length_levels[level]) # 3. saving data # for each slice, get all non-zero pixels and replace with continuous values coordinates_input = self.image_input.getNonZeroCoordinates() im_output.changeType('float32') # for all points in input, find the value that has to be set up, depending on the vertebral level for i, coord in enumerate(coordinates_input): im_output.data[int(coord.x), int(coord.y), int(coord.z)] = continuous_values[coord.z] return im_output
def convert(fname_in, fname_out, squeeze_data=True, type=None, verbose=1): """ Convert data :return True/False """ from msct_image import Image from sct_utils import printv printv('sct_convert -i ' + fname_in + ' -o ' + fname_out, verbose, 'code') # Open file im = Image(fname_in) # Save file im.setFileName(fname_out) if type is not None: im.changeType(type=type) im.save(squeeze_data=squeeze_data) return im
def convert(fname_in, fname_out, squeeze_data=True, type=None, verbose=1): """ Convert data :return True/False """ from msct_image import Image from sct_utils import printv printv('sct_convert -i '+fname_in+' -o '+fname_out, verbose, 'code') # Open file im = Image(fname_in) # Save file im.setFileName(fname_out) if type is not None: im.changeType(type=type) im.save(squeeze_data=squeeze_data) return im
#!/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 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'
def run_main(): sct.start_stream_logger() parser = get_parser() args = sys.argv[1:] arguments = parser.parse(args) # Input filename fname_input_data = arguments["-i"] fname_data = os.path.abspath(fname_input_data) # Method used method = 'optic' if "-method" in arguments: method = arguments["-method"] # Contrast type contrast_type = '' if "-c" in arguments: contrast_type = arguments["-c"] if method == 'optic' and not contrast_type: # Contrast must be error = 'ERROR: -c is a mandatory argument when using Optic method.' sct.printv(error, type='error') return # Ga between slices interslice_gap = 10.0 if "-gap" in arguments: interslice_gap = float(arguments["-gap"]) # Output folder if "-ofolder" in arguments: folder_output = sct.slash_at_the_end(arguments["-ofolder"], slash=1) else: folder_output = './' # Remove temporary files remove_temp_files = True if "-r" in arguments: remove_temp_files = bool(int(arguments["-r"])) # Outputs a ROI file output_roi = False if "-roi" in arguments: output_roi = bool(int(arguments["-roi"])) # Verbosity verbose = 0 if "-v" in arguments: verbose = int(arguments["-v"]) if method == 'viewer': path_data, file_data, ext_data = sct.extract_fname(fname_data) # create temporary folder temp_folder = sct.TempFolder() temp_folder.copy_from(fname_data) temp_folder.chdir() # make sure image is in SAL orientation, as it is the orientation used by the viewer image_input = Image(fname_data) image_input_orientation = orientation(image_input, get=True, verbose=False) reoriented_image_filename = sct.add_suffix(file_data + ext_data, "_SAL") cmd_image = 'sct_image -i "%s" -o "%s" -setorient SAL -v 0' % ( fname_data, reoriented_image_filename) sct.run(cmd_image, verbose=False) # extract points manually using the viewer fname_points = viewer_centerline(image_fname=reoriented_image_filename, interslice_gap=interslice_gap, verbose=verbose) if fname_points is not None: image_points_RPI = sct.add_suffix(fname_points, "_RPI") cmd_image = 'sct_image -i "%s" -o "%s" -setorient RPI -v 0' % ( fname_points, image_points_RPI) sct.run(cmd_image, verbose=False) image_input_reoriented = Image(image_points_RPI) # fit centerline, smooth it and return the first derivative (in physical space) x_centerline_fit, y_centerline_fit, z_centerline, x_centerline_deriv, y_centerline_deriv, z_centerline_deriv = smooth_centerline( image_points_RPI, algo_fitting='nurbs', nurbs_pts_number=3000, phys_coordinates=True, verbose=verbose, all_slices=False) centerline = Centerline(x_centerline_fit, y_centerline_fit, z_centerline, x_centerline_deriv, y_centerline_deriv, z_centerline_deriv) # average centerline coordinates over slices of the image x_centerline_fit_rescorr, y_centerline_fit_rescorr, z_centerline_rescorr, x_centerline_deriv_rescorr, y_centerline_deriv_rescorr, z_centerline_deriv_rescorr = centerline.average_coordinates_over_slices( image_input_reoriented) # compute z_centerline in image coordinates for usage in vertebrae mapping voxel_coordinates = image_input_reoriented.transfo_phys2pix([[ x_centerline_fit_rescorr[i], y_centerline_fit_rescorr[i], z_centerline_rescorr[i] ] for i in range(len(z_centerline_rescorr))]) x_centerline_voxel = [coord[0] for coord in voxel_coordinates] y_centerline_voxel = [coord[1] for coord in voxel_coordinates] z_centerline_voxel = [coord[2] for coord in voxel_coordinates] # compute z_centerline in image coordinates with continuous precision voxel_coordinates = image_input_reoriented.transfo_phys2continuouspix( [[ x_centerline_fit_rescorr[i], y_centerline_fit_rescorr[i], z_centerline_rescorr[i] ] for i in range(len(z_centerline_rescorr))]) x_centerline_voxel_cont = [coord[0] for coord in voxel_coordinates] y_centerline_voxel_cont = [coord[1] for coord in voxel_coordinates] z_centerline_voxel_cont = [coord[2] for coord in voxel_coordinates] # Create an image with the centerline image_input_reoriented.data *= 0 min_z_index, max_z_index = int(round( min(z_centerline_voxel))), int(round(max(z_centerline_voxel))) for iz in range(min_z_index, max_z_index + 1): image_input_reoriented.data[ int(round(x_centerline_voxel[iz - min_z_index])), int(round(y_centerline_voxel[iz - min_z_index])), int( 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 sct.printv('\nWrite NIFTI volumes...', verbose) fname_centerline_oriented = file_data + '_centerline' + ext_data image_input_reoriented.setFileName(fname_centerline_oriented) image_input_reoriented.changeType('uint8') image_input_reoriented.save() sct.printv('\nSet to original orientation...', verbose) sct.run('sct_image -i ' + fname_centerline_oriented + ' -setorient ' + image_input_orientation + ' -o ' + fname_centerline_oriented) # create a txt file with the centerline fname_centerline_oriented_txt = file_data + '_centerline.txt' file_results = open(fname_centerline_oriented_txt, 'w') for i in range(min_z_index, max_z_index + 1): file_results.write( str(int(i)) + ' ' + str(round(x_centerline_voxel_cont[i - min_z_index], 2)) + ' ' + str(round(y_centerline_voxel_cont[i - min_z_index], 2)) + '\n') file_results.close() fname_centerline_oriented_roi = optic.centerline2roi( fname_image=fname_centerline_oriented, folder_output='./', verbose=verbose) # return to initial folder temp_folder.chdir_undo() # copy result to output folder shutil.copy(temp_folder.get_path() + fname_centerline_oriented, folder_output) shutil.copy(temp_folder.get_path() + fname_centerline_oriented_txt, folder_output) if output_roi: shutil.copy( temp_folder.get_path() + fname_centerline_oriented_roi, folder_output) centerline_filename = folder_output + fname_centerline_oriented else: centerline_filename = 'error' # delete temporary folder if remove_temp_files: temp_folder.cleanup() else: # condition on verbose when using OptiC if verbose == 1: verbose = 2 # OptiC models path_script = os.path.dirname(__file__) path_sct = os.path.dirname(path_script) optic_models_path = os.path.join(path_sct, 'data/optic_models', '{}_model'.format(contrast_type)) # Execute OptiC binary _, centerline_filename = optic.detect_centerline( image_fname=fname_data, contrast_type=contrast_type, optic_models_path=optic_models_path, folder_output=folder_output, remove_temp_files=remove_temp_files, output_roi=output_roi, verbose=verbose) sct.printv('\nDone! To view results, type:', verbose) sct.printv( "fslview " + fname_input_data + " " + centerline_filename + " -l Red -b 0,1 -t 0.7 &\n", verbose, 'info')
# Create output text file if output_file_name != None : file_name = output_file_name else: file_name = 'generated_centerline.txt' sct.printv('\nWrite text file...') #file_results = open("../"+file_name, 'w') file_results = open(file_name, 'w') for i in range(0, z_centerline_fit.shape[0], 1): file_results.write(str(int(z_centerline_fit[i])) + ' ' + str(x_centerline_fit[i]) + ' ' + str(y_centerline_fit[i]) + '\n') file_results.close() #return file_name # ======================================================================================================================= # Start program #======================================================================================================================= if __name__ == "__main__": parser = Parser(__file__) parser.usage.set_description('Class to process centerline extraction from.') parser.add_option() arguments = parser.parse(sys.argv[1:]) image = Image(arguments["-i"]) image.changeType('minimize')
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 continuous_vertebral_levels(self): """ This function transforms the vertebral levels file from the template into a continuous file. Instead of having integer representing the vertebral level on each slice, a continuous value that represents the position of the slice in the vertebral level coordinate system. The image must be RPI :return: """ im_input = Image(self.image_input, self.verbose) im_output = Image(self.image_input, self.verbose) im_output.data *= 0 # 1. extract vertebral levels from input image # a. extract centerline # b. for each slice, extract corresponding level nx, ny, nz, nt, px, py, pz, pt = im_input.dim from sct_straighten_spinalcord import smooth_centerline x_centerline_fit, y_centerline_fit, z_centerline_fit, x_centerline_deriv, y_centerline_deriv, z_centerline_deriv = smooth_centerline( self.image_input, algo_fitting='nurbs', verbose=0) value_centerline = np.array([ im_input.data[int(x_centerline_fit[it]), int(y_centerline_fit[it]), int(z_centerline_fit[it])] for it in range(len(z_centerline_fit)) ]) # 2. compute distance for each vertebral level --> Di for i being the vertebral levels vertebral_levels = {} for slice_image, level in enumerate(value_centerline): if level not in vertebral_levels: vertebral_levels[level] = slice_image length_levels = {} for level in vertebral_levels: indexes_slice = np.where(value_centerline == level) length_levels[level] = np.sum([ math.sqrt( ((x_centerline_fit[indexes_slice[0][index_slice + 1]] - x_centerline_fit[indexes_slice[0][index_slice]]) * px)**2 + ((y_centerline_fit[indexes_slice[0][index_slice + 1]] - y_centerline_fit[indexes_slice[0][index_slice]]) * py)**2 + ((z_centerline_fit[indexes_slice[0][index_slice + 1]] - z_centerline_fit[indexes_slice[0][index_slice]]) * pz)**2) for index_slice in range(len(indexes_slice[0]) - 1) ]) # 2. for each slice: # a. identify corresponding vertebral level --> i # b. calculate distance of slice from upper vertebral level --> d # c. compute relative distance in the vertebral level coordinate system --> d/Di continuous_values = {} for it, iz in enumerate(z_centerline_fit): level = value_centerline[it] indexes_slice = np.where(value_centerline == level) indexes_slice = indexes_slice[0][indexes_slice[0] >= it] distance_from_level = np.sum([ math.sqrt(((x_centerline_fit[indexes_slice[index_slice + 1]] - x_centerline_fit[indexes_slice[index_slice]]) * px * px)**2 + ((y_centerline_fit[indexes_slice[index_slice + 1]] - y_centerline_fit[indexes_slice[index_slice]]) * py * py)**2 + ((z_centerline_fit[indexes_slice[index_slice + 1]] - z_centerline_fit[indexes_slice[index_slice]]) * pz * pz)**2) for index_slice in range(len(indexes_slice) - 1) ]) continuous_values[iz] = level + 2.0 * distance_from_level / float( length_levels[level]) # 3. saving data # for each slice, get all non-zero pixels and replace with continuous values coordinates_input = self.image_input.getNonZeroCoordinates() im_output.changeType('float32') # for all points in input, find the value that has to be set up, depending on the vertebral level for i, coord in enumerate(coordinates_input): im_output.data[int(coord.x), int(coord.y), int(coord.z)] = continuous_values[coord.z] return im_output
#!/usr/bin/env python from skimage import transform as tf from skimage import data from msct_image import Image from math import pi im0 = Image('data_by_slice/slice_0_im.nii.gz') seg0 = Image('data_by_slice/slice_0_seg.nii.gz') ''' transfo = tf.SimilarityTransform(scale=1, rotation=pi / 2, translation=(0, 1)) print transfo.params im0.changeType('uint8') print im0.data text = data.text() im_moved = tf.warp(transfo, text) # im0.data) print im_moved Image(param=im_moved, absolutepath='moved_slice_0.nii.gz').save() ''' text = data.text() seg0.changeType('uint8') test = seg0.data Image(param=test, absolutepath='converted_slice_0_seg.nii.gz').save()