def register_seg(seg_input, seg_dest): """Slice-by-slice registration by translation of two segmentations. For each slice, we estimate the translation vector by calculating the difference of position of the two centers of mass. The segmentations can be of different sizes but the output segmentation must be smaller than the input segmentation. input: seg_input: name of moving segmentation file (type: string) seg_dest: name of fixed segmentation file (type: string) output: x_displacement: list of translation along x axis for each slice (type: list) y_displacement: list of translation along y axis for each slice (type: list) """ seg_input_img = Image(seg_input) seg_dest_img = Image(seg_dest) seg_input_data = seg_input_img.data seg_dest_data = seg_dest_img.data x_center_of_mass_input = [0 for i in range(seg_dest_data.shape[2])] y_center_of_mass_input = [0 for i in range(seg_dest_data.shape[2])] print '\nGet center of mass of the input segmentation for each slice (corresponding to a slice in the output segmentation)...' #different if size of the two seg are different #TO DO: select only the slices corresponding to the output segmentation coord_origin_dest = seg_dest_img.transfo_pix2phys([[0, 0, 0]]) [[x_o, y_o, z_o]] = seg_input_img.transfo_phys2pix(coord_origin_dest) for iz in xrange(seg_dest_data.shape[2]): x_center_of_mass_input[iz], y_center_of_mass_input[ iz] = ndimage.measurements.center_of_mass( array(seg_input_data[:, :, z_o + iz])) x_center_of_mass_output = [0 for i in range(seg_dest_data.shape[2])] y_center_of_mass_output = [0 for i in range(seg_dest_data.shape[2])] print '\nGet center of mass of the output segmentation for each slice ...' for iz in xrange(seg_dest_data.shape[2]): x_center_of_mass_output[iz], y_center_of_mass_output[ iz] = ndimage.measurements.center_of_mass( array(seg_dest_data[:, :, iz])) x_displacement = [0 for i in range(seg_input_data.shape[2])] y_displacement = [0 for i in range(seg_input_data.shape[2])] print '\nGet displacement by voxel...' for iz in xrange(seg_dest_data.shape[2]): x_displacement[iz] = -( x_center_of_mass_output[iz] - x_center_of_mass_input[iz] ) # WARNING: in ITK's coordinate system, this is actually Tx and not -Tx y_displacement[ iz] = y_center_of_mass_output[iz] - y_center_of_mass_input[ iz] # This is Ty in ITK's and fslview' coordinate systems return x_displacement, y_displacement
def register_seg(seg_input, seg_dest): """Slice-by-slice registration by translation of two segmentations. For each slice, we estimate the translation vector by calculating the difference of position of the two centers of mass. The segmentations can be of different sizes but the output segmentation must be smaller than the input segmentation. input: seg_input: name of moving segmentation file (type: string) seg_dest: name of fixed segmentation file (type: string) output: x_displacement: list of translation along x axis for each slice (type: list) y_displacement: list of translation along y axis for each slice (type: list) """ seg_input_img = Image(seg_input) seg_dest_img = Image(seg_dest) seg_input_data = seg_input_img.data seg_dest_data = seg_dest_img.data x_center_of_mass_input = [0 for i in range(seg_dest_data.shape[2])] y_center_of_mass_input = [0 for i in range(seg_dest_data.shape[2])] print "\nGet center of mass of the input segmentation for each slice (corresponding to a slice in the output segmentation)..." # different if size of the two seg are different # TO DO: select only the slices corresponding to the output segmentation coord_origin_dest = seg_dest_img.transfo_pix2phys([[0, 0, 0]]) [[x_o, y_o, z_o]] = seg_input_img.transfo_phys2pix(coord_origin_dest) for iz in xrange(seg_dest_data.shape[2]): x_center_of_mass_input[iz], y_center_of_mass_input[iz] = ndimage.measurements.center_of_mass( array(seg_input_data[:, :, z_o + iz]) ) x_center_of_mass_output = [0 for i in range(seg_dest_data.shape[2])] y_center_of_mass_output = [0 for i in range(seg_dest_data.shape[2])] print "\nGet center of mass of the output segmentation for each slice ..." for iz in xrange(seg_dest_data.shape[2]): x_center_of_mass_output[iz], y_center_of_mass_output[iz] = ndimage.measurements.center_of_mass( array(seg_dest_data[:, :, iz]) ) x_displacement = [0 for i in range(seg_input_data.shape[2])] y_displacement = [0 for i in range(seg_input_data.shape[2])] print "\nGet displacement by voxel..." for iz in xrange(seg_dest_data.shape[2]): x_displacement[iz] = -( x_center_of_mass_output[iz] - x_center_of_mass_input[iz] ) # WARNING: in ITK's coordinate system, this is actually Tx and not -Tx y_displacement[iz] = ( y_center_of_mass_output[iz] - y_center_of_mass_input[iz] ) # This is Ty in ITK's and fslview' coordinate systems return x_displacement, y_displacement
def register_seg(seg_input, seg_dest): seg_input_img = Image(seg_input) seg_dest_img = Image(seg_dest) seg_input_data = seg_input_img.data seg_dest_data = seg_dest_img.data x_center_of_mass_input = [0 for i in range(seg_dest_data.shape[2])] y_center_of_mass_input = [0 for i in range(seg_dest_data.shape[2])] print '\nGet center of mass of the input segmentation for each slice (corresponding to a slice in the output segmentation)...' #different if size of the two seg are different #TO DO: select only the slices corresponding to the output segmentation coord_origin_dest = seg_dest_img.transfo_pix2phys([[0, 0, 0]]) [[x_o, y_o, z_o]] = seg_input_img.transfo_phys2pix(coord_origin_dest) for iz in xrange(seg_dest_data.shape[2]): print iz x_center_of_mass_input[iz], y_center_of_mass_input[ iz] = ndimage.measurements.center_of_mass( array(seg_input_data[:, :, z_o + iz])) x_center_of_mass_output = [0 for i in range(seg_dest_data.shape[2])] y_center_of_mass_output = [0 for i in range(seg_dest_data.shape[2])] print '\nGet center of mass of the output segmentation for each slice ...' for iz in xrange(seg_dest_data.shape[2]): x_center_of_mass_output[iz], y_center_of_mass_output[ iz] = ndimage.measurements.center_of_mass( array(seg_dest_data[:, :, iz])) x_displacement = [0 for i in range(seg_input_data.shape[2])] y_displacement = [0 for i in range(seg_input_data.shape[2])] print '\nGet displacement by voxel...' for iz in xrange(seg_dest_data.shape[2]): x_displacement[iz] = -( x_center_of_mass_output[iz] - x_center_of_mass_input[iz] ) #strangely, this is the inverse of x_displacement when the same equation defines y_displacement y_displacement[ iz] = y_center_of_mass_output[iz] - y_center_of_mass_input[iz] return x_displacement, y_displacement
def register_seg(seg_input, seg_dest): seg_input_img = Image(seg_input) seg_dest_img = Image(seg_dest) seg_input_data = seg_input_img.data seg_dest_data = seg_dest_img.data x_center_of_mass_input = [0 for i in range(seg_dest_data.shape[2])] y_center_of_mass_input = [0 for i in range(seg_dest_data.shape[2])] print "\nGet center of mass of the input segmentation for each slice (corresponding to a slice in the output segmentation)..." # different if size of the two seg are different # TO DO: select only the slices corresponding to the output segmentation coord_origin_dest = seg_dest_img.transfo_pix2phys([[0, 0, 0]]) [[x_o, y_o, z_o]] = seg_input_img.transfo_phys2pix(coord_origin_dest) for iz in xrange(seg_dest_data.shape[2]): print iz x_center_of_mass_input[iz], y_center_of_mass_input[iz] = ndimage.measurements.center_of_mass( array(seg_input_data[:, :, z_o + iz]) ) x_center_of_mass_output = [0 for i in range(seg_dest_data.shape[2])] y_center_of_mass_output = [0 for i in range(seg_dest_data.shape[2])] print "\nGet center of mass of the output segmentation for each slice ..." for iz in xrange(seg_dest_data.shape[2]): x_center_of_mass_output[iz], y_center_of_mass_output[iz] = ndimage.measurements.center_of_mass( array(seg_dest_data[:, :, iz]) ) x_displacement = [0 for i in range(seg_input_data.shape[2])] y_displacement = [0 for i in range(seg_input_data.shape[2])] print "\nGet displacement by voxel..." for iz in xrange(seg_dest_data.shape[2]): x_displacement[iz] = -( x_center_of_mass_output[iz] - x_center_of_mass_input[iz] ) # strangely, this is the inverse of x_displacement when the same equation defines y_displacement y_displacement[iz] = y_center_of_mass_output[iz] - y_center_of_mass_input[iz] return x_displacement, y_displacement
def normalize_intensity_template(dataset_info, fname_template_centerline=None, contrast='t1', verbose=1): """ This function normalizes the intensity of the image inside the spinal cord :param fname_template: path to template image :param fname_template_centerline: path to template centerline (binary image or npz) :return: """ path_data = dataset_info['path_data'] list_subjects = dataset_info['subjects'] path_template = dataset_info['path_template'] average_intensity = [] intensity_profiles = {} timer_profile = sct.Timer(len(list_subjects)) timer_profile.start() # computing the intensity profile for each subject for subject_name in list_subjects: path_data_subject = path_data + subject_name + '/' + contrast + '/' if fname_template_centerline is None: fname_image = path_data_subject + contrast + '.nii.gz' fname_image_centerline = path_data_subject + contrast + dataset_info['suffix_centerline'] + '.nii.gz' else: fname_image = path_data_subject + contrast + '_straight.nii.gz' if fname_template_centerline.endswith('.npz'): fname_image_centerline = None else: fname_image_centerline = fname_template_centerline image = Image(fname_image) nx, ny, nz, nt, px, py, pz, pt = image.dim if fname_image_centerline is not None: # open centerline from template number_of_points_in_centerline = 4000 x_centerline_fit, y_centerline_fit, z_centerline, x_centerline_deriv, y_centerline_deriv, z_centerline_deriv = smooth_centerline( fname_image_centerline, algo_fitting='nurbs', verbose=0, nurbs_pts_number=number_of_points_in_centerline, 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) else: centerline_template = Centerline(fname=fname_template_centerline) x, y, z, xd, yd, zd = centerline_template.average_coordinates_over_slices(image) # Compute intensity values z_values, intensities = [], [] extend = 1 # this means the mean intensity of the slice will be calculated over a 3x3 square for i in range(len(z)): coord_z = image.transfo_phys2pix([[x[i], y[i], z[i]]])[0] z_values.append(coord_z[2]) intensities.append(np.mean(image.data[coord_z[0] - extend - 1:coord_z[0] + extend, coord_z[1] - extend - 1:coord_z[1] + extend, coord_z[2]])) # for the slices that are not in the image, extend min and max values to cover the whole image min_z, max_z = min(z_values), max(z_values) intensities_temp = copy(intensities) z_values_temp = copy(z_values) for cz in range(nz): if cz not in z_values: z_values_temp.append(cz) if cz < min_z: intensities_temp.append(intensities[z_values.index(min_z)]) elif cz > max_z: intensities_temp.append(intensities[z_values.index(max_z)]) else: print 'error...', cz intensities = intensities_temp z_values = z_values_temp # Preparing data for smoothing arr_int = [[z_values[i], intensities[i]] for i in range(len(z_values))] arr_int.sort(key=lambda x: x[0]) # and make sure it is ordered with z def smooth(x, window_len=11, window='hanning'): """smooth the data using a window with requested size. """ if x.ndim != 1: raise ValueError, "smooth only accepts 1 dimension arrays." if x.size < window_len: raise ValueError, "Input vector needs to be bigger than window size." if window_len < 3: return x if not window in ['flat', 'hanning', 'hamming', 'bartlett', 'blackman']: raise ValueError, "Window is on of 'flat', 'hanning', 'hamming', 'bartlett', 'blackman'" s = np.r_[x[window_len - 1:0:-1], x, x[-2:-window_len - 1:-1]] if window == 'flat': # moving average w = np.ones(window_len, 'd') else: w = eval('np.' + window + '(window_len)') y = np.convolve(w / w.sum(), s, mode='same') return y[window_len - 1:-window_len + 1] # Smoothing intensities = [c[1] for c in arr_int] intensity_profile_smooth = smooth(np.array(intensities), window_len=50) average_intensity.append(np.mean(intensity_profile_smooth)) intensity_profiles[subject_name] = intensity_profile_smooth if verbose == 2: import matplotlib.pyplot as plt plt.figure() plt.title(subject_name) plt.plot(intensities) plt.plot(intensity_profile_smooth) plt.show() # set the average image intensity over the entire dataset average_intensity = 1000.0 # normalize the intensity of the image based on spinal cord for subject_name in list_subjects: path_data_subject = path_data + subject_name + '/' + contrast + '/' fname_image = path_data_subject + contrast + '_straight.nii.gz' image = Image(fname_image) nx, ny, nz, nt, px, py, pz, pt = image.dim image_image_new = image.copy() image_image_new.changeType(type='float32') for i in range(nz): image_image_new.data[:, :, i] *= average_intensity / intensity_profiles[subject_name][i] # Save intensity normalized template fname_image_normalized = sct.add_suffix(fname_image, '_norm') image_image_new.setFileName(fname_image_normalized) image_image_new.save()
# # generate_warping_field('data_T2_RPI.nii.gz', x_disp_2_smooth, y_disp_2_smooth, fname='warping_field_im_trans.nii.gz') # sct.run('sct_apply_transfo -i data_RPI_registered_reg1.nii.gz -d data_T2_RPI.nii.gz -w warping_field_im_trans.nii.gz -o data_RPI_registered_reg2.nii.gz -x spline') f_1 = "/Users/tamag/data/data_template/independant_templates/Results_magma/t2_avg_RPI.nii.gz" f_2 = "/Users/tamag/data/data_template/independant_templates/Results_magma/t1_avg.independent_RPI_reg1_unpad.nii.gz" f_3 = "/Users/tamag/data/data_template/independant_templates/Results_magma/t1_avg.independent_RPI.nii.gz" os.chdir("/Users/tamag/data/data_template/independant_templates/Results_magma") im_1 = Image(f_1) im_2 = Image(f_2) data_1 = im_1.data coord_test1 = [[1, 1, 1]] coord_test = [[1, 1, 1], [2, 2, 2], [3, 3, 3]] coordi_phys = im_1.transfo_pix2phys(coordi=coord_test) coordi_pix = im_1.transfo_phys2pix(coordi=coordi_phys) bla # im_3 = nibabel.load(f_3) # data_3 = im_3.get_data() # hdr_3 = im_3.get_header() # # data_f = data_3 - laplace(data_3) # # img_f = nibabel.Nifti1Image(data_f, None, hdr_3) # nibabel.save(img_f, "rehauss.nii.gz")
# # generate_warping_field('data_T2_RPI.nii.gz', x_disp_2_smooth, y_disp_2_smooth, fname='warping_field_im_trans.nii.gz') # sct.run('sct_apply_transfo -i data_RPI_registered_reg1.nii.gz -d data_T2_RPI.nii.gz -w warping_field_im_trans.nii.gz -o data_RPI_registered_reg2.nii.gz -x spline') f_1 = "/Users/tamag/data/data_template/independant_templates/Results_magma/t2_avg_RPI.nii.gz" f_2 = "/Users/tamag/data/data_template/independant_templates/Results_magma/t1_avg.independent_RPI_reg1_unpad.nii.gz" f_3 = "/Users/tamag/data/data_template/independant_templates/Results_magma/t1_avg.independent_RPI.nii.gz" os.chdir("/Users/tamag/data/data_template/independant_templates/Results_magma") im_1 = Image(f_1) im_2 = Image(f_2) data_1 = im_1.data coord_test1 = [[1,1,1]] coord_test = [[1,1,1],[2,2,2],[3,3,3]] coordi_phys = im_1.transfo_pix2phys(coordi=coord_test) coordi_pix = im_1.transfo_phys2pix(coordi = coordi_phys) bla # im_3 = nibabel.load(f_3) # data_3 = im_3.get_data() # hdr_3 = im_3.get_header() # # data_f = data_3 - laplace(data_3) # # img_f = nibabel.Nifti1Image(data_f, None, hdr_3) # nibabel.save(img_f, "rehauss.nii.gz")
def project_labels_on_spinalcord(fname_label, fname_seg): """ Project labels orthogonally on the spinal cord centerline. The algorithm works by finding the smallest distance between each label and the spinal cord center of mass. :param fname_label: file name of labels :param fname_seg: file name of cord segmentation (could also be of centerline) :return: file name of projected labels """ # build output name fname_label_projected = sct.add_suffix(fname_label, "_projected") # open labels and segmentation im_label = Image(fname_label) im_seg = Image(fname_seg) # orient to RPI native_orient = im_seg.change_orientation('RPI') im_label.change_orientation('RPI') # smooth centerline and return fitted coordinates in voxel space centerline_x, centerline_y, centerline_z, centerline_derivx, centerline_derivy, centerline_derivz = smooth_centerline( im_seg, algo_fitting="hanning", type_window="hanning", window_length=50, nurbs_pts_number=3000, phys_coordinates=False, all_slices=True) # convert pixel into physical coordinates centerline_xyz_transposed = [ im_seg.transfo_pix2phys( [[centerline_x[i], centerline_y[i], centerline_z[i]]])[0] for i in range(len(centerline_x)) ] # transpose list centerline_phys_x, centerline_phys_y, centerline_phys_z = map( list, map(None, *centerline_xyz_transposed)) # get center of mass of label labels = im_label.getCoordinatesAveragedByValue() # initialize image of projected labels. Note that we use the space of the seg (not label). im_label_projected = im_seg.copy() im_label_projected.data = np.zeros(im_label_projected.data.shape, dtype='uint8') # loop across label values for label in labels: # convert pixel into physical coordinates for the label label_phys_x, label_phys_y, label_phys_z = im_label.transfo_pix2phys( [[label.x, label.y, label.z]])[0] # calculate distance between label and each point of the centerline distance_centerline = [ np.linalg.norm([ centerline_phys_x[i] - label_phys_x, centerline_phys_y[i] - label_phys_y, centerline_phys_z[i] - label_phys_z ]) for i in range(len(centerline_x)) ] # get the index corresponding to the min distance ind_min_distance = np.argmin(distance_centerline) # get centerline coordinate (in physical space) [min_phy_x, min_phy_y, min_phy_z] = [ centerline_phys_x[ind_min_distance], centerline_phys_y[ind_min_distance], centerline_phys_z[ind_min_distance] ] # convert coordinate to voxel space minx, miny, minz = im_seg.transfo_phys2pix( [[min_phy_x, min_phy_y, min_phy_z]])[0] # use that index to assign projected label in the centerline im_label_projected.data[minx, miny, minz] = label.value # re-orient projected labels to native orientation and save im_label_projected.change_orientation( native_orient) # note: native_orient refers to im_seg (not im_label) im_label_projected.setFileName(fname_label_projected) im_label_projected.save() return fname_label_projected
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')
def register_images( im_input, im_dest, mask="", paramreg=Paramreg( step="0", type="im", algo="Translation", metric="MI", iter="5", shrink="1", smooth="0", gradStep="0.5" ), remove_tmp_folder=1, ): path_i, root_i, ext_i = sct.extract_fname(im_input) path_d, root_d, ext_d = sct.extract_fname(im_dest) path_m, root_m, ext_m = sct.extract_fname(mask) # set metricSize if paramreg.metric == "MI": metricSize = "32" # corresponds to number of bins else: metricSize = "4" # corresponds to radius (for CC, MeanSquares...) # 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": ",3,32", } # Get image dimensions and retrieve nz print "\nGet image dimensions of destination image..." nx, ny, nz, nt, px, py, pz, pt = sct.get_dimension(im_dest) print ".. matrix size: " + str(nx) + " x " + str(ny) + " x " + str(nz) print ".. voxel size: " + str(px) + "mm x " + str(py) + "mm x " + str(pz) + "mm" # Define x and y displacement as list x_displacement = [0 for i in range(nz)] y_displacement = [0 for i in range(nz)] theta_rotation = [0 for i in range(nz)] matrix_def = [0 for i in range(nz)] # create temporary folder print ("\nCreate temporary folder...") path_tmp = "tmp." + time.strftime("%y%m%d%H%M%S") sct.create_folder(path_tmp) print "\nCopy input data..." sct.run("cp " + im_input + " " + path_tmp + "/" + root_i + ext_i) sct.run("cp " + im_dest + " " + path_tmp + "/" + root_d + ext_d) if mask: sct.run("cp " + mask + " " + path_tmp + "/mask.nii.gz") # go to temporary folder os.chdir(path_tmp) # Split input volume along z print "\nSplit input volume..." sct.run(sct.fsloutput + "fslsplit " + im_input + " " + root_i + "_z -z") # file_anat_split = ['tmp.anat_orient_z'+str(z).zfill(4) for z in range(0,nz,1)] # Split destination volume along z print "\nSplit destination volume..." sct.run(sct.fsloutput + "fslsplit " + im_dest + " " + root_d + "_z -z") # file_anat_split = ['tmp.anat_orient_z'+str(z).zfill(4) for z in range(0,nz,1)] # Split mask volume along z if mask: print "\nSplit mask volume..." sct.run(sct.fsloutput + "fslsplit mask.nii.gz mask_z -z") # file_anat_split = ['tmp.anat_orient_z'+str(z).zfill(4) for z in range(0,nz,1)] im_dest_img = Image(im_dest) im_input_img = Image(im_input) coord_origin_dest = im_dest_img.transfo_pix2phys([[0, 0, 0]]) coord_origin_input = im_input_img.transfo_pix2phys([[0, 0, 0]]) coord_diff_origin_z = coord_origin_dest[0][2] - coord_origin_input[0][2] [[x_o, y_o, z_o]] = im_input_img.transfo_phys2pix([[0, 0, coord_diff_origin_z]]) # loop across slices for i in range(nz): # set masking num = numerotation(i) num_2 = numerotation(int(num) + z_o) if mask: masking = "-x mask_z" + num + ".nii" else: masking = "" cmd = ( "isct_antsRegistration " "--dimensionality 2 " "--transform " + paramreg.algo + "[" + paramreg.gradStep + ants_registration_params[paramreg.algo.lower()] + "] " "--metric " + paramreg.metric + "[" + root_d + "_z" + num + ".nii" + "," + root_i + "_z" + num_2 + ".nii" + ",1," + metricSize + "] " # [fixedImage,movingImage,metricWeight +nb_of_bins (MI) or radius (other) "--convergence " + paramreg.iter + " " "--shrink-factors " + paramreg.shrink + " " "--smoothing-sigmas " + paramreg.smooth + "mm " #'--restrict-deformation 1x1x0 ' # how to restrict? should not restrict here, if transform is precised...? "--output [transform_" + num + "] " # --> file.txt (contains Tx,Ty) [outputTransformPrefix,<outputWarpedImage>,<outputInverseWarpedImage>] "--interpolation BSpline[3] " + masking ) try: sct.run(cmd) if paramreg.algo == "Rigid" or paramreg.algo == "Translation": f = "transform_" + num + "0GenericAffine.mat" matfile = loadmat(f, struct_as_record=True) array_transfo = matfile["AffineTransform_double_2_2"] if i == 20 or i == 40: print i x_displacement[i] = -array_transfo[4][0] # is it? or is it y? y_displacement[i] = array_transfo[5][0] theta_rotation[i] = asin(array_transfo[2]) if paramreg.algo == "Affine": f = "transform_" + num + "0GenericAffine.mat" matfile = loadmat(f, struct_as_record=True) array_transfo = matfile["AffineTransform_double_2_2"] x_displacement[i] = -array_transfo[4][0] # is it? or is it y? y_displacement[i] = array_transfo[5][0] matrix_def[i] = [ [array_transfo[0][0], array_transfo[1][0]], [array_transfo[2][0], array_transfo[3][0]], ] # comment savoir lequel est lequel? except: if paramreg.algo == "Rigid" or paramreg.algo == "Translation": x_displacement[i] = x_displacement[i - 1] # is it? or is it y? y_displacement[i] = y_displacement[i - 1] theta_rotation[i] = theta_rotation[i - 1] if paramreg.algo == "Affine": x_displacement[i] = x_displacement[i - 1] y_displacement[i] = y_displacement[i - 1] matrix_def[i] = matrix_def[i - 1] # # get displacement form this slice and complete x and y displacement lists # with open('transform_'+num+'.csv') as f: # reader = csv.reader(f) # count = 0 # for line in reader: # count += 1 # if count == 2: # x_displacement[i] = line[0] # y_displacement[i] = line[1] # f.close() # # get matrix of transfo for a rigid transform (pb slicereg fait une rotation ie le deplacement n'est pas homogene par slice) # # recuperer le deplacement ne donnerait pas une liste mais un warping field: mieux vaut recup la matrice output # # pb du smoothing du deplacement par slice !! on peut smoother les param theta tx ty # if paramreg.algo == 'Rigid' or paramreg.algo == 'Translation': # f = 'transform_' +num+ '0GenericAffine.mat' # matfile = loadmat(f, struct_as_record=True) # array_transfo = matfile['AffineTransform_double_2_2'] # x_displacement[i] = -array_transfo[4][0] #is it? or is it y? # y_displacement[i] = array_transfo[5][0] # theta_rotation[i] = acos(array_transfo[0]) # TO DO: different treatment for other algo # Delete tmp folder os.chdir("../") if remove_tmp_folder: print ("\nRemove temporary files...") sct.run("rm -rf " + path_tmp) if paramreg.algo == "Rigid": return ( x_displacement, y_displacement, theta_rotation, ) # check if the displacement are not inverted (x_dis = -x_disp...) theta is in radian if paramreg.algo == "Translation": return x_displacement, y_displacement if paramreg.algo == "Affine": return x_displacement, y_displacement, matrix_def
def register_images(im_input, im_dest, mask='', paramreg=Paramreg(step='0', type='im', algo='Translation', metric='MI', iter='5', shrink='1', smooth='0', gradStep='0.5'), remove_tmp_folder=1): path_i, root_i, ext_i = sct.extract_fname(im_input) path_d, root_d, ext_d = sct.extract_fname(im_dest) path_m, root_m, ext_m = sct.extract_fname(mask) # set metricSize if paramreg.metric == 'MI': metricSize = '32' # corresponds to number of bins else: metricSize = '4' # corresponds to radius (for CC, MeanSquares...) # 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': ',3,32' } # Get image dimensions and retrieve nz print '\nGet image dimensions of destination image...' nx, ny, nz, nt, px, py, pz, pt = sct.get_dimension(im_dest) print '.. matrix size: ' + str(nx) + ' x ' + str(ny) + ' x ' + str(nz) print '.. voxel size: ' + str(px) + 'mm x ' + str(py) + 'mm x ' + str( pz) + 'mm' # Define x and y displacement as list x_displacement = [0 for i in range(nz)] y_displacement = [0 for i in range(nz)] theta_rotation = [0 for i in range(nz)] matrix_def = [0 for i in range(nz)] # create temporary folder print('\nCreate temporary folder...') path_tmp = 'tmp.' + time.strftime("%y%m%d%H%M%S") sct.create_folder(path_tmp) print '\nCopy input data...' sct.run('cp ' + im_input + ' ' + path_tmp + '/' + root_i + ext_i) sct.run('cp ' + im_dest + ' ' + path_tmp + '/' + root_d + ext_d) if mask: sct.run('cp ' + mask + ' ' + path_tmp + '/mask.nii.gz') # go to temporary folder os.chdir(path_tmp) # Split input volume along z print '\nSplit input volume...' sct.run(sct.fsloutput + 'fslsplit ' + im_input + ' ' + root_i + '_z -z') #file_anat_split = ['tmp.anat_orient_z'+str(z).zfill(4) for z in range(0,nz,1)] # Split destination volume along z print '\nSplit destination volume...' sct.run(sct.fsloutput + 'fslsplit ' + im_dest + ' ' + root_d + '_z -z') #file_anat_split = ['tmp.anat_orient_z'+str(z).zfill(4) for z in range(0,nz,1)] # Split mask volume along z if mask: print '\nSplit mask volume...' sct.run(sct.fsloutput + 'fslsplit mask.nii.gz mask_z -z') #file_anat_split = ['tmp.anat_orient_z'+str(z).zfill(4) for z in range(0,nz,1)] im_dest_img = Image(im_dest) im_input_img = Image(im_input) coord_origin_dest = im_dest_img.transfo_pix2phys([[0, 0, 0]]) coord_origin_input = im_input_img.transfo_pix2phys([[0, 0, 0]]) coord_diff_origin_z = coord_origin_dest[0][2] - coord_origin_input[0][2] [[x_o, y_o, z_o]] = im_input_img.transfo_phys2pix([[0, 0, coord_diff_origin_z]]) # loop across slices for i in range(nz): # set masking num = numerotation(i) num_2 = numerotation(int(num) + z_o) if mask: masking = '-x mask_z' + num + '.nii' else: masking = '' cmd = ( 'isct_antsRegistration ' '--dimensionality 2 ' '--transform ' + paramreg.algo + '[' + paramreg.gradStep + ants_registration_params[paramreg.algo.lower()] + '] ' '--metric ' + paramreg.metric + '[' + root_d + '_z' + num + '.nii' + ',' + root_i + '_z' + num_2 + '.nii' + ',1,' + metricSize + '] ' #[fixedImage,movingImage,metricWeight +nb_of_bins (MI) or radius (other) '--convergence ' + paramreg.iter + ' ' '--shrink-factors ' + paramreg.shrink + ' ' '--smoothing-sigmas ' + paramreg.smooth + 'mm ' #'--restrict-deformation 1x1x0 ' # how to restrict? should not restrict here, if transform is precised...? '--output [transform_' + num + '] ' #--> file.txt (contains Tx,Ty) [outputTransformPrefix,<outputWarpedImage>,<outputInverseWarpedImage>] '--interpolation BSpline[3] ' + masking) try: sct.run(cmd) if paramreg.algo == 'Rigid' or paramreg.algo == 'Translation': f = 'transform_' + num + '0GenericAffine.mat' matfile = loadmat(f, struct_as_record=True) array_transfo = matfile['AffineTransform_double_2_2'] if i == 20 or i == 40: print i x_displacement[i] = -array_transfo[4][0] #is it? or is it y? y_displacement[i] = array_transfo[5][0] theta_rotation[i] = asin(array_transfo[2]) if paramreg.algo == 'Affine': f = 'transform_' + num + '0GenericAffine.mat' matfile = loadmat(f, struct_as_record=True) array_transfo = matfile['AffineTransform_double_2_2'] x_displacement[i] = -array_transfo[4][0] #is it? or is it y? y_displacement[i] = array_transfo[5][0] matrix_def[i] = [[array_transfo[0][0], array_transfo[1][0]], [array_transfo[2][0], array_transfo[3][0]] ] # comment savoir lequel est lequel? except: if paramreg.algo == 'Rigid' or paramreg.algo == 'Translation': x_displacement[i] = x_displacement[i - 1] #is it? or is it y? y_displacement[i] = y_displacement[i - 1] theta_rotation[i] = theta_rotation[i - 1] if paramreg.algo == 'Affine': x_displacement[i] = x_displacement[i - 1] y_displacement[i] = y_displacement[i - 1] matrix_def[i] = matrix_def[i - 1] # # get displacement form this slice and complete x and y displacement lists # with open('transform_'+num+'.csv') as f: # reader = csv.reader(f) # count = 0 # for line in reader: # count += 1 # if count == 2: # x_displacement[i] = line[0] # y_displacement[i] = line[1] # f.close() # # get matrix of transfo for a rigid transform (pb slicereg fait une rotation ie le deplacement n'est pas homogene par slice) # # recuperer le deplacement ne donnerait pas une liste mais un warping field: mieux vaut recup la matrice output # # pb du smoothing du deplacement par slice !! on peut smoother les param theta tx ty # if paramreg.algo == 'Rigid' or paramreg.algo == 'Translation': # f = 'transform_' +num+ '0GenericAffine.mat' # matfile = loadmat(f, struct_as_record=True) # array_transfo = matfile['AffineTransform_double_2_2'] # x_displacement[i] = -array_transfo[4][0] #is it? or is it y? # y_displacement[i] = array_transfo[5][0] # theta_rotation[i] = acos(array_transfo[0]) #TO DO: different treatment for other algo #Delete tmp folder os.chdir('../') if remove_tmp_folder: print('\nRemove temporary files...') sct.run('rm -rf ' + path_tmp) if paramreg.algo == 'Rigid': return x_displacement, y_displacement, theta_rotation # check if the displacement are not inverted (x_dis = -x_disp...) theta is in radian if paramreg.algo == 'Translation': return x_displacement, y_displacement if paramreg.algo == 'Affine': return x_displacement, y_displacement, matrix_def
def register_seg(seg_input, seg_dest, verbose=1): """Slice-by-slice registration by translation of two segmentations. For each slice, we estimate the translation vector by calculating the difference of position of the two centers of mass in voxel unit. The segmentations can be of different sizes but the output segmentation must be smaller than the input segmentation. input: seg_input: name of moving segmentation file (type: string) seg_dest: name of fixed segmentation file (type: string) output: x_displacement: list of translation along x axis for each slice (type: list) y_displacement: list of translation along y axis for each slice (type: list) """ seg_input_img = Image(seg_input) seg_dest_img = Image(seg_dest) seg_input_data = seg_input_img.data seg_dest_data = seg_dest_img.data x_center_of_mass_input = [0] * seg_dest_data.shape[2] y_center_of_mass_input = [0] * seg_dest_data.shape[2] sct.printv('\nGet center of mass of the input segmentation for each slice ' '(corresponding to a slice in the output segmentation)...', verbose) # different if size of the two seg are different # TODO: select only the slices corresponding to the output segmentation # grab physical coordinates of destination origin coord_origin_dest = seg_dest_img.transfo_pix2phys([[0, 0, 0]]) # grab the voxel coordinates of the destination origin from the source image [[x_o, y_o, z_o]] = seg_input_img.transfo_phys2pix(coord_origin_dest) # calculate center of mass for each slice of the input image for iz in xrange(seg_dest_data.shape[2]): # starts from z_o, which is the origin of the destination image in the source image x_center_of_mass_input[iz], y_center_of_mass_input[iz] = ndimage.measurements.center_of_mass(array(seg_input_data[:, :, z_o + iz])) # initialize data x_center_of_mass_output = [0] * seg_dest_data.shape[2] y_center_of_mass_output = [0] * seg_dest_data.shape[2] # calculate center of mass for each slice of the destination image sct.printv('\nGet center of mass of the destination segmentation for each slice ...', verbose) for iz in xrange(seg_dest_data.shape[2]): try: x_center_of_mass_output[iz], y_center_of_mass_output[iz] = ndimage.measurements.center_of_mass(array(seg_dest_data[:, :, iz])) except Exception as e: sct.printv('WARNING: Exception error in msct_register_regularized during register_seg:', 1, 'warning') print 'Error on line {}'.format(sys.exc_info()[-1].tb_lineno) print e # calculate displacement in voxel space x_displacement = [0] * seg_input_data.shape[2] y_displacement = [0] * seg_input_data.shape[2] sct.printv('\nGet displacement by voxel...', verbose) for iz in xrange(seg_dest_data.shape[2]): x_displacement[iz] = -(x_center_of_mass_output[iz] - x_center_of_mass_input[iz]) # WARNING: in ITK's coordinate system, this is actually Tx and not -Tx y_displacement[iz] = y_center_of_mass_output[iz] - y_center_of_mass_input[iz] # This is Ty in ITK's and fslview' coordinate systems return x_displacement, y_displacement, None