Exemplo n.º 1
0
def cardiac_service(data_objects, working_dir, settings):
    """
    Implements the platipy framework to provide cardiac atlas based segmentation.
    """

    logger.info("Running Cardiac Segmentation")
    logger.info("Using settings: " + str(settings))

    output_objects = []
    for data_object in data_objects:
        logger.info("Running on data object: " + data_object.path)

        # Read the image series
        load_path = data_object.path
        if data_object.type == "DICOM":
            load_path = sitk.ImageSeriesReader().GetGDCMSeriesFileNames(
                data_object.path)

        img = sitk.ReadImage(load_path)

        results = run_cardiac_segmentation(img, settings)

        # Save resulting masks and add to output for service
        for output in results.keys():

            mask_file = os.path.join(working_dir, "{0}.nii.gz".format(output))
            sitk.WriteImage(results[output], mask_file)

            output_data_object = DataObject(type="FILE",
                                            path=mask_file,
                                            parent=data_object)
            output_objects.append(output_data_object)

        # If the input was a DICOM, then we can use it to generate an output RTStruct
        # if data_object.type == 'DICOM':

        #     dicom_file = load_path[0]
        #     logger.info('Will write Dicom using file: {0}'.format(dicom_file))
        #     masks = {settings['outputContourName']: mask_file}

        #     # Use the image series UID for the file of the RTStruct
        #     suid = pydicom.dcmread(dicom_file).SeriesInstanceUID
        #     output_file = os.path.join(working_dir, 'RS.{0}.dcm'.format(suid))

        #     # Use the convert nifti function to generate RTStruct from nifti masks
        #     convert_nifti(dicom_file, masks, output_file)

        #     # Create the Data Object for the RTStruct and add it to the list
        #     do = DataObject(type='DICOM', path=output_file, parent=d)
        #     output_objects.append(do)

        #     logger.info('RTStruct generated')

    return output_objects
Exemplo n.º 2
0
def cardiac_structure_guided_service(data_objects, working_dir, settings):
    """Runs the structure guided cardiac segmentation service"""

    logger.info("Running Structure Guided Cardiac Segmentation")
    logger.info("Using settings: " + str(settings))

    output_objects = []
    for data_object in data_objects:
        logger.info("Running on data object: " + data_object.path)

        # Read the image series
        load_path = data_object.path
        if data_object.type == "DICOM":
            load_path = sitk.ImageSeriesReader().GetGDCMSeriesFileNames(
                data_object.path)

        img = sitk.ReadImage(load_path)

        # Load the WHOLEHEART contour (child of Image)
        if len(data_object.children) == 0:
            logger.error(
                "Wholeheart structure needed for structure guided cardiac "
                f"segmentation, skipping {data_object.id}")
            continue

        wholeheart = sitk.ReadImage(data_object.children[0].path)

        results, _ = run_cardiac_segmentation(img, wholeheart, settings)

        # Save resulting masks and add to output for service
        for output in results:

            mask_file = os.path.join(working_dir, "{0}.nii.gz".format(output))
            sitk.WriteImage(results[output], mask_file)

            output_data_object = DataObject(type="FILE",
                                            path=mask_file,
                                            parent=data_object)
            output_objects.append(output_data_object)

    return output_objects
Exemplo n.º 3
0
def test_cardiac_service(cardiac_data):
    """An end-to-end test to check that the cardiac service is running as expected"""

    with tempfile.TemporaryDirectory() as working_dir:

        working_path = Path(working_dir)

        # Save off data
        cases = list(cardiac_data.keys())
        for case in cardiac_data:

            ct_path = working_path.joinpath(f"Case_{case}", "Images",
                                            f"Case_{case}_CROP.nii.gz")
            ct_path.parent.mkdir(parents=True, exist_ok=True)
            mask_path = working_path.joinpath(
                f"Case_{case}", "Structures",
                f"Case_{case}_WHOLEHEART_CROP.nii.gz")
            mask_path.parent.mkdir(parents=True, exist_ok=True)

            sitk.WriteImage(cardiac_data[case]["CT"], str(ct_path))
            sitk.WriteImage(cardiac_data[case]["WHOLEHEART"], str(mask_path))

        # Prepare algorithm settings
        test_settings = CARDIAC_SETTINGS_DEFAULTS
        test_settings["atlas_settings"]["atlas_id_list"] = cases[:-1]
        test_settings["atlas_settings"]["atlas_path"] = str(working_path)
        test_settings["atlas_settings"]["atlas_structure_list"] = [
            "WHOLEHEART"
        ]
        test_settings["atlas_settings"]["auto_crop_atlas"] = False
        test_settings["deformable_registration_settings"][
            "resolution_staging"] = [8, 4, 2]
        test_settings["deformable_registration_settings"][
            "iteration_staging"] = [5, 5, 5]
        test_settings["deformable_registration_settings"][
            "smoothing_sigmas"] = [0, 0, 0]
        test_settings["deformable_registration_settings"][
            "default_value"] = -1000
        test_settings["iar_settings"]["reference_structure"] = None
        test_settings["label_fusion_settings"]["optimal_threshold"] = {
            "WHOLEHEART": 0.5
        }
        test_settings["vessel_spline_settings"]["vessel_name_list"] = []
        test_settings["vessel_spline_settings"]["vessel_radius_mm_dict"] = {}
        test_settings["vessel_spline_settings"]["scan_direction_dict"] = {}
        test_settings["vessel_spline_settings"][
            "stop_condition_type_dict"] = {}
        test_settings["vessel_spline_settings"][
            "stop_condition_value_dict"] = {}
        test_settings["postprocessing_settings"]["run_postprocessing"] = False
        test_settings["geometric_segmentation_settings"][
            "run_geometric_algorithms"] = False

        test_settings["rigid_settings"] = {
            "shrink_factors": [2, 1],
            "smooth_sigmas": [0, 0],
            "sampling_rate": 0.75,
            "default_value": -1024,
            "number_of_iterations": 5,
            "final_interp": sitk.sitkBSpline,
            "metric": "mean_squares",
            "optimiser": "gradient_descent_line_search",
        }

        # Run the service function.
        infer_case = cases[-1]

        output, _ = run_cardiac_segmentation(cardiac_data[infer_case]["CT"],
                                             settings=test_settings)

        # Check we have a WHOLEHEART structure
        assert "WHOLEHEART" in output

        # Check the result is similar to the GT

        label_overlap_filter = sitk.LabelOverlapMeasuresImageFilter()
        auto_mask = output["WHOLEHEART"]
        gt_mask = sitk.Cast(cardiac_data[infer_case]["WHOLEHEART"],
                            auto_mask.GetPixelID())
        label_overlap_filter.Execute(auto_mask, gt_mask)
        assert label_overlap_filter.GetDiceCoefficient() > 0.99