pyplati / platipy

Processing Library and Analysis Toolkit for Medical Imaging in Python
https://pyplati.github.io/platipy/
Apache License 2.0
111 stars 27 forks source link

Adding multiple DICOM structure files to a single CT visualisation #121

Closed smallkev closed 1 month ago

smallkev commented 2 years ago

Good afternoon,

I am trying to add 2 different contours in same CT image. I have 2 different RTstructure files (.dcm) which were converted to nifti using convert_rtstruct. I can successfully load and visualise only 1 set of contours in a image while I was not able to add other set of contours.

This is the minimal reproducible example of code used (Python):


import platipy
import pydicom
import numpy as np
import SimpleITK as sitk
import matplotlib.pyplot as plt
import sys
import glob
import pathlib

from platipy.imaging import ImageVisualiser
from platipy.dicom.io.rtstruct_to_nifti import read_dicom_struct_file
from platipy.dicom.io.rtstruct_to_nifti import convert_rtstruct
from platipy.dicom.io.rtstruct_to_nifti import read_dicom_image
from pathlib import Path

import pathlib
import shutil
import urllib.request
zip_url = "https://github.com/RadiotherapyAI/test-data-public/releases/download/deepmind-dicom/0522c0768.zip"
zip_filepath = "data.zip"
data_directory = pathlib.Path("data")
if not data_directory.exists():
    urllib.request.urlretrieve(zip_url, zip_filepath)
    shutil.unpack_archive(zip_filepath, data_directory)

#Reading CT images
READctimages = read_dicom_image ("C:\\Python\\Practice files\\data\\0522c0768\\")

#Reading RT structure images
READcontour_filename= read_dicom_struct_file("C:\\Python\\Practice files\\data\\RS\\RS.dcm")
Contour_conversion = convert_rtstruct("C:\\Python\\Practice files\\data\\0522c0768\\"
                                      ,"C:\\Python\\Practice files\\data\\RS\\RS.dcm"
                                      ,prefix='Struct_'
                                      , output_dir="C:\\Python\\Practice files\\data\\RS\\"
                                     ,spacing=None)

#First structure file set
Struct_list = list(glob.glob("C:\\Python\\Practice files\\data\\RS\\Structs_*.nii.gz"))

contours = {}
for Struct in Struct_list: 
    _name = Struct.split(".nii.gz")[0].split("Struct_")[-1]

    contours[_name] = sitk.ReadImage(Struct)

#Visualisation
image_visualiser = ImageVisualiser(READctimages)
image_visualiser.add_contour(contours,color='red',linewidth=1)
fig = image_visualiser.show()

Error message

---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
c:\Python\Practice files\Simplified example.ipynb Cell 7' in <cell line: 4>()
      2 image_visualiser = ImageVisualiser(READctimages)
      3 image_visualiser.add_contour(contours,color='red',linewidth=1)
----> 4 fig = image_visualiser.show()

File C:\Python\Python3_9_10\lib\site-packages\platipy\imaging\visualisation\visualiser.py:451, in ImageVisualiser.show(self, interact)
    448     # self.interact_adjust_slice()
    450 self.__figure.canvas.draw()
--> 451 self._add_legend()
    452 self.__figure.set_facecolor("white")
    454 return self.__figure

File C:\Python\Python3_9_10\lib\site-packages\platipy\imaging\visualisation\visualiser.py:1613, in ImageVisualiser._add_legend(self)
   1610             ax_ax_position = ax_ax.get_position()
   1611             x_pos_legend = ax_ax_position.xmax + 0.05
-> 1613             approx_font_scaling = self.__figure_size / (
   1614                 len(self.__contours) + len(self.__bounding_boxes)
   1615             )
   1617             plt.figlegend(
   1618                 loc="center left",
   1619                 bbox_to_anchor=(x_pos_legend, y_pos_legend),
   1620                 fontsize=min([10, 16 * approx_font_scaling]),
   1621             )
   1622 else:
   1623     # these is probably only one axis

ZeroDivisionError: division by zero

Can I ask for any advice on this error?

@SimonBiggs might you be able to help me out here?

Thank you very much in advance.

Lastly, I would like to thank Robert Finnegan (@rnfinnegan) and Phil Chlap (@pchlap) for their work in platipy. I am an recent graduate (master of medical physics) who has very limited programming background but platipy helped me a lot in medical image visualisation. It is very highly accessible and easy to use for an individual who has limited programming background. Thank you very much for your works again.

Kind regards

Young woo Kim

SimonBiggs commented 2 years ago

Hi @smallkev,

I tried to reproduce your error locally. There was quite a bit I needed to change within your code to make it work on my end. I adjusted your example to look like the following:

import pathlib
import shutil
import tempfile
import urllib.request

import SimpleITK as sitk
import matplotlib.pyplot as plt

from platipy.dicom.io.rtstruct_to_nifti import convert_rtstruct
from platipy.dicom.io.rtstruct_to_nifti import read_dicom_image
from platipy.imaging import ImageVisualiser

