def extract_parameters(filename, param_names, _verb=False): ''' read parameters values in filename.txt and save it in a dictionary''' # read values in txt param_values = search_value_in_txt(filename, param_names) print('\n *** Parameters : \n') # create dictionary of parameters parameters = {} for i, p_name in enumerate(param_names): parameters[p_name] = float(param_values[i]) if _verb: print(' - {} : {}'.format(p_name, param_values[i])) if _verb: print('\n \n') return parameters
def extract_parameters(filename): ''' read parameters values in filename.txt and save it in a dictionary''' param_names = ['res_xy', 'res_z', 'save_binary_sections'] # read values in txt param_values = search_value_in_txt(filename, param_names) print(' *** Parameters : \n') # create dictionary of parameters parameters = {} for i, p_name in enumerate(param_names): parameters[p_name] = float(param_values[i]) print(' - {} : {}'.format(p_name, param_values[i])) print('\n \n') return parameters
def extract_parameters(filename): ''' read parameters values in filename.txt and save it in a dictionary''' param_names = [ 'res_xy', 'res_z', 't_rate_info', 'clahe_ksize', 'clip_clahe', 'K_cluster', 'K_true', 't_ratio_holes', 'save_clahe', 'save_binary_mask', 'save_segmented', 'save_contours', 'save_countourned' ] # read values in txt param_values = search_value_in_txt(filename, param_names) print(' *** Parameters : \n') # create dictionary of parameters parameters = {} for i, p_name in enumerate(param_names): parameters[p_name] = float(param_values[i]) print(' - {} : {}'.format(p_name, param_values[i])) print('\n \n') return parameters
def extract_parameters(filename): ''' read parameters values in filename.txt and save it in a dictionary''' param_names = [ 'num_of_slices_P', 'sarc_length', 'res_xy', 'res_z', 'threshold_on_cell_ratio', 'threshold_on_peak_ratio', 'threshold_on_hyperbole', 'psd0_hyperbole_psd_ratio', 'k_hyperbole_psd_ratio', 'y0_hyperbole_psd_ratio', 'sigma', 'local_disorder_xy_side', 'local_disorder_z_side', 'neighbours_lim', 'isolated' ] # read values in txt param_values = search_value_in_txt(filename, param_names) print('\n *** Parameters : \n') # create dictionary of parameters parameters = {} for i, p_name in enumerate(param_names): parameters[p_name] = float(param_values[i]) print(' - {} : {}'.format(p_name, param_values[i])) print('\n \n') return parameters
def main(parser): ### Extract input information FROM TERMINAL ======================= args = parser.parse_args() source_path = manage_path_argument(args.source_path) param_filename = args.parameters_filename[0] # preferences _verbose = args.verbose _deep_verbose = args.deep_verbose _save_csv = args.csv _save_hist = args.histogram _save_maps = args.maps if _verbose: print(Bcolors.FAIL + ' *** VERBOSE MODE *** ' + Bcolors.ENDC) if _deep_verbose: print(Bcolors.FAIL + ' *** DEBUGGING MODE *** ' + Bcolors.ENDC) ### =============================================================== # extract filenames and folder names stack_name = os.path.basename(source_path) process_folder = os.path.basename(os.path.dirname(source_path)) base_path = os.path.dirname(os.path.dirname(source_path)) param_filepath = os.path.join(base_path, process_folder, param_filename) stack_prefix = stack_name.split('.')[0] # create introductory information mess_strings = list() mess_strings.append(Bcolors.OKBLUE + '\n\n*** Structure Tensor Orientation Analysis ***\n' + Bcolors.ENDC) mess_strings.append(' > Source path: {}'.format(source_path)) mess_strings.append(' > Stack name: {}'.format(stack_name)) mess_strings.append(' > Process folder: {}'.format(process_folder)) mess_strings.append(' > Base path: {}'.format(base_path)) mess_strings.append(' > Parameter filename: {}'.format(param_filename)) mess_strings.append(' > Parameter filepath: {}'.format(param_filepath)) mess_strings.append('') mess_strings.append(' > PREFERENCES:') mess_strings.append(' - _verbose {}'.format(_verbose)) mess_strings.append(' - _deep_verbose {}'.format(_deep_verbose)) mess_strings.append(' - _save_csv {}'.format(_save_csv)) mess_strings.append(' - _save_hist {}'.format(_save_hist)) mess_strings.append(' - _save_maps {}'.format(_save_maps)) # extract parameters param_names = [ 'roi_xy_pix', 'px_size_xy', 'px_size_z', 'mode_ratio', 'threshold_on_cell_ratio', 'local_disarray_xy_side', 'local_disarray_z_side', 'neighbours_lim', 'fwhm_xy', 'fwhm_z' ] param_values = search_value_in_txt(param_filepath, param_names) # create parameter dictionary parameters = {} mess_strings.append('\n\n*** Parameters used:') mess_strings.append( ' > Parameters extracted from {}\n'.format(param_filename)) for i, p_name in enumerate(param_names): parameters[p_name] = float(param_values[i]) mess_strings.append('> {} - {}'.format(p_name, parameters[p_name])) # acquisition system characteristics: ratio of the pixel size along the z and x-y axes ps_ratio = parameters['px_size_z'] / parameters['px_size_xy'] # size of the analyzed block along the z axis shape_P = np.array( (int(parameters['roi_xy_pix']), int(parameters['roi_xy_pix']), int(parameters['roi_xy_pix'] / ps_ratio))).astype(np.int32) mess_strings.append('\n *** Analysis configuration:') mess_strings.append( ' > Pixel size ratio (z / xy) = {0:0.2f}'.format(ps_ratio)) mess_strings.append( ' > Number of selected stack slices for each ROI ({} x {}): {}'.format( shape_P[0], shape_P[1], shape_P[2])) mess_strings.append(' > Parallelepiped size: ({0},{1},{2}) pixel =' ' [{3:2.2f} {4:2.2f} {5:2.2f}] um'.format( shape_P[0], shape_P[1], shape_P[2], shape_P[0] * parameters['px_size_xy'], shape_P[1] * parameters['px_size_xy'], shape_P[2] * parameters['px_size_z'])) # create .txt report file txt_info_filename = 'Orientations_INFO_' + stack_prefix + '_' \ + str(int(parameters['roi_xy_pix'] * parameters['px_size_xy'])) + 'um.txt' txt_info_path = os.path.join(os.path.dirname(source_path), txt_info_filename) # print analysis report to screen and write into .txt file all introductory information write_on_txt(mess_strings, txt_info_path, _print=True, mode='w') # clear list of strings mess_strings.clear() # 1 - OPEN STACK ------------------------------------------------------------------------ # extract data (entire volume 'V') volume = InputFile(source_path).whole() # change axes: (r, c, z) -> (z, y, x) volume = np.moveaxis(volume, 0, -1) # compute volume size shape_V = np.array(volume.shape) pixel_for_slice = shape_V[0] * shape_V[1] total_voxel_V = pixel_for_slice * shape_V[2] # print volume size information mess_strings.append('\n\n*** Loaded volume size') mess_strings.append(' > Size of entire volume: ({}, {}, {})'.format( shape_V[0], shape_V[1], shape_V[2])) mess_strings.append( ' > Pixels for stack slice: {}'.format(pixel_for_slice)) mess_strings.append(' > Total number of voxels: {}'.format(total_voxel_V)) # extract list of math information (strings) about the volume.npy variable info = print_info(volume, text='\nVolume informations:', _std=False, _return=True) mess_strings = mess_strings + info # print volume information to screen and add it to the report .txt file write_on_txt(mess_strings, txt_info_path, _print=True, mode='a') # clear list of strings mess_strings.clear() # 2 - LOOP FOR BLOCK EXTRACTION and ANALYSIS ------------------------------------------- print('\n\n') print(Bcolors.OKBLUE + '*** Start Structure Tensor Analysis... ' + Bcolors.ENDC) t_start = time.time() # create empty result matrix R, shape_R = create_R(shape_V, shape_P) # conduct analysis on input volume R, count = iterate_orientation_analysis(volume, R, parameters, shape_R, shape_P, _verbose) mess_strings.append('\n > Orientation analysis complete.') # retrieve information about the analyzed data block_with_cell = np.count_nonzero(R[Param.CELL_INFO]) block_with_info = np.count_nonzero(R[Param.ORIENT_INFO]) p_rejec_cell = 100 * (1 - (block_with_cell / count)) p_rejec_info_tot = 100 * (1 - (block_with_info / count)) p_rejec_info = 100 * (1 - (block_with_info / block_with_cell)) # get analysis time t_process = time.time() - t_start # create result strings mess_strings.append('\n\n*** Results of Orientation analysis:') mess_strings.append(' > Expected iterations: {}'.format(np.prod(shape_R))) mess_strings.append(' > Total iterations: {}'.format(count)) mess_strings.append(' > Time elapsed: {0:.3f} s'.format(t_process)) mess_strings.append('\n > Total blocks analyzed: {}'.format(count)) mess_strings.append( ' > Block with cell: {0}, rejected from total: {1} ({2:0.1f}%)'.format( block_with_cell, count - block_with_cell, p_rejec_cell)) mess_strings.append( ' > Block with gradient information: {}'.format(block_with_info)) mess_strings.append( ' > rejected from total: {0} ({1:0.1f}%)'.format( count - block_with_info, p_rejec_info_tot)) mess_strings.append( ' > rejected from block with cell: {0} ({1:0.1f}%)'.format( block_with_cell - block_with_info, p_rejec_info)) mess_strings.append( '\n > R matrix created ( shape: ({}, {}, {}) cells (zyx) )'.format( R.shape[0], R.shape[1], R.shape[2])) # print information to screen and add it to the report .txt file write_on_txt(mess_strings, txt_info_path, _print=True, mode='a') # clear list of strings mess_strings.clear() # 3 - DISARRAY AND FRACTIONAL ANISOTROPY ESTIMATION ------------------------------------- # estimate local disarrays and fractional anisotropy, write estimated values also inside R mtrx_of_disarrays, mtrx_of_local_fa, shape_G, R = estimate_local_disarray( R, parameters, ev_index=2, _verb=_verbose, _verb_deep=_deep_verbose) # 4a - SAVE R ( updated with estimate_local_disarray() ) TO NUMPY FILE ------------------ # create result matrix (R) filename: R_filename = 'R_' + stack_prefix + '_' + str( int(parameters['roi_xy_pix'] * parameters['px_size_xy'])) + 'um.npy' R_prefix = R_filename.split('.')[0] R_filepath = os.path.join(base_path, process_folder, R_filename) # save results to R.npy np.save(R_filepath, R) mess_strings.append('\n> R matrix saved to: {}'.format( os.path.dirname(source_path))) mess_strings.append('> with name: {}'.format(R_filename)) mess_strings.append('\n> Information .txt file saved to: {}'.format( os.path.dirname(txt_info_path))) mess_strings.append('> with name: {}'.format(txt_info_filename)) # print information to screen and add it to the report .txt file write_on_txt(mess_strings, txt_info_path, _print=True, mode='a') # clear list of strings mess_strings.clear() # 4b - SAVE DISARRAY TO NUMPY FILE AND COMPILE RESULTS TXT FILE ------------------------- # save disarray matrices (computed with arithmetic and weighted means) to numpy file disarray_np_filename = dict() for mode in [att for att in vars(Mode) if str(att)[0] is not '_']: disarray_np_filename[getattr(Mode, mode)] = save_in_numpy_file( mtrx_of_disarrays[getattr(Mode, mode)], R_prefix, shape_G, parameters, base_path, process_folder, data_prefix='MatrixDisarray_{}_'.format(mode)) # save fractional anisotropy to numpy file fa_np_filename = save_in_numpy_file(mtrx_of_local_fa, R_prefix, shape_G, parameters, base_path, process_folder, data_prefix='FA_local_') mess_strings.append( '\n> Disarray and Fractional Anisotropy matrices saved to:') mess_strings.append('> {}'.format(os.path.join(base_path, process_folder))) mess_strings.append('with name: \n > {}\n > {}\n > {}\n'.format( disarray_np_filename[Mode.ARITH], disarray_np_filename[Mode.WEIGHT], fa_np_filename)) mess_strings.append('\n') # 5 - STATISTICAL ANALYSIS, HISTOGRAMS AND SAVINGS -------------------------------------- # estimate statistics (see class Stat) of disarray and fractional anisotropy matrices disarray_ARITM_stats = statistics_base(mtrx_of_disarrays[Mode.ARITH], invalid_value=CONST.INV) disarray_WEIGHT_stats = statistics_base(mtrx_of_disarrays[Mode.WEIGHT], w=mtrx_of_local_fa, invalid_value=CONST.INV) fa_stats = statistics_base(mtrx_of_local_fa, invalid_value=CONST.INV) # compile/append strings of statistical results s1 = compile_results_strings(mtrx_of_disarrays[Mode.ARITH], 'Disarray', disarray_ARITM_stats, 'ARITH', '%') s2 = compile_results_strings(mtrx_of_disarrays[Mode.WEIGHT], 'Disarray', disarray_WEIGHT_stats, 'WEIGHT', '%') s3 = compile_results_strings(mtrx_of_local_fa, 'Fractional Anisotropy', fa_stats) disarray_and_fa_results_strings = s1 + ['\n\n\n'] + s2 + ['\n\n\n'] + s3 # update mess strings mess_strings = mess_strings + disarray_and_fa_results_strings # create results .txt filename and path txt_results_filename = 'results_disarray_by_{}_G({},{},{})_limNeig{}.txt'.format( R_prefix, int(shape_G[0]), int(shape_G[1]), int(shape_G[2]), int(parameters['neighbours_lim'])) # save to .csv if _save_csv: mess_strings.append('\n> CSV files saved to:') # save disarray and fractional anisotropy matrices to .csv file for (mtrx, np_fname) in zip([ mtrx_of_disarrays[Mode.ARITH], mtrx_of_disarrays[Mode.WEIGHT], mtrx_of_local_fa ], [ disarray_np_filename[Mode.ARITH], disarray_np_filename[Mode.WEIGHT], fa_np_filename ]): # extract only valid values (different from INV = -1) values = mtrx[mtrx != CONST.INV] # create .csv file path and save data csv_filename = np_fname.split('.')[0] + '.csv' csv_filepath = os.path.join(base_path, process_folder, csv_filename) np.savetxt(csv_filepath, values, delimiter=",", fmt='%f') mess_strings.append('> {}'.format(csv_filepath)) # save histograms if _save_hist: mess_strings.append('\n> Histogram plots saved to:') # zip matrices, description and filenames for (mtrx, lbl, np_fname) in zip([ mtrx_of_disarrays[Mode.ARITH], mtrx_of_disarrays[Mode.WEIGHT], mtrx_of_local_fa ], [ 'Local Disarray % (arithmetic mean)', 'Local Disarray % (weighted mean)', 'Local Fractional Anisotropy' ], [ disarray_np_filename[Mode.ARITH], disarray_np_filename[Mode.WEIGHT], fa_np_filename ]): # extract only valid values (different from INV = -1) values = mtrx[mtrx != CONST.INV] # create file path hist_fname = '.'.join(np_fname.split('.')[:-1]) + '.tiff' hist_filepath = os.path.join(base_path, process_folder, hist_fname) # create histograms and save them to image files plot_histogram(values, xlabel=lbl, ylabel='Sub-volume occurrence', filepath=hist_filepath) mess_strings.append('> {}'.format(hist_filepath)) # save disarray and fa maps if _save_maps: mess_strings.append( '\n> Disarray and Fractional Anisotropy plots saved to:') # disarray value normalization: # - in order to preserve the little differences between ARITM and WEIGH disarray matrices, # these are normalized together # - invalid values are NOT removed for preserving the original matrix (image) shape # - invalid values (if present) are set to the minimum value abs_max = np.max([ mtrx_of_disarrays[Mode.ARITH].max(), mtrx_of_disarrays[Mode.WEIGHT].max() ]) abs_min = np.min([ mtrx_of_disarrays[Mode.ARITH].min(), mtrx_of_disarrays[Mode.WEIGHT].min() ]) dis_norm_A = 255 * ((mtrx_of_disarrays[Mode.ARITH] - abs_min) / (abs_max - abs_min)) dis_norm_W = 255 * ((mtrx_of_disarrays[Mode.WEIGHT] - abs_min) / (abs_max - abs_min)) # define destination folder dest_folder = os.path.join(base_path, process_folder) # create and save data frames (disarray and fractional anisotropy) for (mtrx, np_fname) in zip([dis_norm_A, dis_norm_W, mtrx_of_local_fa], [ disarray_np_filename[Mode.ARITH], disarray_np_filename[Mode.WEIGHT], fa_np_filename ]): # plot frames and save them inside a sub_folder (folder_path) folder_path = plot_map_and_save(mtrx, np_fname, dest_folder, shape_G, shape_P) mess_strings.append('> {}'.format(folder_path)) # print information to screen and add it to the results .txt file txt_results_filepath = os.path.join(base_path, process_folder, txt_results_filename) write_on_txt(mess_strings, txt_results_filepath, _print=True, mode='w')
def main(parser): ## Extract input information FROM TERMINAL ======================= args = parser.parse_args() R_filepath = manage_path_argument(args.R_path) param_filename = args.parameters_filename[0] # preferences _verbose = args.verbose _deep_verbose = args.deep_verbose _save_csv = args.csv _save_hist = args.histogram _save_maps = args.maps if _verbose: print(Bcolors.FAIL + ' *** VERBOSE MODE *** ' + Bcolors.ENDC) if _deep_verbose: print(Bcolors.FAIL + ' *** DEBUGGING MODE *** ' + Bcolors.ENDC) ### =============================================================== # extract filenames and folders R_filename = os.path.basename(R_filepath) process_folder = os.path.basename(os.path.dirname(R_filepath)) base_path = os.path.dirname(os.path.dirname(R_filepath)) param_filepath = os.path.join(base_path, process_folder, param_filename) stack_prefix = R_filepath.split('.')[1] # create introductory information mess_strings = list() mess_strings.append(Bcolors.OKBLUE + '\n\n*** Disarray Analysis ***\n' + Bcolors.ENDC) mess_strings.append(' > R matrix: {}'.format(R_filename)) mess_strings.append(' > Base path: {}'.format(base_path)) mess_strings.append(' > Parameter filename: {}'.format(param_filename)) mess_strings.append(' > Parameter filepath: {}'.format(param_filepath)) mess_strings.append('') mess_strings.append(' > PREFERENCES:') mess_strings.append(' - _verbose {}'.format(_verbose)) mess_strings.append(' - _deep_verbose {}'.format(_deep_verbose)) mess_strings.append(' - _save_csv {}'.format(_save_csv)) mess_strings.append(' - _save_hist {}'.format(_save_hist)) mess_strings.append(' - _save_maps {}'.format(_save_maps)) # extract parameters param_names = [ 'roi_xy_pix', 'px_size_xy', 'px_size_z', 'mode_ratio', 'threshold_on_cell_ratio', 'local_disarray_xy_side', 'local_disarray_z_side', 'neighbours_lim', 'fwhm_xy', 'fwhm_z' ] param_values = search_value_in_txt(param_filepath, param_names) # create dictionary of parameters parameters = {} mess_strings.append('\n\n*** Parameters used:') mess_strings.append( ' > Parameters extracted from {}\n'.format(param_filename)) for i, p_name in enumerate(param_names): parameters[p_name] = float(param_values[i]) mess_strings.append('> {} - {}'.format(p_name, parameters[p_name])) # acquisition system characteristics: ratio of the pixel size along the z and x-y axes ps_ratio = parameters['px_size_z'] / parameters['px_size_xy'] # size of the analyzed block along the z axis shape_P = np.array( (int(parameters['roi_xy_pix']), int(parameters['roi_xy_pix']), int(parameters['roi_xy_pix'] / ps_ratio))).astype(np.int32) mess_strings.append('\n *** Analysis configuration') mess_strings.append( ' > Pixel size ratio (z / xy) = {0:0.2f}'.format(ps_ratio)) mess_strings.append( ' > Number of selected stack slices for each ROI ({} x {}): {}'.format( shape_P[0], shape_P[1], shape_P[2])) mess_strings.append(' > Parallelepiped size: ({0},{1},{2}) pixel =' ' [{3:2.2f} {4:2.2f} {5:2.2f}] um'.format( shape_P[0], shape_P[1], shape_P[2], shape_P[0] * parameters['px_size_xy'], shape_P[1] * parameters['px_size_xy'], shape_P[2] * parameters['px_size_z'])) # print to screen for s in mess_strings: print(s) # clear list of strings mess_strings.clear() # load R array R = np.load((R_filepath)) # --- DISARRAY AND FRACTIONAL ANISOTROPY ESTIMATION ------------------------------------- # estimate local disarrays and fractional anisotropy, write estimated values also inside R mtrx_of_disarrays, mtrx_of_local_fa, shape_G, R = estimate_local_disarray( R, parameters, ev_index=2, _verb=_verbose, _verb_deep=_deep_verbose) # --- SAVE R TO NUMPY FILE ------------------------------------------------------------- # retrieve R array prefix R_prefix = R_filename.split('.')[0] # save results to R.npy np.save(R_filepath, R) mess_strings.append('\n> R matrix saved to: {}'.format( os.path.dirname(R_filepath))) mess_strings.append('> with name: {}'.format(R_filename)) # print to screen for l in mess_strings: print(l) # clear list of strings mess_strings.clear() # --- SAVE DISARRAY MATRICES TO NUMPY FILE AND COMPILE RESULTS TXT FILE ------------------ # save disarray matrices (computed with arithmetic and weighted means) to numpy file disarray_np_filename = dict() for mode in [att for att in vars(Mode) if str(att)[0] is not '_']: disarray_np_filename[getattr(Mode, mode)] = save_in_numpy_file( mtrx_of_disarrays[getattr(Mode, mode)], R_prefix, shape_G, parameters, base_path, process_folder, data_prefix='MatrixDisarray_{}_'.format(mode)) # save fractional anisotropy to numpy file fa_np_filename = save_in_numpy_file(mtrx_of_local_fa, R_prefix, shape_G, parameters, base_path, process_folder, data_prefix='FA_local_') mess_strings.append( '\n> Disarray and Fractional Anisotropy matrices saved to:') mess_strings.append('> {}'.format(os.path.join(base_path, process_folder))) mess_strings.append('with name: \n > {}\n > {}\n > {}\n'.format( disarray_np_filename[Mode.ARITH], disarray_np_filename[Mode.WEIGHT], fa_np_filename)) mess_strings.append('\n') # --- STATISTICAL ANALYSIS, HISTOGRAMS AND SAVINGS -------------------------------------- # estimate statistics (see class Stat) of disarray and fractional anisotropy matrices disarray_ARITM_stats = statistics_base(mtrx_of_disarrays[Mode.ARITH], invalid_value=CONST.INV) disarray_WEIGHT_stats = statistics_base(mtrx_of_disarrays[Mode.WEIGHT], w=mtrx_of_local_fa, invalid_value=CONST.INV) fa_stats = statistics_base(mtrx_of_local_fa, invalid_value=CONST.INV) # compile/append strings of statistical results s1 = compile_results_strings(mtrx_of_disarrays[Mode.ARITH], 'Disarray', disarray_ARITM_stats, 'ARITH', '%') s2 = compile_results_strings(mtrx_of_disarrays[Mode.WEIGHT], 'Disarray', disarray_WEIGHT_stats, 'WEIGHT', '%') s3 = compile_results_strings(mtrx_of_local_fa, 'Fractional Anisotropy', fa_stats) disarray_and_fa_results_strings = s1 + ['\n\n\n'] + s2 + ['\n\n\n'] + s3 # update mess strings mess_strings = mess_strings + disarray_and_fa_results_strings # create results .txt filename and path txt_results_filename = 'results_disarray_by_{}_G({},{},{})_limNeig{}.txt'.format( R_prefix, int(shape_G[0]), int(shape_G[1]), int(shape_G[2]), int(parameters['neighbours_lim'])) # save to .csv if _save_csv: mess_strings.append('\n> CSV files saved to:') # save disarray and fractional anisotropy matrices to .csv file for (mtrx, np_fname) in zip([ mtrx_of_disarrays[Mode.ARITH], mtrx_of_disarrays[Mode.WEIGHT], mtrx_of_local_fa ], [ disarray_np_filename[Mode.ARITH], disarray_np_filename[Mode.WEIGHT], fa_np_filename ]): # extract only valid values (different from INV = -1) values = mtrx[mtrx != CONST.INV] # create .csv file path and save data csv_filename = np_fname.split('.')[0] + '.csv' csv_filepath = os.path.join(base_path, process_folder, csv_filename) np.savetxt(csv_filepath, values, delimiter=",", fmt='%f') mess_strings.append('> {}'.format(csv_filepath)) # save histograms if _save_hist: mess_strings.append('\n> Histogram plots are saved in:') # zip matrices, description and filenames for (mtrx, lbl, np_fname) in zip([ mtrx_of_disarrays[Mode.ARITH], mtrx_of_disarrays[Mode.WEIGHT], mtrx_of_local_fa ], [ 'Local Disarray % (Arithmetic mean)', 'Local Disarray % (Weighted mean)', 'Local Fractional Anisotropy' ], [ disarray_np_filename[Mode.ARITH], disarray_np_filename[Mode.WEIGHT], fa_np_filename ]): # extract only valid values (different of INV = -1) values = mtrx[mtrx != CONST.INV] # create file path hist_fname = '.'.join(np_fname.split('.')[:-1]) + '.tiff' hist_filepath = os.path.join(base_path, process_folder, hist_fname) # create histograms and save them to image files plot_histogram(values, xlabel=lbl, ylabel='Sub-volume occurrence', filepath=hist_filepath) mess_strings.append('> {}'.format(hist_filepath)) # save disarray and fa maps if _save_maps: mess_strings.append( '\n> Disarray and Fractional Anisotropy plots saved to:') # disarray value normalization: # - in order to preserve the little differences between ARITM and WEIGH disarray matrices, # these are normalized together # - invalid values are NOT removed for preserving the original matrix (image) shape # - invalid values (if present) are set to the minimum value abs_max = np.max([ mtrx_of_disarrays[Mode.ARITH].max(), mtrx_of_disarrays[Mode.WEIGHT].max() ]) abs_min = np.min([ mtrx_of_disarrays[Mode.ARITH].min(), mtrx_of_disarrays[Mode.WEIGHT].min() ]) dis_norm_A = 255 * ((mtrx_of_disarrays[Mode.ARITH] - abs_min) / (abs_max - abs_min)) dis_norm_W = 255 * ((mtrx_of_disarrays[Mode.WEIGHT] - abs_min) / (abs_max - abs_min)) # define destination folder dest_folder = os.path.join(base_path, process_folder) # create and save data frames (disarray and fractional anisotropy) for (mtrx, np_fname) in zip([dis_norm_A, dis_norm_W, mtrx_of_local_fa], [ disarray_np_filename[Mode.ARITH], disarray_np_filename[Mode.WEIGHT], fa_np_filename ]): # plot frames and save them inside a sub_folder (folder_path) folder_path = plot_map_and_save(mtrx, np_fname, dest_folder, shape_G, shape_P) mess_strings.append('> {}'.format(folder_path)) # print information to screen and add it to the results .txt file txt_results_filepath = os.path.join(base_path, process_folder, txt_results_filename) write_on_txt(mess_strings, txt_results_filepath, _print=True, mode='w')
def main(parser): args = parser.parse_args() # Extract input information source_path = manage_path_argument(args.source_path) parameter_filename = args.parameters_filename[0] # extract filenames and folders stack_name = os.path.basename(source_path) process_folder = os.path.basename(os.path.dirname(source_path)) base_path = os.path.dirname(os.path.dirname(source_path)) parameter_filepath = os.path.join(base_path, process_folder, parameter_filename) stack_prefix = stack_name.split('.')[0] # extract other preferences _verbose = args.verbose _save_csv = args.csv # create sointroductiveme informations mess_strings = list() mess_strings.append('\n\n*** ST orientation Analysis ***\n') mess_strings.append(' > source path: {}'.format(source_path)) mess_strings.append(' > stack name: {}'.format(stack_name)) mess_strings.append(' > process folder: {}'.format(process_folder)) mess_strings.append(' > base path: {}'.format(base_path)) mess_strings.append(' > Parameter filename: {}'.format(parameter_filename)) mess_strings.append(' > Parameter filepath: {}'.format(parameter_filepath)) mess_strings.append('') # TODO here added local_disarray_z_side and local_disarray_xy_side # extract parameters param_names = [ 'roi_xy_pix', 'px_size_xy', 'px_size_z', 'mode_ratio', 'threshold_on_cell_ratio', 'local_disarray_xy_side', 'local_disarray_z_side', 'neighbours_lim', 'fwhm_xy', 'fwhm_z' ] param_values = search_value_in_txt(parameter_filepath, param_names) # create dictionary of parameters parameters = {} mess_strings.append('\n\n*** Parameters used:') mess_strings.append( ' > Parameters extracted from {}\n'.format(parameter_filename)) for i, p_name in enumerate(param_names): parameters[p_name] = float(param_values[i]) mess_strings.append('> {} - {}'.format(p_name, parameters[p_name])) # Parameters of Acquisition System: # ratio between pixel size in z and xy ps_ratio = parameters['px_size_z'] / parameters['px_size_xy'] # analysis block dimension in z-axis num_of_slices_P = int(parameters['roi_xy_pix'] / ps_ratio) row_P = col_P = int(parameters['roi_xy_pix']) shape_P = np.array((row_P, col_P, num_of_slices_P)).astype(np.int32) mess_strings.append('\n *** Analysis configuration') mess_strings.append( ' > Rapporto fra Pixel Size (z / xy) = {0:0.2f}'.format(ps_ratio)) mess_strings.append( ' > Numero di slice selezionate per ogni ROI ({} x {}): {}'.format( row_P, col_P, num_of_slices_P)) mess_strings.append( ' > Dimension of Parallelepiped: ({0},{1},{2}) pixel =' ' [{3:2.2f} {4:2.2f} {5:2.2f}] um'.format( shape_P[0], shape_P[1], shape_P[2], row_P * parameters['px_size_xy'], col_P * parameters['px_size_xy'], num_of_slices_P * parameters['px_size_z'])) # create result.txt filename: txt_filename = 'Orientations_' + stack_prefix + '_' \ + str(int(parameters['roi_xy_pix'] * parameters['px_size_xy'])) + 'um.txt' txt_path = os.path.join(os.path.dirname(source_path), txt_filename) # print and write into .txt introductive informations write_on_txt(mess_strings, txt_path, _print=True) # clear list of strings mess_strings.clear() # 1 ---------------------------------------------------------------------------------------------------- # OPEN STACK # extract data - entire Volume: 'V' volume = InputFile(source_path).whole() # NB - in futuro va cambiata gestion assi volume = np.moveaxis(volume, 0, -1) # (r, c, z) -> (z, y, x) # calculate dimension shape_V = np.array(volume.shape) pixel_for_slice = shape_V[0] * shape_V[1] total_voxel_V = pixel_for_slice * shape_V[2] mess_strings.append('\n\n*** Entire loaded Volume dimension:') mess_strings.append(' > Dimension if entire Volume : ({}, {}, {})'.format( shape_V[0], shape_V[1], shape_V[2])) mess_strings.append( ' > Pixel for slice : {}'.format(pixel_for_slice)) mess_strings.append( ' > Total voxel in Volume : {}'.format(total_voxel_V)) # extract list of math informations (as strings) about volume.npy variable info = print_info(volume, text='\nVolume informations:', _std=False, _return=True) mess_strings = mess_strings + info # print and write into .txt write_on_txt(mess_strings, txt_path, _print=True) # clear list of strings mess_strings.clear() # 2 ---------------------------------------------------------------------------------------------------- # CYCLE FOR BLOCKS EXTRACTION and ANALYSIS print('\n\n') print('*** Start Structure Tensor analysis... ') t_start = time.time() # create empty Result matrix R, shape_R = create_R(shape_V, shape_P) # estimate sigma of blurring for isotropic resolution sigma_blur = sigma_for_uniform_resolution( FWHM_xy=parameters['fwhm_xy'], FWHM_z=parameters['fwhm_z'], px_size_xy=parameters['px_size_xy']) perc = 0 count = 0 # count iteration tot = np.prod(shape_R) print(' > Expected iterations : ', tot) for z in range(shape_R[2]): if _verbose: print('\n\n') print('{0:0.1f} % - z: {1:3}'.format(perc, z)) for r in range(shape_R[0]): for c in range(shape_R[1]): start_coord = create_coord_by_iter(r, c, z, shape_P) slice_coord = create_slice_coordinate(start_coord, shape_P) perc = 100 * (count / tot) if _verbose: print('\n') # save init info in R R[r, c, z]['id_block'] = count R[r, c, z]['init_coord'] = start_coord # extract parallelepiped parall = volume[slice_coord] # check dimension (if iteration is on border of volume, add zero_pad) parall = pad_dimension(parall, shape_P) # If it's not all black... if np.max(parall) != 0: # analysis of parallelepiped extracted there_is_cell, there_is_info, results = block_analysis( parall, shape_P, parameters, sigma_blur, _verbose) # save info in R[r, c, z] if there_is_cell: R[r, c, z]['cell_info'] = True if there_is_info: R[r, c, z]['orient_info'] = True # save results in R if _verbose: print(' saved in R: ') for key in results.keys(): R[r, c, z][key] = results[key] if _verbose: print(' > {} : {}'.format(key, R[r, c, z][key])) else: if _verbose: print(' block rejected ') print() count += 1 block_with_cell = np.count_nonzero(R['cell_info']) block_with_info = np.count_nonzero(R['orient_info']) p_rejec_cell = 100 * (1 - (block_with_cell / count)) p_rejec_info_tot = 100 * (1 - (block_with_info / count)) p_rejec_info = 100 * (1 - (block_with_info / block_with_cell)) t_process = time.time() - t_start mess_strings.append('\n\n*** Results of Orientation analysis:') mess_strings.append(' > Expected iterations : {}'.format(np.prod(shape_R))) mess_strings.append(' > total_ iteration : {}'.format(count)) mess_strings.append(' > Time elapsed: {0:.3f} s'.format(t_process)) mess_strings.append('\n > Total blocks: {}'.format(count)) mess_strings.append( ' > block with cell : {0}, rejected from total: {1} ({2:0.1f}%)'. format(block_with_cell, count - block_with_cell, p_rejec_cell)) mess_strings.append( ' > block with gradient information : {}'.format(block_with_info)) mess_strings.append(' > rejected from total: {0} ({1:0.1f}%)'.format( count - block_with_info, p_rejec_info_tot)) mess_strings.append( ' > rejected from block with cell: {0} ({1:0.1f}%)'.format( block_with_cell - block_with_info, p_rejec_info)) # print and write into .txt write_on_txt(mess_strings, txt_path, _print=True) # clear list of strings mess_strings.clear() # 3 ---------------------------------------------------------------------------------------------------- # Disarray estimation # the function estimate local disarrays and write these values also inside R matrix_of_disarrays, shape_G, R = estimate_local_disarry(R, parameters, ev_index=2, _verb=True, _verb_deep=False) # extract only valid disarray values disarray_values = matrix_of_disarrays[matrix_of_disarrays != -1] # 4 ---------------------------------------------------------------------------------------------------- # WRITE RESULTS AND SAVE # create result matrix (R) filename: R_filename = 'R_' + stack_prefix + '_' + str( int(parameters['roi_xy_pix'] * parameters['px_size_xy'])) + 'um.npy' R_prefix = R_filename.split('.')[0] R_filepath = os.path.join(base_path, process_folder, R_filename) # Save Results in R.npy np.save(R_filepath, R) mess_strings.append('\n > R matrix saved in: {}'.format( os.path.dirname(source_path))) mess_strings.append(' > with name: {}'.format(R_filename)) mess_strings.append('\n > Results .txt file saved in: {}'.format( os.path.dirname(txt_path))) mess_strings.append(' > with name: {}'.format(txt_filename)) # create filename of numpy.file where save disarray matrix disarray_numpy_filename = 'MatrixDisarray_{}_G({},{},{})_limNeig{}.npy'.format( R_prefix, int(shape_G[0]), int(shape_G[1]), int(shape_G[2]), int(parameters['neighbours_lim'])) mess_strings.append('\n> Matrix of Disarray saved in:') mess_strings.append(os.path.join(base_path, process_folder)) mess_strings.append(' > with name: \n{}'.format(disarray_numpy_filename)) # save numpy file np.save(os.path.join(base_path, process_folder, disarray_numpy_filename), matrix_of_disarrays) # create results strings mess_strings.append( '\n\n*** Results of statistical analysis of Disarray on accepted points. \n' ) mess_strings.append('> Disarray (%):= 100 * (1 - alignment)\n') mess_strings.append('> Matrix of disarray shape: {}'.format( matrix_of_disarrays.shape)) mess_strings.append('> Valid disarray values: {}'.format( disarray_values.shape)) mess_strings.append('\n> Disarray mean: {0:0.2f}%'.format( np.mean(disarray_values))) mess_strings.append('> Disarray std: {0:0.2f}% '.format( np.std(disarray_values))) mess_strings.append('> Disarray (min, MAX)%: ({0:0.2f}, {1:0.2f})'.format( np.min(disarray_values), np.max(disarray_values))) # create results.txt filename and filepath disarray_results_filename = 'results_disarray_by_{}_G({},{},{})_limNeig{}.txt'.format( R_prefix, int(shape_G[0]), int(shape_G[1]), int(shape_G[2]), int(parameters['neighbours_lim'])) disarray_txt_filepath = os.path.join(base_path, process_folder, disarray_results_filename) if _save_csv: disarray_csv_filename = disarray_results_filename.split( '.')[0] + '.csv' np.savetxt(os.path.join(base_path, process_folder, disarray_csv_filename), disarray_values, delimiter=",", fmt='%f') # print and write into .txt write_on_txt(mess_strings, disarray_txt_filepath, _print=True)