def test_slice_exclusion_rules_none( model_config: SegmentationModelBase) -> None: """ Test `apply_slice_exclusion_rules` if no rule is provided """ # create a copy as apply_slice_exclusion_rules modifies in place segmentation_copy = np.copy(segmentation_single_overlap) image_util.apply_slice_exclusion_rules(model_config, segmentation_copy) assert np.array_equal(segmentation_copy, segmentation_single_overlap)
def test_slice_exclusion_rules_class_not_present( model_config: SegmentationModelBase) -> None: """ Test `apply_slice_exclusion_rules` if the class to exclude is not present """ # create a copy as apply_slice_exclusion_rules modifies in place segmentation_copy = np.copy(segmentation_class_not_present) image_util.apply_slice_exclusion_rules(model_config, segmentation_copy) assert np.array_equal(segmentation_copy, segmentation_class_not_present)
def test_slice_exclusion_rules_no_overlap( model_config: SegmentationModelBase) -> None: """ Test `apply_slice_exclusion_rules` in the no overlap case """ # create a copy as apply_slice_exclusion_rules modifies in place segmentation_copy = np.copy(segmentation_no_overlap) image_util.apply_slice_exclusion_rules(model_config, segmentation_copy) assert np.array_equal(segmentation_copy, segmentation_no_overlap)
def test_slice_exclusion_rules_multiple_overlap( model_config: SegmentationModelBase, expected_segmentation: np.ndarray) -> None: """ Test `apply_slice_exclusion_rules` in the multiple overlap case """ # create a copy as apply_slice_exclusion_rules modifies in place segmentation_copy = np.copy(segmentation_multiple_overlap) image_util.apply_slice_exclusion_rules(model_config, segmentation_copy) assert np.array_equal(segmentation_copy, expected_segmentation)
def post_process( self, results: InferencePipeline.Result) -> InferencePipeline.Result: """ Perform connected component analysis to update segmentation with largest connected component based on the configurations :param results: inference results to post-process :return: post-processed version of results """ if self.model_config.posterior_smoothing_mm: posteriors = gaussian_smooth_posteriors( posteriors=results.posteriors, kernel_size_mm=self.model_config.posterior_smoothing_mm, voxel_spacing_mm=results.voxel_spacing_mm) results = InferencePipeline.Result( epoch=results.epoch, patient_id=results.patient_id, posteriors=posteriors, segmentation=posteriors_to_segmentation(posteriors), voxel_spacing_mm=results.voxel_spacing_mm) if self.model_config.summed_probability_rules and not self.model_config.disable_extra_postprocessing: assert isinstance(self.model_config, SegmentationModelBase) results = results.with_new_segmentation( image_util.apply_summed_probability_rules( self.model_config, results.posteriors, results.segmentation)) if self.model_config.largest_connected_component_foreground_classes is not None: # get indices for classes to restrict restrict_class_indices_and_thresholds = [] for name, idx in self.model_config.class_and_index_with_background( ).items(): for name2, threshold in self.model_config.largest_connected_component_foreground_classes: if name2 == name: restrict_class_indices_and_thresholds.append( (idx, threshold)) results = results.with_new_segmentation( image_util.extract_largest_foreground_connected_component( multi_label_array=results.segmentation, # mypy gets confused below because List is invariant. Sequence is covariant # but does not allow "append". restrictions=restrict_class_indices_and_thresholds) ) # type: ignore if self.model_config.slice_exclusion_rules and not self.model_config.disable_extra_postprocessing: results = results.with_new_segmentation( image_util.apply_slice_exclusion_rules(self.model_config, results.segmentation)) return results