Bronchus Segmentation#

This example demonstrated how to use the bronchial tree segmentation algorithm used in:

W. Ghandourh, J. Dowling, P. Chlap et al., “Medical Dosimetry Assessing tumor centrality in lung stereotactic ablative body radiotherapy ( SABR ): the effects of variations in bronchial tree delineation and potential for automated methods,” vol. 46, pp. 94–101, 2021, doi:**`10.1016/j.meddos.2020.09.004 <https://doi.org/10.1016/j.meddos.2020.09.004>`__**.

Import Modules#

[1]:
try:
    import platipy
except:
    !pip install platipy
    import platipy

import SimpleITK as sitk

%matplotlib inline

from platipy.imaging.tests.data import get_lung_nifti
from platipy.imaging.projects.bronchus.run import run_bronchus_segmentation
from platipy.imaging import ImageVisualiser
from platipy.imaging.label.utils import get_com

Download Test Data#

This will download lung cancer patient CT scans, with contours of several structures. This only has to be done once - if it is ran again don’t worry, the same data will not be downloaded again!

[2]:
data_path = get_lung_nifti()

Load Test Image#

Read in the image we want to automatically segment

[3]:
test_pat_path = data_path.joinpath("LCTSC-Test-S1-201")
test_image = sitk.ReadImage(str(test_pat_path.joinpath("IMAGES/LCTSC_TEST_S1_201_0_CT_0.nii.gz")))

Run Auto-segmentation#

This will take some time, and will print updates along the way

[4]:
auto_structures = run_bronchus_segmentation(test_image)
Generating Lung Mask...
Generating Lung Mask... Done
-------------------------------
summary of lung intensities.  Mean: -689.7705964524534 sd: 164.05080332949413 median: -729.79296875
*Airway opening: [257, 196, 108]
*Voxel HU at opening: 1
--------------------------------------------
Extracting airways.  Iteration: 0
*Lung Mask HU: -750
*Slices from sup for airway opening: 3
No labels found in mask
--------------------------------------------
Extracting airways.  Iteration: 1
*Lung Mask HU: -775
*Slices from sup for airway opening: 3
No labels found in mask
--------------------------------------------
Extracting airways.  Iteration: 2
*Lung Mask HU: -800
*Slices from sup for airway opening: 3
No labels found in mask
--------------------------------------------
Extracting airways.  Iteration: 3
*Lung Mask HU: -825
*Slices from sup for airway opening: 3
No labels found in mask
--------------------------------------------
Extracting airways.  Iteration: 4
*Lung Mask HU: -850
*Slices from sup for airway opening: 3
No labels found in mask
--------------------------------------------
Extracting airways.  Iteration: 5
*Lung Mask HU: -900
*Slices from sup for airway opening: 3
No labels found in mask
--------------------------------------------
Extracting airways.  Iteration: 6
*Lung Mask HU: -700
*Slices from sup for airway opening: 3
No labels found in mask
--------------------------------------------
Extracting airways.  Iteration: 7
*Lung Mask HU: -950
*Slices from sup for airway opening: 3
No labels found in mask
--------------------------------------------
Extracting airways.  Iteration: 8
*Lung Mask HU: -650
*Slices from sup for airway opening: 3
No labels found in mask
*Airway opening: [259, 201, 102]
*Voxel HU at opening: 1
--------------------------------------------
Extracting airways.  Iteration: 9
*Lung Mask HU: -750
*Slices from sup for airway opening: 10
 Airway Mask size passed: 90033
 Roundness: 0.518584427381907
 Elongation: 3.314440100646848
--------------------------------------------
Extracting airways.  Iteration: 10
*Lung Mask HU: -775
*Slices from sup for airway opening: 10
 Airway Mask size passed: 87987
 Roundness: 0.5206611338884475
 Elongation: 3.3711273033085107
--------------------------------------------
Extracting airways.  Iteration: 11
*Lung Mask HU: -800
*Slices from sup for airway opening: 10
 Airway Mask size passed: 86620
 Roundness: 0.5190044294760688
 Elongation: 3.3937056078327137
--------------------------------------------
Extracting airways.  Iteration: 12
*Lung Mask HU: -825
*Slices from sup for airway opening: 10
 Airway Mask size passed: 84374
 Roundness: 0.5232948774582152
 Elongation: 3.4940802535337427
--------------------------------------------
Extracting airways.  Iteration: 13
*Lung Mask HU: -850
*Slices from sup for airway opening: 10
 Airway Mask size passed: 81954
 Roundness: 0.5269199707802875
 Elongation: 3.5721722733604353
--------------------------------------------
Extracting airways.  Iteration: 14
*Lung Mask HU: -900
*Slices from sup for airway opening: 10
 Airway Mask size passed: 76060
 Roundness: 0.537612318167935
 Elongation: 3.944671084976228
--------------------------------------------
Extracting airways.  Iteration: 15
*Lung Mask HU: -700
*Slices from sup for airway opening: 10
 Airway Mask size failed (> 150000): 1659413
 Roundness: 0.5537332413709152
 Elongation: 1.2750023134566382
--------------------------------------------
Extracting airways.  Iteration: 16
*Lung Mask HU: -950
*Slices from sup for airway opening: 10
 Airway Mask size passed: 59652
 Roundness: 0.6014459998871523
 Elongation: 6.3515641371955995
--------------------------------------------
Extracting airways.  Iteration: 17
*Lung Mask HU: -650
*Slices from sup for airway opening: 10
 Airway Mask size failed (> 150000): 2933049
 Roundness: 0.4764602838161556
 Elongation: 1.4176602059683505
Selected Lung Mask HU: -750
 Cropping from slice: 63 + 13 slices

Save segmentations#

Optionally write the automatic segmentations to disk

[5]:
output_directory = test_pat_path.joinpath("SEGMENTATIONS")
output_directory.mkdir(exist_ok=True)

for struct_name in list(auto_structures.keys()):
    sitk.WriteImage(auto_structures[struct_name], str(output_directory.joinpath(f"{struct_name}.nii.gz")))

print(f"Segmentations saved to: {output_directory}")


Segmentations saved to: data/nifti/lung/LCTSC-Test-S1-201/SEGMENTATIONS

Visualise Segmentations#

Next, we can generate a nice figure to check what the segmentation looks like

The first step here is to convert SimpleITK images to NumPy arrays

[6]:
vis = ImageVisualiser(test_image, cut=get_com(auto_structures["Auto_Bronchus"]))

vis.add_contour({struct: auto_structures[struct] for struct in auto_structures.keys()})

fig = vis.show()
../_images/_examples_bronchus_segmentation_11_0.png
[ ]: