Esempio n. 1
0
def load_train_and_test_data_channels(
        patient_ids: List[int],
        normalization_fn: PhotometricNormalization) -> List[Sample]:
    if np.any(np.asarray(patient_ids) <= 0):
        raise ValueError("data_items must be >= 0")

    file_name = lambda k, y: full_ml_test_data_path("train_and_test_data"
                                                    ) / f"id{k}_{y}.nii.gz"

    get_sample = lambda z: io_util.load_images_from_dataset_source(
        dataset_source=PatientDatasetSource(
            metadata=PatientMetadata(patient_id=z),
            image_channels=[file_name(z, c) for c in TEST_CHANNEL_IDS],
            mask_channel=file_name(z, TEST_MASK_ID),
            ground_truth_channels=[file_name(z, TEST_GT_ID)]))

    samples = []
    for x in patient_ids:
        sample = get_sample(x)
        sample = Sample(image=normalization_fn.transform(
            sample.image, sample.mask),
                        mask=sample.mask,
                        labels=sample.labels,
                        metadata=sample.metadata)
        samples.append(sample)

    return samples
Esempio n. 2
0
def run_inference(images_with_header: List[ImageWithHeader],
                  inference_pipeline: FullImageInferencePipelineBase,
                  config: SegmentationModelBase) -> np.ndarray:
    """
    Runs inference on a list of channels and given a config and inference pipeline
    :param images_with_header:
    :param inference_pipeline:
    :param config:
    :return: segmentation
    """
    # Check the image has the correct spacing
    if config.dataset_expected_spacing_xyz:
        for image_with_header in images_with_header:
            spacing_xyz = reverse_tuple_float3(
                image_with_header.header.spacing)
            if not is_spacing_valid(spacing_xyz,
                                    config.dataset_expected_spacing_xyz):
                raise ValueError(
                    f'Input image has spacing {spacing_xyz} '
                    f'but expected {config.dataset_expected_spacing_xyz}')
    # Photo norm
    photo_norm = PhotometricNormalization(config_args=config)
    photo_norm_images = [
        photo_norm.transform(image_with_header.image)
        for image_with_header in images_with_header
    ]
    segmentation = inference_pipeline.predict_and_post_process_whole_image(
        image_channels=np.array(photo_norm_images),
        voxel_spacing_mm=images_with_header[0].header.spacing).segmentation

    return segmentation
Esempio n. 3
0
def plot_normalization_result(loaded_images: Sample,
                              normalizer: PhotometricNormalization,
                              result_folder: Path,
                              result_prefix: str = "",
                              image_range: Optional[TupleFloat2] = None,
                              channel_index: int = 0,
                              class_index: int = 1,
                              contour_file_suffix: str = "") -> List[Path]:
    """
    Creates two PNG plots that summarize the result of photometric normalization of the first channel in the
    sample image.
    The first plot contains pixel value histograms before and after photometric normalization.
    The second plot contains the normalized image, overlayed with contours for the foreground pixels,
    at the slice where the foreground has most pixels.
    :param loaded_images: An instance of Sample with the image and the labels. The first channel of the image will
    be plotted.
    :param image_range: The image value range that will be mapped to the color map. If None, the full image range
    will be mapped to the colormap.
    :param normalizer: The photometric normalization that should be applied.
    :param result_folder: The folder into which the resulting PNG files should be written.
    :param result_prefix: The prefix for all output filenames.
    :param channel_index: Compute normalization results for this channel.
    :param class_index: When plotting image/contour overlays, use this class.
    :param contour_file_suffix: Use this suffix for the file name that contains the image/contour overlay.
    :return: The paths of the two PNG files that the function writes.
    """
    # Labels are encoded with background and a single foreground class. We need the
    # slice with largest number of foreground voxels
    ground_truth = loaded_images.labels[class_index, ...]
    largest_gt_slice = get_largest_z_slice(ground_truth)
    first_channel = loaded_images.image[channel_index, ...]
    filename_stem = f"{result_prefix}{loaded_images.patient_id:03d}_slice_{largest_gt_slice:03d}"
    normalized_image = normalizer.transform(loaded_images.image,
                                            loaded_images.mask)[channel_index,
                                                                ...]

    before_after_plot = \
        plot_before_after_statistics(first_channel,
                                     normalized_image,
                                     loaded_images.mask,
                                     z_slice=largest_gt_slice,
                                     normalizer_status_message=normalizer.status_of_most_recent_call,
                                     plot_file_name=result_folder / filename_stem)
    image_contour_plot = \
        plot_image_and_label_contour(image=normalized_image[largest_gt_slice, ...],
                                     labels=ground_truth[largest_gt_slice, ...],
                                     contour_arguments={'colors': 'r'},
                                     image_range=image_range,
                                     plot_file_name=result_folder / f"{filename_stem}_contour{contour_file_suffix}")
    return [before_after_plot, image_contour_plot]