def register_slicereg2d_rigid(fname_source, fname_dest, window_length=31, paramreg=Paramreg(step='0', type='im', algo='Rigid', metric='MeanSquares', iter='10', shrink='1', smooth='0', gradStep='0.5'), fname_mask='', warp_forward_out='step0Warp.nii.gz', warp_inverse_out='step0InverseWarp.nii.gz', factor=2, remove_temp_files=1, verbose=0, ants_registration_params={'rigid': '', 'affine': '', 'compositeaffine': '', 'similarity': '', 'translation': '','bspline': ',10', 'gaussiandisplacementfield': ',3,0', 'bsplinedisplacementfield': ',5,10', 'syn': ',3,0', 'bsplinesyn': ',1,3'}): """Slice-by-slice regularized registration (rigid) of two images. We first register slice-by-slice the two images using antsRegistration in 2D. Then we remove outliers using Median Absolute Deviation technique (MAD) and smooth the translations and angle of rotation along x and y axis using moving average hanning window. Eventually, we generate two warping fields (forward and inverse) resulting from this regularized registration technique. The images must be of same size (otherwise generate_warping_field will not work for forward or inverse creation). input: fname_source: name of moving image (type: string) fname_dest: name of fixed image (type: string) window_length[optional]: size of window for moving average smoothing (type: int) paramreg[optional]: parameters of antsRegistration (type: Paramreg class from sct_register_multimodal) fname_mask[optional]: name of mask file (type: string) (parameter -x of antsRegistration) warp_forward_out[optional]: name of output forward warp (type: string) warp_inverse_out[optional]: name of output inverse warp (type: string) factor[optional]: sensibility factor for outlier detection (higher the factor, smaller the detection) (type: int or float) remove_temp_files[optional]: 1 to remove, 0 to keep (type: int) verbose[optional]: display parameter (type: int, value: 0,1 or 2) ants_registration_params[optional]: specific algorithm's parameters for antsRegistration (type: dictionary) output: creation of warping field files of name 'warp_forward_out' and 'warp_inverse_out'. """ from msct_register_regularized import register_images, generate_warping_field from numpy import asarray from msct_smooth import smoothing_window, outliers_detection, outliers_completion # Calculate displacement x_disp, y_disp, theta_rot = register_images(fname_source, fname_dest, mask=fname_mask, paramreg=paramreg, remove_tmp_folder=remove_temp_files, ants_registration_params=ants_registration_params) # Change to array x_disp_a = asarray(x_disp) y_disp_a = asarray(y_disp) theta_rot_a = asarray(theta_rot) # Detect outliers mask_x_a = outliers_detection(x_disp_a, type='median', factor=factor, return_filtered_signal='no', verbose=verbose) mask_y_a = outliers_detection(y_disp_a, type='median', factor=factor, return_filtered_signal='no', verbose=verbose) mask_theta_a = outliers_detection(theta_rot_a, type='median', factor=2, return_filtered_signal='no', verbose=verbose) # Replace value of outliers by linear interpolation using closest non-outlier points x_disp_a_no_outliers = outliers_completion(mask_x_a, verbose=0) y_disp_a_no_outliers = outliers_completion(mask_y_a, verbose=0) theta_rot_a_no_outliers = outliers_completion(mask_theta_a, verbose=0) # Smooth results x_disp_smooth = smoothing_window(x_disp_a_no_outliers, window_len=int(window_length), window='hanning', verbose = verbose) y_disp_smooth = smoothing_window(y_disp_a_no_outliers, window_len=int(window_length), window='hanning', verbose = verbose) theta_rot_smooth = smoothing_window(theta_rot_a_no_outliers, window_len=int(window_length), window='hanning', verbose = verbose) # Generate warping field generate_warping_field(fname_dest, x_disp_smooth, y_disp_smooth, theta_rot_smooth, fname=warp_forward_out) # Inverse warping field generate_warping_field(fname_source, -x_disp_smooth, -y_disp_smooth, -theta_rot_smooth, fname=warp_inverse_out)
def register_slicereg2d_pointwise(fname_source, fname_dest, window_length=31, paramreg=Paramreg(step='0', type='seg', algo='slicereg2d_pointwise', metric='MeanSquares', iter='10', shrink='1', smooth='0', gradStep='0.5'), warp_forward_out='step0Warp.nii.gz', warp_inverse_out='step0InverseWarp.nii.gz', factor=2, verbose=0): """Slice-by-slice regularized registration by translation of two segmentations. First we estimate for each slice the translation vector by calculating the difference of position of the two centers of mass of the two segmentations. Then we remove outliers using Median Absolute Deviation technique (MAD) and smooth the translation along x and y axis using moving average hanning window. Eventually, we generate two warping fields (forward and inverse) resulting from this regularized registration technique. The segmentations must be of same size (otherwise generate_warping_field will not work for forward or inverse creation). input: fname_source: name of moving image (type: string) fname_dest: name of fixed image (type: string) window_length: size of window for moving average smoothing (type: int) paramreg[optional]: parameters of antsRegistration (type: Paramreg class from sct_register_multimodal) warp_forward_out: name of output forward warp (type: string) warp_inverse_out: name of output inverse warp (type: string) factor: sensibility factor for outlier detection (higher the factor, smaller the detection) (type: int or float) verbose: display parameter (type: int, value: 0,1 or 2) output: creation of warping field files of name 'warp_forward_out' and 'warp_inverse_out'. """ if paramreg.type != 'seg': print '\nERROR: Algorithm slicereg2d_pointwise only operates for segmentation type.' sys.exit(2) else: from msct_register_regularized import register_seg, generate_warping_field from numpy import asarray from msct_smooth import smoothing_window, outliers_detection, outliers_completion # Calculate displacement x_disp, y_disp = register_seg(fname_source, fname_dest) # Change to array x_disp_a = asarray(x_disp) y_disp_a = asarray(y_disp) # Detect outliers mask_x_a = outliers_detection(x_disp_a, type='median', factor=factor, return_filtered_signal='no', verbose=verbose) mask_y_a = outliers_detection(y_disp_a, type='median', factor=factor, return_filtered_signal='no', verbose=verbose) # Replace value of outliers by linear interpolation using closest non-outlier points x_disp_a_no_outliers = outliers_completion(mask_x_a, verbose=0) y_disp_a_no_outliers = outliers_completion(mask_y_a, verbose=0) # Smooth results x_disp_smooth = smoothing_window(x_disp_a_no_outliers, window_len=int(window_length), window='hanning', verbose=verbose) y_disp_smooth = smoothing_window(y_disp_a_no_outliers, window_len=int(window_length), window='hanning', verbose=verbose) # Generate warping field generate_warping_field(fname_dest, x_disp_smooth, y_disp_smooth, fname=warp_forward_out) #name_warp= 'step'+str(paramreg.step) # Inverse warping field generate_warping_field(fname_source, -x_disp_smooth, -y_disp_smooth, fname=warp_inverse_out)
from numpy import asarray from msct_smooth import smoothing_window # go to output folder print '\nGo to output folder ' + PATH_OUTPUT + '/subjects/' + subject + '/T1' os.chdir(PATH_OUTPUT + '/subjects/' + subject + '/T1') # Register seg to create first warping field and apply it print '\nUsing register_seg with centerlines to create first warping field and applying it...' x_disp, y_disp = register_seg('centerline_T1.nii.gz', 'centerline_T2.nii.gz') x_disp_a = asarray(x_disp) y_disp_a = asarray(y_disp) x_disp_smooth = smoothing_window(x_disp_a, window_len=31, window='hanning', verbose=2) y_disp_smooth = smoothing_window(y_disp_a, window_len=31, window='hanning', verbose=2) generate_warping_field('centerline_T2.nii.gz', x_disp_smooth, y_disp_smooth, fname='warping_field_seg.nii.gz') sct.run( 'sct_apply_transfo -i data_RPI_registered.nii.gz -d data_T2_RPI.nii.gz -w warping_field_seg.nii.gz -o data_RPI_registered_reg1.nii.gz -x spline' ) # Register_image to create second warping field and apply it
for i in range(0, len(SUBJECTS_LIST)): subject = SUBJECTS_LIST[i][0] from numpy import asarray from msct_smooth import smoothing_window # go to output folder print "\nGo to output folder " + PATH_OUTPUT + "/subjects/" + subject + "/T1" os.chdir(PATH_OUTPUT + "/subjects/" + subject + "/T1") # Register seg to create first warping field and apply it print "\nUsing register_seg with centerlines to create first warping field and applying it..." x_disp, y_disp = register_seg("centerline_T1.nii.gz", "centerline_T2.nii.gz") x_disp_a = asarray(x_disp) y_disp_a = asarray(y_disp) x_disp_smooth = smoothing_window(x_disp_a, window_len=31, window="hanning", verbose=2) y_disp_smooth = smoothing_window(y_disp_a, window_len=31, window="hanning", verbose=2) generate_warping_field("centerline_T2.nii.gz", x_disp_smooth, y_disp_smooth, fname="warping_field_seg.nii.gz") sct.run( "sct_apply_transfo -i data_RPI_registered.nii.gz -d data_T2_RPI.nii.gz -w warping_field_seg.nii.gz -o data_RPI_registered_reg1.nii.gz -x spline" ) # Register_image to create second warping field and apply it print "\nUsing register_image with images to create second warping field and applying it..." x_disp_2, y_disp_2 = register_images("data_RPI_registered_reg1.nii.gz", "data_T2_RPI.nii.gz") x_disp_2_a = asarray(x_disp_2) y_disp_2_a = asarray(y_disp_2) x_disp_2_smooth = smoothing_window(x_disp_2_a, window_len=31, window="hanning", verbose=2) y_disp_2_smooth = smoothing_window(y_disp_2_a, window_len=31, window="hanning", verbose=2)
paramreg=Paramreg(step='0', type='im', algo='Rigid', metric='MI', iter='100', shrink='1', smooth='0', gradStep='3'), remove_tmp_folder=1) x_disp_a = asarray(x_disp) y_disp_a = asarray(y_disp) theta_a = asarray(theta) x_disp_smooth = smoothing_window(x_disp_a, window_len=window_size, window='hanning', verbose=2) y_disp_smooth = smoothing_window(y_disp_a, window_len=window_size, window='hanning', verbose=2) theta_smooth = smoothing_window(theta_a, window_len=window_size, window='hanning', verbose=2) theta_smooth_inv = -theta_smooth generate_warping_field(im_d, x_disp_smooth, y_disp_smooth, theta_rot=theta_smooth,
def compute_csa(fname_segmentation, name_method, volume_output, verbose, remove_temp_files, step, smoothing_param, figure_fit, name_output, slices, vert_levels, path_to_template, 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"), 1) sct.run('mkdir '+path_tmp, verbose) # Copying input data to tmp folder and convert to nii sct.printv('\nCopying input data to tmp folder and convert to nii...', verbose) sct.run('isct_c3d '+fname_segmentation+' -o '+path_tmp+'segmentation.nii') # go to tmp folder os.chdir(path_tmp) # Change orientation of the input segmentation into RPI sct.printv('\nChange orientation of the input segmentation into RPI...', verbose) fname_segmentation_orient = set_orientation('segmentation.nii', 'RPI', 'segmentation_orient.nii') # Get size of data sct.printv('\nGet data dimensions...', verbose) nx, ny, nz, nt, px, py, pz, pt = Image(fname_segmentation_orient).dim sct.printv(' ' + str(nx) + ' x ' + str(ny) + ' x ' + str(nz), verbose) # Open segmentation volume sct.printv('\nOpen segmentation volume...', verbose) file_seg = nibabel.load(fname_segmentation_orient) data_seg = file_seg.get_data() hdr_seg = file_seg.get_header() # # 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) # Xp, Yp = (data_seg[:, :, 0] >= 0).nonzero() # X and Y range # extract centerline and smooth it x_centerline_fit, y_centerline_fit, z_centerline, x_centerline_deriv, y_centerline_deriv, z_centerline_deriv = smooth_centerline(fname_segmentation_orient, 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) # csa = [0.0 for i in xrange(0, max_z_index-min_z_index+1)] for iz in xrange(0, len(z_centerline)): # compute the vector normal to the plane normal = normalize(np.array([x_centerline_deriv[iz], y_centerline_deriv[iz], z_centerline_deriv[iz]])) # 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 = sum(sum(data_seg[:, :, iz+min_z_index])) # compute CSA, by scaling with voxel size (in mm) and adjusting for oblique plane csa[iz] = number_voxels * px * py * np.cos(angle) if smoothing_param: from msct_smooth import smoothing_window sct.printv('\nSmooth CSA across slices...', verbose) 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 # 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 if volume_output: sct.printv('\nCreate volume of CSA values...', verbose) # get orientation of the input data orientation = get_orientation('segmentation.nii') data_seg = 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_seg[:, :, 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_seg[i[0], i[1], iz] = csa[iz-min_z_index] # create header hdr_seg.set_data_dtype('float32') # set imagetype to uint8 # save volume img = nibabel.Nifti1Image(data_seg, None, hdr_seg) nibabel.save(img, 'csa_RPI.nii') # Change orientation of the output centerline into input orientation fname_csa_volume = set_orientation('csa_RPI.nii', orientation, 'csa_RPI_orient.nii') # come back to parent folder os.chdir('..') # Generate output files sct.printv('\nGenerate output files...', verbose) from shutil import copyfile 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 if volume_output: sct.generate_output_file(fname_csa_volume, path_data+name_output) # extension already included in name_output # average csa across vertebral levels or slices if asked (flag -z or -l) if slices or vert_levels: if vert_levels and not path_to_template: sct.printv('\nERROR: Path to template is missing. See usage.\n', 1, 'error') sys.exit(2) elif vert_levels and path_to_template: abs_path_to_template = os.path.abspath(path_to_template) # go to tmp folder os.chdir(path_tmp) # create temporary folder sct.printv('\nCreate temporary folder to average csa...', verbose) path_tmp_extract_metric = sct.slash_at_the_end('label_temp', 1) sct.run('mkdir '+path_tmp_extract_metric, verbose) # Copying output CSA volume in the temporary folder sct.printv('\nCopy data to tmp folder...', verbose) sct.run('cp '+fname_segmentation+' '+path_tmp_extract_metric) # create file info_label path_fname_seg, file_fname_seg, ext_fname_seg = sct.extract_fname(fname_segmentation) create_info_label('info_label.txt', path_tmp_extract_metric, file_fname_seg+ext_fname_seg) # average CSA if slices: os.system("sct_extract_metric -i "+path_data+name_output+" -f "+path_tmp_extract_metric+" -m wa -o ../csa_mean.txt -z "+slices) if vert_levels: sct.run('cp -R '+abs_path_to_template+' .') os.system("sct_extract_metric -i "+path_data+name_output+" -f "+path_tmp_extract_metric+" -m wa -o ../csa_mean.txt -v "+vert_levels) os.chdir('..') # Remove temporary files print('\nRemove temporary folder used to average CSA...') sct.run('rm -rf '+path_tmp_extract_metric) # Remove temporary files if remove_temp_files: print('\nRemove temporary files...') sct.run('rm -rf '+path_tmp)
def compute_csa(fname_segmentation, name_method, volume_output, verbose, remove_temp_files, step, smoothing_param, figure_fit, name_output, slices, vert_levels, path_to_template, 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"), 1) sct.run('mkdir ' + path_tmp, verbose) # Copying input data to tmp folder and convert to nii sct.printv('\nCopying input data to tmp folder and convert to nii...', verbose) sct.run('isct_c3d ' + fname_segmentation + ' -o ' + path_tmp + 'segmentation.nii') # go to tmp folder os.chdir(path_tmp) # Change orientation of the input segmentation into RPI sct.printv('\nChange orientation of the input segmentation into RPI...', verbose) fname_segmentation_orient = set_orientation('segmentation.nii', 'RPI', 'segmentation_orient.nii') # Get size of data sct.printv('\nGet data dimensions...', verbose) nx, ny, nz, nt, px, py, pz, pt = Image(fname_segmentation_orient).dim sct.printv(' ' + str(nx) + ' x ' + str(ny) + ' x ' + str(nz), verbose) # Open segmentation volume sct.printv('\nOpen segmentation volume...', verbose) file_seg = nibabel.load(fname_segmentation_orient) data_seg = file_seg.get_data() hdr_seg = file_seg.get_header() # # 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) # Xp, Yp = (data_seg[:, :, 0] >= 0).nonzero() # X and Y range # extract centerline and smooth it x_centerline_fit, y_centerline_fit, z_centerline, x_centerline_deriv, y_centerline_deriv, z_centerline_deriv = smooth_centerline( fname_segmentation_orient, 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) # csa = [0.0 for i in xrange(0, max_z_index-min_z_index+1)] for iz in xrange(0, len(z_centerline)): # compute the vector normal to the plane normal = normalize( np.array([ x_centerline_deriv[iz], y_centerline_deriv[iz], z_centerline_deriv[iz] ])) # 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 = sum(sum(data_seg[:, :, iz + min_z_index])) # compute CSA, by scaling with voxel size (in mm) and adjusting for oblique plane csa[iz] = number_voxels * px * py * np.cos(angle) if smoothing_param: from msct_smooth import smoothing_window sct.printv('\nSmooth CSA across slices...', verbose) 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 # 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 if volume_output: sct.printv('\nCreate volume of CSA values...', verbose) # get orientation of the input data orientation = get_orientation('segmentation.nii') data_seg = 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_seg[:, :, 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_seg[i[0], i[1], iz] = csa[iz - min_z_index] # create header hdr_seg.set_data_dtype('float32') # set imagetype to uint8 # save volume img = nibabel.Nifti1Image(data_seg, None, hdr_seg) nibabel.save(img, 'csa_RPI.nii') # Change orientation of the output centerline into input orientation fname_csa_volume = set_orientation('csa_RPI.nii', orientation, 'csa_RPI_orient.nii') # come back to parent folder os.chdir('..') # Generate output files sct.printv('\nGenerate output files...', verbose) from shutil import copyfile 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 if volume_output: sct.generate_output_file( fname_csa_volume, path_data + name_output) # extension already included in name_output # average csa across vertebral levels or slices if asked (flag -z or -l) if slices or vert_levels: if vert_levels and not path_to_template: sct.printv('\nERROR: Path to template is missing. See usage.\n', 1, 'error') sys.exit(2) elif vert_levels and path_to_template: abs_path_to_template = os.path.abspath(path_to_template) # go to tmp folder os.chdir(path_tmp) # create temporary folder sct.printv('\nCreate temporary folder to average csa...', verbose) path_tmp_extract_metric = sct.slash_at_the_end('label_temp', 1) sct.run('mkdir ' + path_tmp_extract_metric, verbose) # Copying output CSA volume in the temporary folder sct.printv('\nCopy data to tmp folder...', verbose) sct.run('cp ' + fname_segmentation + ' ' + path_tmp_extract_metric) # create file info_label path_fname_seg, file_fname_seg, ext_fname_seg = sct.extract_fname( fname_segmentation) create_info_label('info_label.txt', path_tmp_extract_metric, file_fname_seg + ext_fname_seg) # average CSA if slices: os.system("sct_extract_metric -i " + path_data + name_output + " -f " + path_tmp_extract_metric + " -m wa -o ../csa_mean.txt -z " + slices) if vert_levels: sct.run('cp -R ' + abs_path_to_template + ' .') os.system("sct_extract_metric -i " + path_data + name_output + " -f " + path_tmp_extract_metric + " -m wa -o ../csa_mean.txt -v " + vert_levels) os.chdir('..') # Remove temporary files print('\nRemove temporary folder used to average CSA...') sct.run('rm -rf ' + path_tmp_extract_metric) # Remove temporary files if remove_temp_files: print('\nRemove temporary files...') sct.run('rm -rf ' + path_tmp)
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 register_slicereg2d_bsplinesyn(fname_source, fname_dest, window_length=31, paramreg=Paramreg(step='0', type='im', algo='BSplineSyN', metric='MeanSquares', iter='10', shrink='1', smooth='0', gradStep='0.5'), fname_mask='', warp_forward_out='step0Warp.nii.gz', warp_inverse_out='step0InverseWarp.nii.gz', factor=2, remove_temp_files=1, verbose=0, ants_registration_params={'rigid': '', 'affine': '', 'compositeaffine': '', 'similarity': '', 'translation': '','bspline': ',10', 'gaussiandisplacementfield': ',3,0', 'bsplinedisplacementfield': ',5,10', 'syn': ',3,0', 'bsplinesyn': ',1,3'}): """Slice-by-slice regularized registration (bsplinesyn) of two images. We first register slice-by-slice the two images using antsRegistration in 2D (algo: bsplinesyn) and create 3D warping fields (forward and inverse) by merging the 2D warping fields along z. Then we directly detect outliers and smooth the 3d warping fields applying a moving average hanning window on each pixel of the plan xOy (i.e. we consider that for a position (x,y) in the plan xOy, the variation along z of the vector of displacement (xo, yo, zo) of the warping field should not be too abrupt). Eventually, we generate two warping fields (forward and inverse) resulting from this regularized registration technique. The images must be of same size (otherwise generate_warping_field will not work for forward or inverse creation). input: fname_source: name of moving image (type: string) fname_dest: name of fixed image (type: string) window_length[optional]: size of window for moving average smoothing (type: int) paramreg[optional]: parameters of antsRegistration (type: Paramreg class from sct_register_multimodal) fname_mask[optional]: name of mask file (type: string) (parameter -x of antsRegistration) warp_forward_out[optional]: name of output forward warp (type: string) warp_inverse_out[optional]: name of output inverse warp (type: string) factor[optional]: sensibility factor for outlier detection (higher the factor, smaller the detection) (type: int or float) remove_temp_files[optional]: 1 to remove, 0 to keep (type: int) verbose[optional]: display parameter (type: int, value: 0,1 or 2) ants_registration_params[optional]: specific algorithm's parameters for antsRegistration (type: dictionary) output: creation of warping field files of name 'warp_forward_out' and 'warp_inverse_out'. """ from nibabel import load, Nifti1Image, save from msct_smooth import smoothing_window, outliers_detection, outliers_completion from msct_register_regularized import register_images from numpy import apply_along_axis, zeros import sct_utils as sct from msct_image import Image name_warp_syn = 'Warp_total' # Registrating images register_images(fname_source, fname_dest, mask=fname_mask, paramreg=paramreg, remove_tmp_folder=remove_temp_files, ants_registration_params=ants_registration_params) print'\nRegularizing warping fields along z axis...' print'\n\tSplitting warping fields ...' # sct.run('isct_c3d -mcs ' + name_warp_syn + '.nii.gz -oo ' + name_warp_syn + '_x.nii.gz ' + name_warp_syn + '_y.nii.gz') # sct.run('isct_c3d -mcs ' + name_warp_syn + '_inverse.nii.gz -oo ' + name_warp_syn + '_x_inverse.nii.gz ' + name_warp_syn + '_y_inverse.nii.gz') sct.run('sct_maths -i ' + name_warp_syn + '.nii.gz -w -mcs -o ' + name_warp_syn + '_x.nii.gz,' + name_warp_syn + '_y.nii.gz') sct.run('sct_maths -i ' + name_warp_syn + '_inverse.nii.gz -w -mcs -o ' + name_warp_syn + '_x_inverse.nii.gz,' + name_warp_syn + '_y_inverse.nii.gz') data_warp_x = load(name_warp_syn + '_x.nii.gz').get_data() data_warp_y = load(name_warp_syn + '_y.nii.gz').get_data() hdr_warp = load(name_warp_syn + '_x.nii.gz').get_header() data_warp_x_inverse = load(name_warp_syn + '_x_inverse.nii.gz').get_data() data_warp_y_inverse = load(name_warp_syn + '_y_inverse.nii.gz').get_data() hdr_warp_inverse = load(name_warp_syn + '_x_inverse.nii.gz').get_header() #Outliers deletion print'\n\tDeleting outliers...' mask_x_a = apply_along_axis(lambda m: outliers_detection(m, type='median', factor=factor, return_filtered_signal='no', verbose=0), axis=-1, arr=data_warp_x) mask_y_a = apply_along_axis(lambda m: outliers_detection(m, type='median', factor=factor, return_filtered_signal='no', verbose=0), axis=-1, arr=data_warp_y) mask_x_inverse_a = apply_along_axis(lambda m: outliers_detection(m, type='median', factor=factor, return_filtered_signal='no', verbose=0), axis=-1, arr=data_warp_x_inverse) mask_y_inverse_a = apply_along_axis(lambda m: outliers_detection(m, type='median', factor=factor, return_filtered_signal='no', verbose=0), axis=-1, arr=data_warp_y_inverse) #Outliers replacement by linear interpolation using closest non-outlier points data_warp_x_no_outliers = apply_along_axis(lambda m: outliers_completion(m, verbose=0), axis=-1, arr=mask_x_a) data_warp_y_no_outliers = apply_along_axis(lambda m: outliers_completion(m, verbose=0), axis=-1, arr=mask_y_a) data_warp_x_inverse_no_outliers = apply_along_axis(lambda m: outliers_completion(m, verbose=0), axis=-1, arr=mask_x_inverse_a) data_warp_y_inverse_no_outliers = apply_along_axis(lambda m: outliers_completion(m, verbose=0), axis=-1, arr=mask_y_inverse_a) #Smoothing of results along z print'\n\tSmoothing results...' data_warp_x_smooth = apply_along_axis(lambda m: smoothing_window(m, window_len=int(window_length), window='hanning', verbose=0), axis=-1, arr=data_warp_x_no_outliers) data_warp_x_smooth_inverse = apply_along_axis(lambda m: smoothing_window(m, window_len=int(window_length), window='hanning', verbose=0), axis=-1, arr=data_warp_x_inverse_no_outliers) data_warp_y_smooth = apply_along_axis(lambda m: smoothing_window(m, window_len=int(window_length), window='hanning', verbose=0), axis=-1, arr=data_warp_y_no_outliers) data_warp_y_smooth_inverse = apply_along_axis(lambda m: smoothing_window(m, window_len=int(window_length), window='hanning', verbose=0), axis=-1, arr=data_warp_y_inverse_no_outliers) print'\nSaving regularized warping fields...' #Get image dimensions of destination image nx, ny, nz, nt, px, py, pz, pt = Image(fname_dest).dim data_warp_smooth = zeros(((((nx, ny, nz, 1, 3))))) data_warp_smooth[:,:,:,0,0] = data_warp_x_smooth data_warp_smooth[:,:,:,0,1] = data_warp_y_smooth data_warp_smooth_inverse = zeros(((((nx, ny, nz, 1, 3))))) data_warp_smooth_inverse[:,:,:,0,0] = data_warp_x_smooth_inverse data_warp_smooth_inverse[:,:,:,0,1] = data_warp_y_smooth_inverse # Force header's parameter to intent so that the file may be recognised as a warping field by ants hdr_warp.set_intent('vector', (), '') hdr_warp_inverse.set_intent('vector', (), '') img = Nifti1Image(data_warp_smooth, None, header=hdr_warp) img_inverse = Nifti1Image(data_warp_smooth_inverse, None, header=hdr_warp_inverse) save(img, filename=warp_forward_out) print'\tFile ' + warp_forward_out + ' saved.' save(img_inverse, filename=warp_inverse_out) print'\tFile ' + warp_inverse_out + ' saved.'
def register_slicereg2d(fname_source, fname_dest, fname_mask='', window_length='0', warp_forward_out='step0Warp.nii.gz', warp_inverse_out='step0InverseWarp.nii.gz', paramreg=None, ants_registration_params=None, detect_outlier='0', remove_temp_files=1, verbose=0): from msct_register_regularized import register_seg, register_images, generate_warping_field from numpy import asarray, apply_along_axis, zeros from msct_smooth import smoothing_window, outliers_detection, outliers_completion # Calculate displacement current_algo = paramreg.algo if paramreg.type == 'seg': # calculate translation of center of mass between source and destination in voxel space res_reg = register_seg(fname_source, fname_dest, verbose) elif paramreg.type == 'im': if paramreg.algo == 'slicereg2d_pointwise': sct.printv('\nERROR: Algorithm slicereg2d_pointwise only operates for segmentation type.', verbose, 'error') sys.exit(2) algo_dic = {'slicereg2d_pointwise': 'Translation', 'slicereg2d_translation': 'Translation', 'slicereg2d_rigid': 'Rigid', 'slicereg2d_affine': 'Affine', 'slicereg2d_syn': 'SyN', 'slicereg2d_bsplinesyn': 'BSplineSyN'} paramreg.algo = algo_dic[current_algo] res_reg = register_images(fname_source, fname_dest, mask=fname_mask, paramreg=paramreg, remove_tmp_folder=remove_temp_files, ants_registration_params=ants_registration_params) else: sct.printv('\nERROR: wrong registration type inputed. pleas choose \'im\', or \'seg\'.', verbose, 'error') sys.exit(2) # if algo is slicereg2d _pointwise, -translation or _rigid: x_disp and y_disp are displacement fields # if algo is slicereg2d _affine, _syn or _bsplinesyn: x_disp and y_disp are warping fields names if current_algo in ['slicereg2d_pointwise', 'slicereg2d_translation', 'slicereg2d_rigid']: # Change to array x_disp, y_disp, theta_rot = res_reg x_disp_a = asarray(x_disp) y_disp_a = asarray(y_disp) # Detect outliers if not detect_outlier == '0': mask_x_a = outliers_detection(x_disp_a, type='median', factor=int(detect_outlier), return_filtered_signal='no', verbose=verbose) mask_y_a = outliers_detection(y_disp_a, type='median', factor=int(detect_outlier), return_filtered_signal='no', verbose=verbose) # Replace value of outliers by linear interpolation using closest non-outlier points x_disp_a_no_outliers = outliers_completion(mask_x_a, verbose=0) y_disp_a_no_outliers = outliers_completion(mask_y_a, verbose=0) else: x_disp_a_no_outliers = x_disp_a y_disp_a_no_outliers = y_disp_a # Smooth results if not window_length == '0': x_disp_smooth = smoothing_window(x_disp_a_no_outliers, window_len=int(window_length), window='hanning', verbose=verbose) y_disp_smooth = smoothing_window(y_disp_a_no_outliers, window_len=int(window_length), window='hanning', verbose=verbose) else: x_disp_smooth = x_disp_a_no_outliers y_disp_smooth = y_disp_a_no_outliers if theta_rot is not None: # same steps for theta_rot: theta_rot_a = asarray(theta_rot) mask_theta_a = outliers_detection(theta_rot_a, type='median', factor=int(detect_outlier), return_filtered_signal='no', verbose=verbose) theta_rot_a_no_outliers = outliers_completion(mask_theta_a, verbose=0) theta_rot_smooth = smoothing_window(theta_rot_a_no_outliers, window_len=int(window_length), window='hanning', verbose = verbose) else: theta_rot_smooth = None # Generate warping field generate_warping_field(fname_dest, x_disp_smooth, y_disp_smooth, theta_rot_smooth, fname=warp_forward_out) #name_warp= 'step'+str(paramreg.step) # Inverse warping field generate_warping_field(fname_source, -x_disp_smooth, -y_disp_smooth, -theta_rot_smooth if theta_rot_smooth is not None else None, fname=warp_inverse_out) elif current_algo in ['slicereg2d_affine', 'slicereg2d_syn', 'slicereg2d_bsplinesyn']: from msct_image import Image warp_x, inv_warp_x, warp_y, inv_warp_y = res_reg im_warp_x = Image(warp_x) im_inv_warp_x = Image(inv_warp_x) im_warp_y = Image(warp_y) im_inv_warp_y = Image(inv_warp_y) data_warp_x = im_warp_x.data data_warp_x_inverse = im_inv_warp_x.data data_warp_y = im_warp_y.data data_warp_y_inverse = im_inv_warp_y.data hdr_warp = im_warp_x.hdr hdr_warp_inverse = im_inv_warp_x.hdr #Outliers deletion print'\n\tDeleting outliers...' mask_x_a = apply_along_axis(lambda m: outliers_detection(m, type='median', factor=int(detect_outlier), return_filtered_signal='no', verbose=0), axis=-1, arr=data_warp_x) mask_y_a = apply_along_axis(lambda m: outliers_detection(m, type='median', factor=int(detect_outlier), return_filtered_signal='no', verbose=0), axis=-1, arr=data_warp_y) mask_x_inverse_a = apply_along_axis(lambda m: outliers_detection(m, type='median', factor=int(detect_outlier), return_filtered_signal='no', verbose=0), axis=-1, arr=data_warp_x_inverse) mask_y_inverse_a = apply_along_axis(lambda m: outliers_detection(m, type='median', factor=int(detect_outlier), return_filtered_signal='no', verbose=0), axis=-1, arr=data_warp_y_inverse) #Outliers replacement by linear interpolation using closest non-outlier points data_warp_x_no_outliers = apply_along_axis(lambda m: outliers_completion(m, verbose=0), axis=-1, arr=mask_x_a) data_warp_y_no_outliers = apply_along_axis(lambda m: outliers_completion(m, verbose=0), axis=-1, arr=mask_y_a) data_warp_x_inverse_no_outliers = apply_along_axis(lambda m: outliers_completion(m, verbose=0), axis=-1, arr=mask_x_inverse_a) data_warp_y_inverse_no_outliers = apply_along_axis(lambda m: outliers_completion(m, verbose=0), axis=-1, arr=mask_y_inverse_a) #Smoothing of results along z print'\n\tSmoothing results...' data_warp_x_smooth = apply_along_axis(lambda m: smoothing_window(m, window_len=int(window_length), window='hanning', verbose=0), axis=-1, arr=data_warp_x_no_outliers) data_warp_x_smooth_inverse = apply_along_axis(lambda m: smoothing_window(m, window_len=int(window_length), window='hanning', verbose=0), axis=-1, arr=data_warp_x_inverse_no_outliers) data_warp_y_smooth = apply_along_axis(lambda m: smoothing_window(m, window_len=int(window_length), window='hanning', verbose=0), axis=-1, arr=data_warp_y_no_outliers) data_warp_y_smooth_inverse = apply_along_axis(lambda m: smoothing_window(m, window_len=int(window_length), window='hanning', verbose=0), axis=-1, arr=data_warp_y_inverse_no_outliers) print'\nSaving regularized warping fields...' # TODO: MODIFY NEXT PART #Get image dimensions of destination image from msct_image import Image from nibabel import load, Nifti1Image, save nx, ny, nz, nt, px, py, pz, pt = Image(fname_dest).dim data_warp_smooth = zeros(((((nx, ny, nz, 1, 3))))) data_warp_smooth[:,:,:,0,0] = data_warp_x_smooth data_warp_smooth[:,:,:,0,1] = data_warp_y_smooth data_warp_smooth_inverse = zeros(((((nx, ny, nz, 1, 3))))) data_warp_smooth_inverse[:,:,:,0,0] = data_warp_x_smooth_inverse data_warp_smooth_inverse[:,:,:,0,1] = data_warp_y_smooth_inverse # Force header's parameter to intent so that the file may be recognised as a warping field by ants hdr_warp.set_intent('vector', (), '') hdr_warp_inverse.set_intent('vector', (), '') img = Nifti1Image(data_warp_smooth, None, header=hdr_warp) img_inverse = Nifti1Image(data_warp_smooth_inverse, None, header=hdr_warp_inverse) save(img, filename=warp_forward_out) print'\tFile ' + warp_forward_out + ' saved.' save(img_inverse, filename=warp_inverse_out) print'\tFile ' + warp_inverse_out + ' saved.' return warp_forward_out, warp_inverse_out
def smooth_centerline(fname_centerline, algo_fitting="hanning", type_window="hanning", window_length=80, verbose=0): """ :param fname_centerline: centerline in RPI orientation :return: a bunch of useful stuff """ # window_length = param.window_length # type_window = param.type_window # algo_fitting = param.algo_fitting sct.printv("\nSmooth centerline/segmentation...", verbose) # get dimensions (again!) nx, ny, nz, nt, px, py, pz, pt = sct.get_dimension(fname_centerline) # open centerline file = load(fname_centerline) data = file.get_data() # loop across z and associate x,y coordinate with the point having maximum intensity # N.B. len(z_centerline) = nz_nonz can be smaller than nz in case the centerline is smaller than the input volume z_centerline = [iz for iz in range(0, nz, 1) if data[:, :, iz].any()] nz_nonz = len(z_centerline) x_centerline = [0 for iz in range(0, nz_nonz, 1)] y_centerline = [0 for iz in range(0, nz_nonz, 1)] x_centerline_deriv = [0 for iz in range(0, nz_nonz, 1)] y_centerline_deriv = [0 for iz in range(0, nz_nonz, 1)] z_centerline_deriv = [0 for iz in range(0, nz_nonz, 1)] # get center of mass of the centerline/segmentation sct.printv(".. Get center of mass of the centerline/segmentation...", verbose) for iz in range(0, nz_nonz, 1): x_centerline[iz], y_centerline[iz] = ndimage.measurements.center_of_mass(array(data[:, :, z_centerline[iz]])) # import matplotlib.pyplot as plt # fig = plt.figure() # ax = fig.add_subplot(111) # data_tmp = data # data_tmp[x_centerline[iz], y_centerline[iz], z_centerline[iz]] = 10 # implot = ax.imshow(data_tmp[:, :, z_centerline[iz]].T) # implot.set_cmap('gray') # plt.show() sct.printv(".. Smoothing algo = " + algo_fitting, verbose) if algo_fitting == "hanning": # 2D smoothing sct.printv(".. Windows length = " + str(window_length), verbose) # change to array x_centerline = asarray(x_centerline) y_centerline = asarray(y_centerline) # Smooth the curve x_centerline_smooth = smoothing_window( x_centerline, window_len=window_length / pz, window=type_window, verbose=verbose ) y_centerline_smooth = smoothing_window( y_centerline, window_len=window_length / pz, window=type_window, verbose=verbose ) # convert to list final result x_centerline_smooth = x_centerline_smooth.tolist() y_centerline_smooth = y_centerline_smooth.tolist() # clear variable del data x_centerline_fit = x_centerline_smooth y_centerline_fit = y_centerline_smooth z_centerline_fit = z_centerline # get derivative x_centerline_deriv, y_centerline_deriv, z_centerline_deriv = evaluate_derivative_3D( x_centerline_fit, y_centerline_fit, z_centerline, px, py, pz ) x_centerline_fit = asarray(x_centerline_fit) y_centerline_fit = asarray(y_centerline_fit) z_centerline_fit = asarray(z_centerline_fit) elif algo_fitting == "nurbs": from msct_smooth import b_spline_nurbs x_centerline_fit, y_centerline_fit, z_centerline_fit, x_centerline_deriv, y_centerline_deriv, z_centerline_deriv = b_spline_nurbs( x_centerline, y_centerline, z_centerline, nbControl=None, verbose=verbose ) else: sct.printv("ERROR: wrong algorithm for fitting", 1, "error") return ( x_centerline_fit, y_centerline_fit, z_centerline_fit, x_centerline_deriv, y_centerline_deriv, z_centerline_deriv, )
# generate_warping_field(im_d_3, x_, y_, theta, center_rotation=None, fname='warping_field_15transx.nii.gz') # sct.run('sct_apply_transfo -i '+im_d_3+' -d '+im_d_3+' -w warping_field_15transx.nii.gz -o ' + im_d_5 + ' -x nn') # im and algo rigid im_i = im_T1 im_d = im_T2 window_size = 31 x_disp, y_disp, theta = register_images(im_i, im_d, paramreg=Paramreg(step='0', type='im', algo='Rigid', metric='MI', iter='100', shrink='1', smooth='0', gradStep='3'), remove_tmp_folder=1) x_disp_a = asarray(x_disp) y_disp_a = asarray(y_disp) theta_a = asarray(theta) x_disp_smooth = smoothing_window(x_disp_a, window_len=window_size, window='hanning', verbose = 2) y_disp_smooth = smoothing_window(y_disp_a, window_len=window_size, window='hanning', verbose = 2) theta_smooth = smoothing_window(theta_a, window_len=window_size, window='hanning', verbose = 2) theta_smooth_inv = -theta_smooth generate_warping_field(im_d, x_disp_smooth, y_disp_smooth, theta_rot=theta_smooth, fname='warping_field_seg_rigid.nii.gz') generate_warping_field(im_i, -x_disp_smooth, -y_disp_smooth, theta_rot=theta_smooth_inv, fname='warping_field_seg_rigid_inv.nii.gz') sct.run('sct_apply_transfo -i '+ im_i +' -d ' +im_d+ ' -w warping_field_seg_rigid.nii.gz -o output_im_rigid.nii.gz -x nn') sct.run('sct_apply_transfo -i '+ im_d +' -d ' +im_i+ ' -w warping_field_seg_rigid_inv.nii.gz -o output_im_rigid_inv.nii.gz -x nn') # # im and algo affine # im_i = im_T1 # im_d = im_T2
# tck_x = splrep(z_index, x_displacement, s=smoothing_param_x) # x_disp_smooth = splev(z_index, tck_x) # # For y # y_for_fitting = [-i for i in y_displacement] # m_y =mean(y_for_fitting) # sigma_y = std(y_for_fitting) # smoothing_param_y = m_y * sigma_y**2 #Equivalent to : m*sigma**2 # tck_y = splrep(z_index, y_for_fitting, s=smoothing_param_y) # y_disp_smooth = splev(z_index, tck_y) # y_disp_smooth *= -1 #with hanning and mirror from msct_smooth import smoothing_window x_displacement_array = asarray(x_displacement) y_displacement_array = asarray(y_displacement) x_disp_smooth = smoothing_window(x_displacement_array, window_len=31) y_disp_smooth = smoothing_window(y_displacement_array, window_len=31) # #with hanning and no mirror # window = 'hanning' # window_len_int = 30 # w = eval(window+'(window_len_int)') # x_disp_smooth = convolve(x_displacement, w/w.sum(), mode='same') # y_disp_smooth = convolve(y_displacement, w/w.sum(), mode='same') plt.figure() plt.subplot(2, 1, 1) plt.plot(z_index, x_displacement, "ro") plt.plot(z_index, x_disp_smooth) plt.subplot(2, 1, 2) plt.plot(z_index, y_displacement, "ro")
# tck_x = splrep(z_index, x_displacement, s=smoothing_param_x) # x_disp_smooth = splev(z_index, tck_x) # # For y # y_for_fitting = [-i for i in y_displacement] # m_y =mean(y_for_fitting) # sigma_y = std(y_for_fitting) # smoothing_param_y = m_y * sigma_y**2 #Equivalent to : m*sigma**2 # tck_y = splrep(z_index, y_for_fitting, s=smoothing_param_y) # y_disp_smooth = splev(z_index, tck_y) # y_disp_smooth *= -1 #with hanning and mirror from msct_smooth import smoothing_window x_displacement_array = asarray(x_displacement) y_displacement_array = asarray(y_displacement) x_disp_smooth = smoothing_window(x_displacement_array, window_len=31) y_disp_smooth = smoothing_window(y_displacement_array, window_len=31) # #with hanning and no mirror # window = 'hanning' # window_len_int = 30 # w = eval(window+'(window_len_int)') # x_disp_smooth = convolve(x_displacement, w/w.sum(), mode='same') # y_disp_smooth = convolve(y_displacement, w/w.sum(), mode='same') plt.figure() plt.subplot(2,1,1) plt.plot(z_index,x_displacement, "ro") plt.plot(z_index,x_disp_smooth) plt.subplot(2,1,2) plt.plot(z_index,y_displacement, "ro")
def register_slicereg2d_bsplinesyn( src, dest, window_length=31, paramreg=Paramreg( step="0", type="im", algo="BSplineSyN", metric="MeanSquares", iter="10", shrink="1", smooth="0", gradStep="0.5" ), fname_mask="", warp_forward_out="step0Warp.nii.gz", warp_inverse_out="step0InverseWarp.nii.gz", factor=2, remove_temp_files=1, verbose=0, ants_registration_params={ "rigid": "", "affine": "", "compositeaffine": "", "similarity": "", "translation": "", "bspline": ",10", "gaussiandisplacementfield": ",3,0", "bsplinedisplacementfield": ",5,10", "syn": ",3,0", "bsplinesyn": ",1,3", }, ): """Slice-by-slice regularized registration (bsplinesyn) of two images. We first register slice-by-slice the two images using antsRegistration in 2D (algo: bsplinesyn) and create 3D warping fields (forward and inverse) by merging the 2D warping fields along z. Then we directly detect outliers and smooth the 3d warping fields applying a moving average hanning window on each pixel of the plan xOy (i.e. we consider that for a position (x,y) in the plan xOy, the variation along z of the vector of displacement (xo, yo, zo) of the warping field should not be too abrupt). Eventually, we generate two warping fields (forward and inverse) resulting from this regularized registration technique. The images must be of same size (otherwise generate_warping_field will not work for forward or inverse creation). input: src: name of moving image (type: string) dest: name of fixed image (type: string) window_length[optional]: size of window for moving average smoothing (type: int) paramreg[optional]: parameters of antsRegistration (type: Paramreg class from sct_register_multimodal) fname_mask[optional]: name of mask file (type: string) (parameter -x of antsRegistration) warp_forward_out[optional]: name of output forward warp (type: string) warp_inverse_out[optional]: name of output inverse warp (type: string) factor[optional]: sensibility factor for outlier detection (higher the factor, smaller the detection) (type: int or float) remove_temp_files[optional]: 1 to remove, 0 to keep (type: int) verbose[optional]: display parameter (type: int, value: 0,1 or 2) ants_registration_params[optional]: specific algorithm's parameters for antsRegistration (type: dictionary) output: creation of warping field files of name 'warp_forward_out' and 'warp_inverse_out'. """ from nibabel import load, Nifti1Image, save from msct_smooth import smoothing_window, outliers_detection, outliers_completion from msct_register_regularized import register_images from numpy import apply_along_axis, zeros import sct_utils as sct name_warp_syn = "Warp_total" # Registrating images register_images( src, dest, mask=fname_mask, paramreg=paramreg, remove_tmp_folder=remove_temp_files, ants_registration_params=ants_registration_params, ) print "\nRegularizing warping fields along z axis..." print "\n\tSplitting warping fields ..." sct.run( "isct_c3d -mcs " + name_warp_syn + ".nii.gz -oo " + name_warp_syn + "_x.nii.gz " + name_warp_syn + "_y.nii.gz" ) sct.run( "isct_c3d -mcs " + name_warp_syn + "_inverse.nii.gz -oo " + name_warp_syn + "_x_inverse.nii.gz " + name_warp_syn + "_y_inverse.nii.gz" ) data_warp_x = load(name_warp_syn + "_x.nii.gz").get_data() data_warp_y = load(name_warp_syn + "_y.nii.gz").get_data() hdr_warp = load(name_warp_syn + "_x.nii.gz").get_header() data_warp_x_inverse = load(name_warp_syn + "_x_inverse.nii.gz").get_data() data_warp_y_inverse = load(name_warp_syn + "_y_inverse.nii.gz").get_data() hdr_warp_inverse = load(name_warp_syn + "_x_inverse.nii.gz").get_header() # Outliers deletion print "\n\tDeleting outliers..." mask_x_a = apply_along_axis( lambda m: outliers_detection(m, type="median", factor=factor, return_filtered_signal="no", verbose=0), axis=-1, arr=data_warp_x, ) mask_y_a = apply_along_axis( lambda m: outliers_detection(m, type="median", factor=factor, return_filtered_signal="no", verbose=0), axis=-1, arr=data_warp_y, ) mask_x_inverse_a = apply_along_axis( lambda m: outliers_detection(m, type="median", factor=factor, return_filtered_signal="no", verbose=0), axis=-1, arr=data_warp_x_inverse, ) mask_y_inverse_a = apply_along_axis( lambda m: outliers_detection(m, type="median", factor=factor, return_filtered_signal="no", verbose=0), axis=-1, arr=data_warp_y_inverse, ) # Outliers replacement by linear interpolation using closest non-outlier points data_warp_x_no_outliers = apply_along_axis(lambda m: outliers_completion(m, verbose=0), axis=-1, arr=mask_x_a) data_warp_y_no_outliers = apply_along_axis(lambda m: outliers_completion(m, verbose=0), axis=-1, arr=mask_y_a) data_warp_x_inverse_no_outliers = apply_along_axis( lambda m: outliers_completion(m, verbose=0), axis=-1, arr=mask_x_inverse_a ) data_warp_y_inverse_no_outliers = apply_along_axis( lambda m: outliers_completion(m, verbose=0), axis=-1, arr=mask_y_inverse_a ) # Smoothing of results along z print "\n\tSmoothing results..." data_warp_x_smooth = apply_along_axis( lambda m: smoothing_window(m, window_len=int(window_length), window="hanning", verbose=0), axis=-1, arr=data_warp_x_no_outliers, ) data_warp_x_smooth_inverse = apply_along_axis( lambda m: smoothing_window(m, window_len=int(window_length), window="hanning", verbose=0), axis=-1, arr=data_warp_x_inverse_no_outliers, ) data_warp_y_smooth = apply_along_axis( lambda m: smoothing_window(m, window_len=int(window_length), window="hanning", verbose=0), axis=-1, arr=data_warp_y_no_outliers, ) data_warp_y_smooth_inverse = apply_along_axis( lambda m: smoothing_window(m, window_len=int(window_length), window="hanning", verbose=0), axis=-1, arr=data_warp_y_inverse_no_outliers, ) print "\nSaving regularized warping fields..." # Get image dimensions of destination image nx, ny, nz, nt, px, py, pz, pt = sct.get_dimension(dest) data_warp_smooth = zeros(((((nx, ny, nz, 1, 3))))) data_warp_smooth[:, :, :, 0, 0] = data_warp_x_smooth data_warp_smooth[:, :, :, 0, 1] = data_warp_y_smooth data_warp_smooth_inverse = zeros(((((nx, ny, nz, 1, 3))))) data_warp_smooth_inverse[:, :, :, 0, 0] = data_warp_x_smooth_inverse data_warp_smooth_inverse[:, :, :, 0, 1] = data_warp_y_smooth_inverse # Force header's parameter to intent so that the file may be recognised as a warping field by ants hdr_warp.set_intent("vector", (), "") hdr_warp_inverse.set_intent("vector", (), "") img = Nifti1Image(data_warp_smooth, None, header=hdr_warp) img_inverse = Nifti1Image(data_warp_smooth_inverse, None, header=hdr_warp_inverse) save(img, filename=warp_forward_out) print "\tFile " + warp_forward_out + " saved." save(img_inverse, filename=warp_inverse_out) print "\tFile " + warp_inverse_out + " saved."
def register_slicereg2d_translation( src, dest, window_length=31, paramreg=Paramreg( step="0", type="im", algo="Translation", metric="MeanSquares", iter="10", shrink="1", smooth="0", gradStep="0.5" ), fname_mask="", warp_forward_out="step0Warp.nii.gz", warp_inverse_out="step0InverseWarp.nii.gz", factor=2, remove_temp_files=1, verbose=0, ants_registration_params={ "rigid": "", "affine": "", "compositeaffine": "", "similarity": "", "translation": "", "bspline": ",10", "gaussiandisplacementfield": ",3,0", "bsplinedisplacementfield": ",5,10", "syn": ",3,0", "bsplinesyn": ",1,3", }, ): """Slice-by-slice regularized registration by translation of two images. We first register slice-by-slice the two images using antsRegistration in 2D. Then we remove outliers using Median Absolute Deviation technique (MAD) and smooth the translations along x and y axis using moving average hanning window. Eventually, we generate two warping fields (forward and inverse) resulting from this regularized registration technique. The images must be of same size (otherwise generate_warping_field will not work for forward or inverse creation). input: src: name of moving image (type: string) dest: name of fixed image (type: string) window_length[optional]: size of window for moving average smoothing (type: int) paramreg[optional]: parameters of antsRegistration (type: Paramreg class from sct_register_multimodal) fname_mask[optional]: name of mask file (type: string) (parameter -x of antsRegistration) warp_forward_out[optional]: name of output forward warp (type: string) warp_inverse_out[optional]: name of output inverse warp (type: string) factor[optional]: sensibility factor for outlier detection (higher the factor, smaller the detection) (type: int or float) remove_temp_files[optional]: 1 to remove, 0 to keep (type: int) verbose[optional]: display parameter (type: int, value: 0,1 or 2) ants_registration_params[optional]: specific algorithm's parameters for antsRegistration (type: dictionary) output: creation of warping field files of name 'warp_forward_out' and 'warp_inverse_out'. """ from msct_register_regularized import register_images, generate_warping_field from numpy import asarray from msct_smooth import smoothing_window, outliers_detection, outliers_completion # Calculate displacement x_disp, y_disp = register_images( src, dest, mask=fname_mask, paramreg=paramreg, remove_tmp_folder=remove_temp_files, ants_registration_params=ants_registration_params, ) # Change to array x_disp_a = asarray(x_disp) y_disp_a = asarray(y_disp) # Detect outliers mask_x_a = outliers_detection(x_disp_a, type="median", factor=factor, return_filtered_signal="no", verbose=verbose) mask_y_a = outliers_detection(y_disp_a, type="median", factor=factor, return_filtered_signal="no", verbose=verbose) # Replace value of outliers by linear interpolation using closest non-outlier points x_disp_a_no_outliers = outliers_completion(mask_x_a, verbose=0) y_disp_a_no_outliers = outliers_completion(mask_y_a, verbose=0) # Smooth results x_disp_smooth = smoothing_window( x_disp_a_no_outliers, window_len=int(window_length), window="hanning", verbose=verbose ) y_disp_smooth = smoothing_window( y_disp_a_no_outliers, window_len=int(window_length), window="hanning", verbose=verbose ) # Generate warping field generate_warping_field(dest, x_disp_smooth, y_disp_smooth, fname=warp_forward_out) # Inverse warping field generate_warping_field(src, -x_disp_smooth, -y_disp_smooth, fname=warp_inverse_out)