def __compute_subcortical_structures_location(self, volume, spacing, category=None, reference='BCB'): distances = {} overlaps = {} distances_columns = [] overlaps_columns = [] tract_cutoff = 0.5 if reference == 'BrainLab': tract_cutoff = 0.25 tracts_dict = ResourcesConfiguration.getInstance().subcortical_structures['MNI'][reference] for i, tfn in enumerate(tracts_dict.keys()): reg_tract_ni = nib.load(tracts_dict[tfn]) reg_tract = reg_tract_ni.get_data()[:] reg_tract[reg_tract < tract_cutoff] = 0 reg_tract[reg_tract >= tract_cutoff] = 1 overlap_volume = np.logical_and(reg_tract, volume).astype('uint8') distances_columns.append('distance_' + tfn.split('.')[0][:-4] + '_' + category) overlaps_columns.append('overlap_' + tfn.split('.')[0][:-4] + '_' + category) if np.count_nonzero(overlap_volume) != 0: distances[tfn] = -1. overlaps[tfn] = (np.count_nonzero(overlap_volume) / np.count_nonzero(volume)) * 100. else: dist = -1. if np.count_nonzero(reg_tract) > 0: dist = hd95(volume, reg_tract, voxelspacing=reg_tract_ni.header.get_zooms(), connectivity=1) distances[tfn] = dist overlaps[tfn] = 0. self.diagnosis_parameters.statistics[category]['Overall'].mni_space_subcortical_structures_overlap[reference] = overlaps self.diagnosis_parameters.statistics[category]['Overall'].mni_space_subcortical_structures_distance[reference] = distances
def __init__(self, input_filename, input_segmentation, preprocessing_scheme): self.input_filename = input_filename self.input_segmentation = input_segmentation self.preprocessing_scheme = preprocessing_scheme self.output_path = ResourcesConfiguration.getInstance().output_folder # Working with Gd-enhanced T1-weighted MRI volume as input for now. self.atlas_brain_filepath = ResourcesConfiguration.getInstance().mni_atlas_filepath_T1 self.from_slicer = ResourcesConfiguration.getInstance().from_slicer self.registration_runner = ANTsRegistration() self.diagnosis_parameters = NeuroDiagnosisParameters() self.output_report_filepath = os.path.join(self.output_path, 'report.txt') if os.path.exists(self.output_report_filepath): os.remove(self.output_report_filepath) self.tumor_multifocal = None
def __compute_resection_features(self, volume, category=None): resection_probability_map_filepath = None if self.diagnosis_parameters.statistics[category]['Overall'].left_laterality_percentage >= 50.: # Tumor in the left hemi-sphere resection_probability_map_filepath = ResourcesConfiguration.getInstance().mni_resection_maps['Probability']['Left'] else: resection_probability_map_filepath = ResourcesConfiguration.getInstance().mni_resection_maps['Probability']['Right'] resection_probability_map_ni = nib.load(resection_probability_map_filepath) resection_probability_map = resection_probability_map_ni.get_data()[:] resection_probability_map = np.nan_to_num(resection_probability_map) tumor_voxels_count = np.count_nonzero(volume) total_resectability = np.sum(resection_probability_map[volume != 0]) resectable_volume = total_resectability * 1e-3 residual_tumor_volume = (tumor_voxels_count * 1e-3) - resectable_volume avg_resectability = total_resectability / tumor_voxels_count self.diagnosis_parameters.statistics[category]['Overall'].mni_space_expected_residual_tumor_volume = residual_tumor_volume self.diagnosis_parameters.statistics[category]['Overall'].mni_space_expected_resectable_tumor_volume = resectable_volume self.diagnosis_parameters.statistics[category]['Overall'].mni_space_resectability_index = avg_resectability
def diagnose_main(input_volume_filename, input_segmentation_filename, output_folder, preprocessing_scheme='P2', gpu_id='-1'): env = ResourcesConfiguration.getInstance() env.set_environment(output_dir=output_folder) os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID" os.environ["CUDA_VISIBLE_DEVICES"] = gpu_id diagnose(input_filename=input_volume_filename, input_segmentation=input_segmentation_filename, preprocessing_scheme=preprocessing_scheme)
def __compute_lateralisation(self, volume, category=None): brain_lateralisation_mask_ni = load_nifti_volume(ResourcesConfiguration.getInstance().mni_atlas_lateralisation_mask_filepath) brain_lateralisation_mask = brain_lateralisation_mask_ni.get_data()[:] right_side_percentage = np.count_nonzero((brain_lateralisation_mask == 1) & (volume != 0)) / np.count_nonzero( (volume != 0)) left_side_percentage = np.count_nonzero((brain_lateralisation_mask == 2) & (volume != 0)) / np.count_nonzero( (volume != 0)) left_laterality_percentage = np.round(left_side_percentage * 100., 2) right_laterality_percentage = np.round(right_side_percentage * 100., 2) midline_crossing = True if max(left_laterality_percentage, right_laterality_percentage) < 100. else False self.diagnosis_parameters.statistics[category]['Overall'].left_laterality_percentage = left_side_percentage self.diagnosis_parameters.statistics[category]['Overall'].right_laterality_percentage = right_side_percentage self.diagnosis_parameters.statistics[category]['Overall'].laterality_midline_crossing = midline_crossing
def run_diagnosis(self): if not os.path.exists(self.input_image_filepath) or not os.path.exists( self.output_folderpath): self.standardOutputWritten( 'Process could not be started - The 1st and 2nd above-fields must be filled in.\n' ) return self.run_button.setEnabled(False) self.prompt_lineedit.clear() self.main_display_tabwidget.setCurrentIndex(1) QApplication.processEvents( ) # to immidiently update GUI after button is clicked self.seg_preprocessing_scheme = 'P1' if self.settings_seg_preproc_menu_p1_action.isChecked( ) else 'P2' try: start_time = time.time() print('Initialize - Begin (Step 0/6)') from diagnosis.main import diagnose_main print('Initialize - End (Step 0/6)') print('Step runtime: {} seconds.'.format( np.round(time.time() - start_time, 3)) + "\n") diagnose_main( input_volume_filename=self.input_image_filepath, input_segmentation_filename=self.input_annotation_filepath, output_folder=self.output_folderpath, preprocessing_scheme=self.seg_preprocessing_scheme) except Exception as e: print('{}'.format(traceback.format_exc())) self.run_button.setEnabled(True) self.standardOutputWritten( 'Process could not be completed - Issue arose.\n') QApplication.processEvents() return self.run_button.setEnabled(True) results_filepath = os.path.join( ResourcesConfiguration.getInstance().output_folder, 'report.txt') self.results_textedit.setPlainText(open(results_filepath, 'r').read()) self.main_display_tabwidget.setCurrentIndex(2)
def __compute_cortical_structures_location(self, volume, category=None, reference='MNI'): regions_data = ResourcesConfiguration.getInstance().cortical_structures['MNI'][reference] region_mask_ni = nib.load(regions_data['Mask']) region_mask = region_mask_ni.get_data() lobes_description = pd.read_csv(regions_data['Description']) total_lobes_labels = np.unique(region_mask)[1:] # Removing the background label with value 0. overlap_per_lobe = {} for li in total_lobes_labels: overlap = volume[region_mask == li] ratio_in_lobe = np.count_nonzero(overlap) / np.count_nonzero(volume) overlap = np.round(ratio_in_lobe * 100., 2) region_name = '' if reference == 'MNI': region_name = reference + '_' + lobes_description.loc[lobes_description['Label'] == li]['Region'].values[0] + '_' + lobes_description.loc[lobes_description['Label'] == li]['Laterality'].values[0] + '_' + category elif reference == 'Harvard-Oxford': region_name = reference + '_' + lobes_description.loc[lobes_description['Label'] == li]['Region'].values[0] + '_' + category else: region_name = reference + '_' + lobes_description.loc[lobes_description['Label'] == li]['Region'].values[0] + '_' + category overlap_per_lobe[region_name] = overlap self.diagnosis_parameters.statistics[category]['Overall'].mni_space_cortical_structures_overlap[reference] = overlap_per_lobe
def perform_brain_masking(image_filepath, mask_filepath): """ Set to 0 any voxel that does not belong to the brain mask. :param image_filepath: path to the main MRI volume :param mask_filepath: path to the brain segmentation mask :return: masked_image_filepath """ image_ni = load_nifti_volume(image_filepath) brain_mask_ni = load_nifti_volume(mask_filepath) image = image_ni.get_data()[:] brain_mask = brain_mask_ni.get_data()[:] image[brain_mask == 0] = 0 tmp_folder = os.path.join( ResourcesConfiguration.getInstance().output_folder, 'tmp') os.makedirs(tmp_folder, exist_ok=True) masked_input_filepath = os.path.join( tmp_folder, os.path.basename(image_filepath).split('.')[0] + '_masked.nii.gz') nib.save(nib.Nifti1Image(image, affine=image_ni.affine), masked_input_filepath) return masked_input_filepath
def perform_brain_extraction(image_filepath): brain_predictions_file = perform_custom_brain_extraction( image_filepath, ResourcesConfiguration.getInstance().output_folder) return brain_predictions_file
def run(self): tmp_timer = 0 start_time = time.time() self.input_filename = adjust_input_volume_for_nifti(self.input_filename, self.output_path) # Generating the brain mask for the input file print('Brain extraction - Begin (Step 1/6)') brain_mask_filepath = perform_brain_extraction(image_filepath=self.input_filename) print('Brain extraction - End (Step 1/6)') print('Step runtime: {} seconds.'.format(round(time.time() - start_time - tmp_timer, 3)) + "\n") tmp_timer = time.time() # Generating brain-masked fixed and moving images print('Registration preprocessing - Begin (Step 2/6)') input_masked_filepath = perform_brain_masking(image_filepath=self.input_filename, mask_filepath=brain_mask_filepath) atlas_masked_filepath = perform_brain_masking(image_filepath=self.atlas_brain_filepath, mask_filepath=ResourcesConfiguration.getInstance().mni_atlas_brain_mask_filepath) print('Registration preprocessing - End (Step 2/6)') print('Step runtime: {} seconds.'.format(round(time.time() - tmp_timer, 3)) + "\n") tmp_timer = time.time() # Performing registration print('Registration - Begin (Step 3/6)') self.registration_runner.compute_registration(fixed=atlas_masked_filepath, moving=input_masked_filepath, registration_method='sq') print('Registration - End (Step 3/6)') print('Step runtime: {} seconds.'.format(round(time.time() - tmp_timer, 3)) + "\n") tmp_timer = time.time() # Performing tumor segmentation if not os.path.exists(self.input_segmentation): print('Tumor segmentation - Begin (Step 4/6)') self.input_segmentation = self.__perform_tumor_segmentation(brain_mask_filepath) print('Tumor segmentation - End (Step 4/6)') print('Step runtime: {} seconds.'.format(round(time.time() - tmp_timer, 3)) + "\n") tmp_timer = time.time() print('Apply registration - Begin (Step 5/6)') # Registering the tumor to the atlas self.registration_runner.apply_registration_transform(moving=self.input_segmentation, fixed=self.atlas_brain_filepath, interpolation='nearestNeighbor') # Dumping the different atlas labels self.registration_runner.dump_mni_atlas_labels() # Registering the brain lobes to the patient's space self.registration_runner.apply_registration_inverse_transform(moving=ResourcesConfiguration.getInstance().cortical_structures['MNI']['MNI']['Mask'], fixed=self.input_filename, interpolation='nearestNeighbor', label='MNI') self.registration_runner.apply_registration_inverse_transform(moving=ResourcesConfiguration.getInstance().cortical_structures['MNI']['Schaefer7']['Mask'], fixed=self.input_filename, interpolation='nearestNeighbor', label='Schaefer7') self.registration_runner.apply_registration_inverse_transform(moving=ResourcesConfiguration.getInstance().cortical_structures['MNI']['Schaefer17']['Mask'], fixed=self.input_filename, interpolation='nearestNeighbor', label='Schaefer17') self.registration_runner.apply_registration_inverse_transform(moving=ResourcesConfiguration.getInstance().cortical_structures['MNI']['Harvard-Oxford']['Mask'], fixed=self.input_filename, interpolation='nearestNeighbor', label='Harvard-Oxford') print('Apply registration - End (Step 5/6)') print('Step runtime: {} seconds.'.format(round(time.time() - tmp_timer, 3)) + "\n") tmp_timer = time.time() # Computing tumor location and statistics print('Generate report - Begin (Step 6/6)') self.__compute_statistics() self.diagnosis_parameters.to_txt(self.output_report_filepath) self.diagnosis_parameters.to_csv(self.output_report_filepath[:-4] + '.csv') print('Generate report - End (Step 6/6)') print('Step runtime: {} seconds.'.format(time.time() - tmp_timer) + "\n") print('Total processing time: {} seconds.'.format(round(time.time() - start_time, 3))) print('--------------------------------') # Cleaning the temporary files tmp_folder = os.path.join(self.output_path, 'tmp') shutil.rmtree(tmp_folder)