def test_font_scaling():
    with tempfile.TemporaryDirectory() as temp_dir:
        temp_dir = pathlib.Path(temp_dir)

        zip_url = (
            "https://github.com/RadiotherapyAI/test-data-public/"
            "releases/download/deepmind-dicom/0522c0768.zip"
        )
        zip_filepath = temp_dir / "data.zip"

        urllib.request.urlretrieve(zip_url, zip_filepath)
        shutil.unpack_archive(zip_filepath, temp_dir)

        patient_dir = temp_dir / "0522c0768"
        structure_path = patient_dir / "RS.dcm"

        ct_images = read_dicom_image(patient_dir)
        prefix = "structure_masks_"

        convert_rtstruct(
            patient_dir,
            structure_path,
            prefix=prefix,
            output_dir=patient_dir,
            spacing=None,
        )

        structure_paths = patient_dir.glob(f"{prefix}*.nii.gz")

        contours = {}
        for path in structure_paths:
            filename = _name_with_all_suffixes_removed(path)
            contour_name = filename.removeprefix(prefix)

            contours[contour_name] = sitk.ReadImage(str(path))

        image_visualiser = ImageVisualiser(ct_images)
        image_visualiser.add_contour(contours, color="red", linewidth=1)
        fig = image_visualiser.show()

    return fig

def _name_with_all_suffixes_removed(path: pathlib.Path):
    while path.suffix:
        path = path.with_suffix("")

    return path.name

if __name__ == "__main__":
    _fig = test_font_scaling()
    plt.show()

And that above code worked without any issue, and produced a result that looked like the following:

image

Cheers :slightly_smiling_face:, Simon

rnfinnegan commented 2 years ago

Hello!

I am very happy that you find PlatiPy useful.

Thanks for providing a working example, @SimonBiggs!

For some context, it seems like your original code produced an error because there are no contours, i.e. contours is empty. When you save the DICOM RT-Structures you use the prefix Struct_, but when you read them in you use the prefix Structs_. This would make Struct_list empty! Could you check to see if this is the case, for example by adding print("contours is", contours)?

Let me know if this helps.

Cheers, Rob

smallkev commented 2 years ago

Thank you very much for your help, @SimonBiggs.

Kind regards.

Young woo Kim

smallkev commented 2 years ago

Hello, Robert Finnegan(@rnfinnegan).

Firstly, thank you very much for your help.

I've checked my original codes by checking the structure list using print("contours is", contours). And I found that one of structure list was empty. So I've re-read all of my codes again, then I found that the prefix used for conversion and reading the structure files were different. Now, I can successfully add contours.

Thank you very much for your help.

If it is okay, can I ask one more question?

I've tried to add 2 different sets of contours from 2 different structure files by adding these codes:

image_visualiser.add_contour(contours,color='red',linewidth=1)
image_visualiser.add_contour(contourss,color='green',linewidth=0.5)
fig = image_visualiser.show()

But it only shows 1 set of contour (contourss, green) in the image.

Can I add 2 different sets of contours in same image at once?

Thank you very much.

Kind regards.

Young woo Kim

SimonBiggs commented 2 years ago

Can I add 2 different sets of contours in same image at once?

Hi @smallkev,

I might be wrong about this, but without actually testing it myself I suspect the following approach might bring you some success.

At the end of the day, you want more contours by making this contours dictionary have more items in it: https://github.com/pyplati/platipy/blob/3f778df2ee825441933aa95a80f428e336157d48/platipy/imaging/visualisation/tests/test_use_case.py#L61-L66

This could be achieved by repeating the following section of code for each structure file, except, each time, use a different prefix:

https://github.com/pyplati/platipy/blob/3f778df2ee825441933aa95a80f428e336157d48/platipy/imaging/visualisation/tests/test_use_case.py#L49-L57

And then, when collecting the contour files allow for searching through all prefixes. Do this by changing this line: https://github.com/pyplati/platipy/blob/3f778df2ee825441933aa95a80f428e336157d48/platipy/imaging/visualisation/tests/test_use_case.py#L59

to say:

structure_paths = patient_dir.glob("*.nii.gz") 

And removing the following line entirely:

https://github.com/pyplati/platipy/blob/3f778df2ee825441933aa95a80f428e336157d48/platipy/imaging/visualisation/tests/test_use_case.py#L64

This should then result in each contour displayed including the structure file prefix you have defined, and allowing for multiple files worth of structures to be included.

smallkev commented 2 years ago

Thank you very much! @SimonBiggs.

I've just check with my codes and it worked.

Thank you very much again.

Kind regards

Young woo Kim

SimonBiggs commented 2 years ago

Thank you very much!

My pleasure :)

SimonBiggs commented 2 years ago

Also, as a last step, it might be worth changing the title of this issue to something that is more "Googlable". If you changed it to something like:

Adding multiple DICOM structure files to a single CT visulaisation

Then someone who is Google searching in that vein might land on this thread and also be helped :slightly_smiling_face: