def save_metrics_images(data, metric_names, viz_obj: MedicalImageVisualizer): # ************** Plot and save Metrics for ROI ***************** data.loc['AVG'] = data.mean() # Compute all average values title = '' input_dics = [] for c_metric in metric_names: title += F"{c_metric}: {data.loc['AVG'][c_metric]:.3f}" input_dics.append(data[c_metric].dropna().to_dict()) viz_obj.plot_multiple_bar_plots(input_dics, title=title, legends=metric_names, file_name='Mean_Performance.png')
def __init__(self, **kwargs): self.viz_obj = MedicalImageVisualizer( output_folder="/data/UM/COVID/PREPROC/2D/output_imgs", disp_images=False ) # TODO it should be a unique object but is not working # All the arguments that are passed to the constructor of the class MUST have its name on it. for arg_name, arg_value in kwargs.items(): self.__dict__["_" + arg_name] = arg_value
def preprocess_imgs_and_ctrs(input_folder, output_folder, resampling, img_names, ctr_names_orig, out_img_names, out_ctr_names_orig, match_whole_w_ctr, normalize_imgs, ctr_folder_names, bias_corrections, fix_adc, options): """ Generates nrrd files from dicom files. It does it for contours and series :param input_folder: Path to the DICOM files :param output_folder: Path to output nrrd files :param resampling: Array with 3 values indicating each resolution x,y,z :param img_names: Array Names of the images we want to transform :param ctr_names: Array Name of the contours we want to read :param out_img_names: Output img names :param out_ctr_names: Output ctr names :param match_whole_w_ctr: Bool array Indicate if we need to match the name of the contours exactly or as a RegEx :param normalize_imgs: Bool array Indicates if we need to perform percentile normalization to the images :param ctr_folder_names: Str Array With the name of the 'folder' names to search for contours :return: """ viz_obj = MedicalImageVisualizer() ctr_names = ctr_names_orig.copy( ) # Patch to avoid problems with global variable out_ctr_names = out_ctr_names_orig.copy( ) # Patch to avoid problems with global variable create_folder(output_folder) # ******************** READS DATA ******************* print('\tReading data....') [orig_imgs, final_img_names] = read_dicom_mri_series(input_folder, img_names, out_img_names) [orig_ctrs, final_ctr_names ] = read_rtstruct_mri_series(input_folder, ctr_folder_names=ctr_folder_names, in_ctr_names=ctr_names, out_ctr_names=out_ctr_names, ref_img_itk=orig_imgs[0], match_whole_word=match_whole_w_ctr) # Saves original images without bias correction write_itk_imgs(output_folder, 'img', orig_imgs, final_img_names) write_itk_imgs(output_folder, 'ctr', orig_ctrs, final_ctr_names) # ************** Correcting ADC intensities ************* for idx_fix_adc, c_fix_adc in enumerate(fix_adc): if c_fix_adc: print( '\tFixing ADC, changing "black" values on original images ....' ) orig_imgs[idx_fix_adc] = correct_adc_itk(orig_imgs[idx_fix_adc]) # ************** Normalize images (N4K bias correction) ************* if options[PreprocParams.bias_correction]: print("\tBias correction.....") pretxt = 'img_n4k' for ii in range(len(orig_imgs)): if bias_corrections[ii]: # First try to read an existing file, if not, compute it file_name = join( output_folder, '{}_{}.nrrd'.format(pretxt, final_img_names[ii])) if exists(file_name): print('\t\tReading previous n4k file...') orig_imgs[ii] = sitk.ReadImage(file_name) else: orig_imgs[ii] = n4itk(orig_imgs[ii]) # Saving bias corrected images write_itk_imgs(output_folder, pretxt, orig_imgs, final_img_names) norm_perc = options[PreprocParams.normalize_percentiles] for idx_img in range(len(orig_imgs)): if normalize_imgs[idx_img]: print(F'\tNormalizing intensities ... {img_names[idx_img]}') orig_imgs[idx_img] = normalize_to_percentiles([orig_imgs[idx_img]], norm_perc[0], norm_perc[1])[0] # *********** Resample to [.5,.5,.5] and interpolate with optical flow ****************** if options[PreprocParams.resample]: print("\tResampling .....") # viz_obj.plot_img_and_ctrs_itk(orig_imgs[0], orig_ctrs, slices=SliceMode.MIDDLE, title='Befor resampling') resampled_imgs, resampled_ctrs = reample_imgs_and_ctrs( orig_imgs, orig_ctrs, resampling) # viz_obj.plot_img_and_ctrs_itk(resampled_imgs[0], resampled_ctrs, slices=SliceMode.MIDDLE,title='RESAMPLED') if options[PreprocParams.optical_flow_ctr_interpolation]: print('\t\tOptical flow ....') resampled_ctrs = optical_flow_interpolation(resampled_ctrs) write_itk_imgs(output_folder, 'hr', resampled_imgs, final_img_names) write_itk_imgs(output_folder, 'hr_ctr', resampled_ctrs, final_ctr_names) # *********** Crop and normalize to 0 and 1 ************ if options[PreprocParams.compute_roi_from_intersection]: print("\tCropping.....") roi_imgs, roi_ctrs, startROI_final, sizeROI_final = getCroppedIsotropicImgsOZ( resampled_imgs, resampled_ctrs) if options[PreprocParams.smooth_ctrs]: print("\t\tSmoothing ctrs.....") # viz_obj.plot_img_and_ctrs_itk(roi_ctrs[0], slices=SliceMode.MIDDLE,title='Before smoothing') roi_ctrs = smoothContours(roi_ctrs) # viz_obj.plot_img_and_ctrs_itk(roi_ctrs[0], slices=SliceMode.MIDDLE,title='After smoothing') # Saves the size and start position of the ROI, used when running the model np.savetxt(join(output_folder, 'start_ROI.csv'), startROI_final) np.savetxt(join(output_folder, 'size_ROI.csv'), sizeROI_final) # Save the roi images write_itk_imgs(output_folder, 'roi', roi_imgs, final_img_names) write_itk_imgs(output_folder, 'roi_ctr', roi_ctrs, final_ctr_names) # viz_obj.plot_imgs_and_ctrs_itk(roi_imgs, roi_ctrs, slices=SliceMode.MIDDLE, title='Final ROIs') print("DONE!!!!...")
def preprocess_imgs(input_folder, output_folder, resampling, img_names, out_img_names, normalize_imgs, bias_corrections, fix_adc, options, save_imgs: bool): """ Generates preprocessesd images only, this can be used when making classifications of the test dataset of the NN. :param input_folder: Path to the DICOM files :param output_folder: Path to output nrrd files :param resampling: Array with 3 values indicating each resolution x,y,z :param img_names: Array Names of the images we want to transform :param out_img_names: Output img names :param normalize_imgs: Bool array Indicates if we need to perform percentile normalization to the images :param save_imgs: Bool indicates if we need to save or not the output images :return: """ viz_ob = MedicalImageVisualizer() create_folder(output_folder) # ******************** READS DATA ******************* print('\tReading data....') [orig_imgs, final_img_names] = read_dicom_mri_series(input_folder, img_names, out_img_names) # Saves original images without bias correction if save_imgs: write_itk_imgs(output_folder, 'img', orig_imgs, final_img_names) if len(fix_adc) == len(orig_imgs): for idx_fix_adc, c_fix_adc in enumerate(fix_adc): if c_fix_adc: print( '\tFixing ADC, changing "black" values on original images ....' ) orig_imgs[idx_fix_adc] = correct_adc_itk( orig_imgs[idx_fix_adc]) else: print('\tNone ADC img is being fixed') # ************** Normalize images (N4K bias correction) ************* if options[PreprocParams.bias_correction]: print("\tBias correction.....") pretxt = 'img_n4k' for ii in range(len(orig_imgs)): if bias_corrections[ii]: # First try to read an existing file, if not, compute it orig_imgs[ii] = n4itk(orig_imgs[ii]) # Saving bias corrected images if save_imgs: write_itk_imgs(output_folder, pretxt, orig_imgs, final_img_names) norm_perc = options[PreprocParams.normalize_percentiles] for idx_img in range(len(orig_imgs)): if normalize_imgs[idx_img]: print(F'\tNormalizing intensities ... {img_names[idx_img]}') orig_imgs[idx_img] = normalize_to_percentiles([orig_imgs[idx_img]], norm_perc[0], norm_perc[1])[0] # *********** Resample to [.5,.5,.5] and interpolate with optical flow ****************** if options[PreprocParams.resample]: print("\tResampling .....") # viz_obj.plot_img_and_ctrs_itk(orig_imgs[0], slices=SliceMode.MIDDLE,title='Befor resampling') resampled_imgs, _ = reample_imgs_and_ctrs(orig_imgs, [], resampling) # viz_obj.plot_img_and_ctrs_itk(resampled_imgs[0], slices=SliceMode.MIDDLE,title='RESAMPLED') if save_imgs: write_itk_imgs(output_folder, 'hr', resampled_imgs, final_img_names) # *********** Crop and normalize to 0 and 1 ************ if options[PreprocParams.compute_roi_from_intersection]: print("\tCropping.....") roi_imgs, _, startROI_final, sizeROI_final = getCroppedIsotropicImgsOZ( resampled_imgs, []) # Saves the size and start position of the ROI, used when running the model np.savetxt(join(output_folder, 'start_ROI.csv'), startROI_final) np.savetxt(join(output_folder, 'size_ROI.csv'), sizeROI_final) # Save the roi images if save_imgs: write_itk_imgs(output_folder, 'roi', roi_imgs, final_img_names) return orig_imgs, resampled_imgs, roi_imgs
def __init__(self, **kwargs): self.viz_obj = MedicalImageVisualizer(disp_images=True) # All the arguments that are passed to the constructor of the class MUST have its name on it. for arg_name, arg_value in kwargs.items(): self.__dict__["_" + arg_name] = arg_value
from Preproc.UtilsPreproc import resample_to_reference_itk from preproc.UtilsItk import copyItkImage # -------------- Test example ----------------- # input_image = sitk.ReadImage("/data/UM/COVID/Kaggle_Mosmed/studies/study_0001.nii") # segmentation = mask.apply(input_image) # default model is U-net(R231) # viz_obj = MedicalImageVisualizer(disp_images=False, output_folder="/home/olmozavala/Dropbox/MyProjects/UM/Covid19_Prognosis/COVID_DL_Segmentation/LungSegmentationSoftware/OUTPUT") # viz_obj.plot_img_and_ctrs_np(sitk.GetArrayFromImage(input_image), [segmentation], # title="Test Lung seg") # Visualizing Mosmed data data_folder = "/data/UM/COVID/Kaggle_Mosmed" output_folder = "/data/UM/COVID/Kaggle_Mosmed/lung_masks" viz_obj = MedicalImageVisualizer(output_folder=join(data_folder, "output_imgs"), disp_images=False) mask_files = os.listdir(join(data_folder, "masks")) mask_files.sort() for c_mask_file_name in mask_files: c_case = int(c_mask_file_name.split("_")[1]) c_img_file_name = F"study_0{c_case:03d}.nii" c_img_file = join(data_folder, "studies", c_img_file_name) print(F"--- Working with {c_img_file} ---") itk_img = sitk.ReadImage(c_img_file) np_lung_mask = mask.apply(itk_img) # default model is U-net(R231) itk_lung_mask = copyItkImage(itk_img, np_lung_mask) viz_obj.plot_img_and_ctrs_itk(itk_img, [itk_lung_mask], title=c_img_file_name, draw_only_ctrs=True,
def make_3d_segmentation(config): """ :param config: :return: """ # *********** Reads the parameters *********** cases = config[ClassificationParams.cases] save_segmented_ctrs = config[ClassificationParams.save_segmented_ctrs] input_folder = config[ClassificationParams.input_folder] input_img_names = config[ClassificationParams.input_img_file_names] output_folder = config[ClassificationParams.output_folder] output_imgs_folder = config[ClassificationParams.output_imgs_folder] output_file_name = config[ClassificationParams.output_file_name] model_weights_file = config[ClassificationParams.model_weights_file] compute_metrics = config[ClassificationParams.compute_metrics] compute_original_resolution = config[ ClassificationParams.compute_original_resolution] save_imgs = config[ClassificationParams.save_imgs] if save_imgs: save_imgs_planes = config[ClassificationParams.save_img_planes] save_imgs_slices = config[ClassificationParams.save_img_slices] # Builds the visualization object viz_obj = MedicalImageVisualizer( disp_images=config[ClassificationParams.show_imgs], output_folder=output_imgs_folder) if compute_metrics: output_ctr_file_names = config[ ClassificationParams.output_ctr_file_names] else: output_ctr_file_names = [] # *********** Chooses the proper model *********** print('Reading model ....') model = select_3d_model(config) # *********** Reads the weights*********** print('Reading weights ....') model.load_weights(model_weights_file) examples = select_cases_from_folder(input_folder, cases) create_folder(output_imgs_folder) # *********** Makes a dataframe to contain the DSC information ********** metrics_params = config[ClassificationParams.metrics] metrics_dict = {met.name: met.value for met in metrics_params} # Check if the output fiels already exist, in thtat case read the df from it. if os.path.exists(join(output_imgs_folder, output_file_name)): data = pd.read_csv(join(output_imgs_folder, output_file_name), index_col=0) else: data_columns = list(metrics_dict.values()) if compute_original_resolution: # In this case we add all the desired metrics, but append 'original at the beginnig' data_columns = { *data_columns, *[F'{ORIGINAL_TXT}_{col}' for col in data_columns] } data = DataFrame(index=examples, columns=data_columns) # *********** Iterates over each case ********* segmentation_type = config[ClassificationParams.segmentation_type] for id_folder, current_folder in enumerate(examples): print(F'******* Computing folder {current_folder} ************') t0 = time.time() try: # -------------------- Reading data ------------- print('\t Reading data....') # All these names are predefined, for any other 3d segmentation we will need to create a different configuration imgs_itk, ctrs_itk, size_roi, start_roi, _ = read_preproc_imgs_and_ctrs_itk( input_folder, folders_to_read=[current_folder], img_names=input_img_names, ctr_names=output_ctr_file_names) imgs_np = [sitk.GetArrayFromImage(c_img) for c_img in imgs_itk[0] ] # The 0 is because we read a single fold ctrs_np = [sitk.GetArrayFromImage(c_img) for c_img in ctrs_itk[0]] # If we want to visualize the input images # viz_obj.plot_imgs_and_ctrs_itk(imgs_itk[0], ctrs_itk=ctrs_itk[0]) # ------------------- Making prediction ----------- print('\t Making prediction....') input_array = format_for_nn_classification(imgs_np) output_nn_all = model.predict(input_array, verbose=1) output_nn_np = output_nn_all[0, :, :, :, 0] # For visualizing the output of the network # viz_obj.plot_img_and_ctrs_np(img_np=output_nn_np) # ------------------- Postprocessing ----------- print('\t Postprocessing prediction....') threshold = .5 output_nn_itk = copyItkImage(imgs_itk[0][0], output_nn_np) print(F'\t\t Threshold NN output to {threshold} ....') output_nn_itk = binaryThresholdImage(output_nn_itk, threshold) if segmentation_type == SegmentationTypes.PROSTATE or segmentation_type == SegmentationTypes.PZ: print( F'\t\t Restricting to largest connected component only ....' ) output_nn_itk = getLargestConnectedComponents(output_nn_itk) output_nn_np = sitk.GetArrayViewFromImage(output_nn_itk) if compute_original_resolution: print('\t Recovering original resolution...') print('\t\t Reading original resolution images....') img_names = [ config[ ClassificationParams.resampled_resolution_image_name], config[ClassificationParams.original_resolution_image_name] ] ctr_name = config[ ClassificationParams.original_resolution_ctr_name] imgs_itk_original_temp, ctrs_itk_original_temp, _, _, _ = read_preproc_imgs_and_ctrs_itk( input_folder, folders_to_read=[current_folder], img_names=img_names, ctr_names=[ctr_name]) gt_ctr_original_itk = ctrs_itk_original_temp[0][ 0] # Retrieves the gt ctr at the original resolution img_original_resampled_itk = imgs_itk_original_temp[0][0] img_original_itk = imgs_itk_original_temp[0][1] print('\t\t Resampling to original....') output_nn_original_itk = recover_original_resolution( roi_np=output_nn_np, resampled_itk=img_original_resampled_itk, original_itk=img_original_itk, start_positions=start_roi[0], size_roi=size_roi[0]) output_nn_original_itk = binaryThresholdImage( output_nn_original_itk, threshold) if segmentation_type == SegmentationTypes.PROSTATE or segmentation_type == SegmentationTypes.PZ: print( F'\t\t\t Restricting to largest connected component only ....' ) output_nn_original_itk = getLargestConnectedComponents( output_nn_original_itk) output_nn_original_np = sitk.GetArrayViewFromImage( output_nn_original_itk) if save_segmented_ctrs: print('\t Saving Prediction...') create_folder(join(output_folder, current_folder)) # TODO at some point we will need to see if we can output more than one ctr sitk.WriteImage( output_nn_itk, join(output_folder, current_folder, output_ctr_file_names[0])) if compute_original_resolution: sitk.WriteImage( output_nn_original_itk, join(output_folder, current_folder, F'{ORIGINAL_TXT}_{output_ctr_file_names[0]}')) if compute_metrics: # Compute metrics print('\t Computing metrics....') for c_metric in metrics_params: # Here we can add more metrics if c_metric == ClassificationMetrics.DSC_3D: metric_value = numpy_dice(output_nn_np, ctrs_np[0]) data.loc[current_folder][c_metric.value] = metric_value print(F'\t\t ----- DSC: {metric_value:.3f} -----') if compute_original_resolution: metric_value = numpy_dice( output_nn_original_np, sitk.GetArrayViewFromImage( gt_ctr_original_itk)) data.loc[current_folder][ F'{ORIGINAL_TXT}_{c_metric.value}'] = metric_value print(F'\t\t ----- DSC: {metric_value:.3f} -----') # Saving the results every 10 steps if id_folder % 10 == 0: save_metrics_images(data, metric_names=list( metrics_dict.values()), viz_obj=viz_obj) data.to_csv(join(output_folder, output_file_name)) if save_imgs: print('\t Plotting images....') plot_intermediate_results(current_folder, data_columns, imgs_itk=imgs_itk[0], gt_ctr_itk=ctrs_itk[0][0], nn_ctr_itk=output_nn_itk, data=data, viz_obj=viz_obj, slices=save_imgs_slices, compute_metrics=compute_metrics) if compute_original_resolution: plot_intermediate_results( current_folder, data_columns, imgs_itk=[img_original_itk], gt_ctr_itk=gt_ctr_original_itk, nn_ctr_itk=output_nn_original_itk, data=data, viz_obj=viz_obj, slices=save_imgs_slices, compute_metrics=compute_metrics, prefix_name=ORIGINAL_TXT) except Exception as e: print( "---------------------------- Failed {} error: {} ----------------" .format(current_folder, e)) print(F'\t Done! Elapsed time {time.time()-t0:0.2f} seg') if compute_metrics: save_metrics_images(data, metric_names=list(metrics_dict.values()), viz_obj=viz_obj) data.to_csv(join(output_folder, output_file_name))
import inout.io_common from img_viz.medical import MedicalImageVisualizer from img_viz.constants import SliceMode from os.path import join, isdir import numpy as np import inout.io_rt as io_rt import SimpleITK as sitk from preproc.constants import PreprocParams viz_obj = MedicalImageVisualizer() def validateFolders(folders_to_read, dicom_path, img_names, ctr_names): final_folders = [] print("Validating folders.... be patient") folder_names = [ join(dicom_path, 'Patient-{num:04d}'.format(num=f)) for f in folders_to_read ] for idx, folder in enumerate(folder_names): try: for ctr in ctr_names: t = sitk.ReadImage(join(dicom_path, folder, ctr)) for img in img_names: t = sitk.ReadImage(join(dicom_path, folder, img))
:return: """ img_np = sitk.GetArrayFromImage(img_itk) img_np_norm = correct_adc_np(img_np, low_threshold, max_value, fix_value) return copyItkImage(img_itk, img_np_norm) # ================= Only for testing ===================== if __name__ == '__main__': from os.path import join file_name = join('..', 'imagevisualizer', 'test_data', 'input', 'Case-0001', 'img_adc.nrrd') print('Reading image....') img_itk = sitk.ReadImage(file_name) img_corrected_itk = correct_adc_itk(img_itk, low_threshold=1, max_value=4500, fix_value='mean') print('Plotting results....') viz_obj = MedicalImageVisualizer(disp_images=True) viz_obj.plot_img_and_ctrs_itk(img_itk, itk_ctrs=[], slices=SliceMode.MIDDLE, file_name_prefix='Original') viz_obj.plot_img_and_ctrs_itk(img_corrected_itk, itk_ctrs=[], slices=SliceMode.MIDDLE, file_name_prefix='Corrected')
def main(): config = get_segmentation_2d_config() cases = config[ClassificationParams.cases] save_segmented_ctrs = config[ClassificationParams.save_segmented_ctrs] input_folder = config[ClassificationParams.input_folder] input_img_names = config[ClassificationParams.input_img_file_names] output_folder = config[ClassificationParams.output_folder] output_imgs_folder = config[ClassificationParams.output_imgs_folder] output_file_name = config[ClassificationParams.output_file_name] model_weights_file = config[ClassificationParams.model_weights_file] save_imgs = config[ClassificationParams.save_imgs] # Builds the visualization object viz_obj = MedicalImageVisualizer( disp_images=config[ClassificationParams.show_imgs], output_folder=output_imgs_folder) output_ctr_file_names = config[ClassificationParams.output_ctr_file_names] # *********** Chooses the proper model *********** print('Reading model ....') model = select_2d_model(config) # *********** Reads the weights*********** print('Reading weights ....') model.load_weights(model_weights_file) examples = select_cases_from_folder(input_folder, cases) create_folder(output_imgs_folder) # *********** Makes a dataframe to contain the DSC information ********** metrics_params = config[ClassificationParams.metrics] metrics_dict = {met.name: met.value for met in metrics_params} # Check if the output files already exist, in that case read the df from it. if os.path.exists(join(output_imgs_folder, output_file_name)): data = pd.read_csv(join(output_imgs_folder, output_file_name), index_col=0) else: data_columns = list(metrics_dict.values()) data = DataFrame(index=examples, columns=data_columns) # *********** Iterates over each case ********* for id_folder, current_folder in enumerate(examples): print(F'******* Computing folder {current_folder} ************') t0 = time.time() try: # -------------------- Reading data ------------- print('\t Reading data....') # All these names are predefined, for any other 3d segmentation we will need to create a different configuration all_imgs, all_ctrs, _, _ = read_preproc_imgs_and_ctrs_png( input_folder, folders_to_read=[current_folder], img_names=input_img_names, ctr_names=output_ctr_file_names) imgs_np = all_imgs[0] ctrs_lungs_np = all_ctrs[0][0].copy( ) # VERIFY THE ORDER IS THE SAME IN THE CONFIG FILE ctrs_lesion_np = all_ctrs[0][1].copy( ) # VERIFY THE ORDER IS THE SAME IN THE CONFIG FILE # If we want to visualize the input images # viz_obj.plot_imgs_and_ctrs_itk(img_np[0], ctrs_itk=ctrs_itk[0]) # ------------------- Making prediction ----------- print('\t Making prediction....') input_array = format_for_nn_classification(imgs_np) output_nn_all = model.predict(input_array, verbose=1) output_nn_np = output_nn_all[0, :, :, 0] output_nn_np[ctrs_lungs_np == 0] = 0 # Making the prediction 0 outside the lungs # For visualizing the output of the network # viz_obj.plot_img_and_ctrs_np_2d(output_nn_np, np_ctrs=[], file_name_prefix=id_folder) # ------------------- Postprocessing ----------- print('\t Postprocessing prediction....') threshold = .5 print(F'\t\t Threshold NN output to {threshold} ....') output_nn_np[ output_nn_np <= threshold] = 0 # Making the prediction 0 outside the lungs output_nn_np[ output_nn_np > threshold] = 1 # Making the prediction 0 outside the lungs if save_segmented_ctrs: print('\t Saving Prediction...') create_folder(join(output_folder, current_folder)) cv2.imwrite( join(output_folder, current_folder, output_ctr_file_names[0]), cv2.convertScaleAbs(output_nn_np, alpha=(255.0))) # Compute metrics print('\t Computing metrics....') for c_metric in metrics_params: # Here we can add more metrics if c_metric == ClassificationMetrics.DSC_2D: metric_value = numpy_dice(output_nn_np, ctrs_lesion_np) data.loc[current_folder][c_metric.value] = metric_value print(F'\t\t ----- DSC: {metric_value:.3f} -----') # Saving the results every 10 steps if id_folder % 10 == 0: save_metrics_images(data, metric_names=list(metrics_dict.values()), viz_obj=viz_obj) data.to_csv(join(output_folder, output_file_name)) if save_imgs: print('\t Plotting images....') plot_intermediate_results(current_folder, data_columns, img_np=imgs_np[0], gt_ctr_np=ctrs_lesion_np, nn_ctr_np=output_nn_np, data=data, viz_obj=viz_obj) except Exception as e: print( "---------------------------- Failed {} error: {} ----------------" .format(current_folder, e)) print(F'\t Done! Elapsed time {time.time()-t0:0.2f} seg') save_metrics_images(data, metric_names=list(metrics_dict.values()), viz_obj=viz_obj) data.to_csv(join(output_folder, output_file_name))