Cardiac LV 17-segment model#

This notebook demonstrates how to use the geometric algorithm to automatically segment the 17-segment Left Ventricle myocardium model defined by the AHA: https://www.ahajournals.org/doi/pdf/10.1161/hc0402.102975

[1]:
try:
    import platipy
except:
    # Install platipy with the 'cardiac' extra since that contains some extra libraries we need.
    !pip install platipy[cardiac]
    import platipy

from pathlib import Path
import matplotlib.pyplot as plt

import SimpleITK as sitk
import numpy as np

from platipy.imaging import ImageVisualiser
from platipy.imaging.label.utils import get_com
from platipy.imaging.utils.io import write_nrrd_structure_set
from platipy.imaging.utils.ventricle import generate_left_ventricle_segments

from platipy.imaging.projects.cardiac.run import install_open_atlas

Download Sample Data#

PlatiPy’s cardiac segmentation tool uses an atlas as part of that segmentation. For this example we download that atlas to demonstrate the 17-segment auto-segmentation.

[2]:
atlas_path = Path("data/atlas")

if not atlas_path.exists():
    install_open_atlas(atlas_path)

Read Data#

We read in some of the data we downloaded. The required structures are: Left Ventricle, Left Atrium, Right Ventricle and the whole heart. The CT image is loaded but is only needed for visualisation purposes.

[3]:
patid = "LUNG1-002"

image_path = atlas_path.joinpath(patid, "IMAGES", "CT.nii.gz")
image = sitk.ReadImage(str(image_path)) # onyl used for visualisation

contours = {}

lv_path = atlas_path.joinpath(patid, "STRUCTURES", "Ventricle_L.nii.gz")
contours["Ventricle_L"] = sitk.ReadImage(str(lv_path))

la_path = atlas_path.joinpath(patid, "STRUCTURES", "Atrium_L.nii.gz")
contours["Atrium_L"] = sitk.ReadImage(str(la_path))

rv_path = atlas_path.joinpath(patid, "STRUCTURES", "Ventricle_R.nii.gz")
contours["Ventricle_R"] = sitk.ReadImage(str(rv_path))

heart_path = atlas_path.joinpath(patid, "STRUCTURES", "Heart.nii.gz")
contours["Heart"] = sitk.ReadImage(str(heart_path))

Generate 17 LV Segments#

The generate_left_ventricle_segments function is run which returns a dictionary where the key is the segment ID (i.e. Ventricle_L_Segment1, Ventricle_L_Segment2, …) and the value is the segment auto-contour (as a SimpleITK.Image).

See the documentation for additional options you can specify.

[4]:
lv_segments = generate_left_ventricle_segments(contours, verbose=True)
Beginning LV segmentation algorithm.
Module 1: Cropping and initial alignment.
  Images cropped. Volume reduction: 1.000
  Alignment computed.
    Cardiac axis:     [-0.51538678 -0.8567381   0.01939842]
    Rotation axis:    [-0.8567381  -0.01939842  0.        ]
    Rotation angle:   1.029337402528849
    Rotation centre:  (53.54705757769439, -33.01797661455572, -33.16549199516518)
Module 2: LV orientation alignment.
  Optimiser tolerance (degrees) = 1
  Beginning alignment process
    N:                1
    LV apex:          [  92.12689862  -29.34676304 -100.3999939 ]
    MV COM:           [ 38.60792831 -34.98956324 -14.50176381]
    LV axis:          [ 53.51897031   5.6428002  -85.89823009]
    Rotation axis:    [  5.6428002  -53.51897031   0.        ]
    Rotation centre:  [ 65.36741347 -32.16816314 -57.45087885]
    Rotation angle:   0.5596804399185753
    N:                2
    LV apex:          [  74.15895319  -25.37873232 -112.3999939 ]
    MV COM:           [ 65.39114152 -32.17008994  -6.80293245]
    LV axis:          [   8.76781167    6.79135762 -105.59706144]
    Rotation axis:    [ 6.79135762 -8.76781167  0.        ]
    Rotation centre:  [ 69.77504736 -28.77441113 -59.60146318]
    Rotation angle:   0.10464206469597664
    N:                3
    LV apex:          [  71.08173551  -27.39587178 -112.3999939 ]
    MV COM:           [ 69.79644172 -28.76506973  -6.63819614]
    LV axis:          [   1.28529379    1.36919795 -105.76179775]
    Rotation axis:    [ 1.36919795 -1.28529379  0.        ]
    Rotation centre:  [ 70.43908861 -28.08047075 -59.51909502]
    Rotation angle:   0.01775451288291543
    N:                4
    LV apex:          [  70.10473551  -28.37287177 -112.3999939 ]
    MV COM:           [ 70.77344171 -27.78806973  -6.63819614]
    LV axis:          [  -0.6687062    -0.58480204 -105.76179775]
    Rotation axis:    [-0.58480204  0.6687062   0.        ]
    Rotation centre:  [ 70.43908861 -28.08047075 -59.51909502]
    Rotation angle:   0.008399315304762168
Module 3: Myocardium generation.
  Apex (long axis) slice:       9
  Apical section extent slice:  19
  Mid section extent slice:     29
  Basal section extent slice:   40
    DeltaCut (DC):  10
    Extent:         31
Module 4: Segment generation.
  RV basal slices:  [29 30 31 32 33]
  RV insertion angle (basal section):  1.5480729659532555
 Apical LV-RV COM angle:  3.04084204317622
  Computing apical segments
  Computing mid segments
  Computing basal segments
  Module 5: Re-orientation.
Complete!

Visualise Segments#

Here we generate a figure using the CT loaded to visualise the results.

[5]:
vis = ImageVisualiser(image, cut=get_com(contours["Ventricle_L"]), figure_size_in=6)
vis.add_contour(contours)
vis.add_contour(lv_segments)
vis.set_limits_from_label(contours["Heart"], expansion=20)
fig = vis.show()
../_images/_examples_left_ventricle_17_segments_9_0.png

Optionally save a NRRD file containing all LV segments. This is useful for loading into Slicer (for example).

[6]:
write_nrrd_structure_set(lv_segments, atlas_path.joinpath(patid, "STRUCTURES", "LV_Segments.nrrd"), colormap=plt.cm.rainbow)
[ ]: