Skip to content

Commit

Permalink
metadata stuffs
Browse files Browse the repository at this point in the history
Former-commit-id: c236408
  • Loading branch information
fishingguy456 committed Jun 2, 2022
1 parent a6501fd commit 4ff60a8
Show file tree
Hide file tree
Showing 9 changed files with 102 additions and 16 deletions.
22 changes: 20 additions & 2 deletions examples/autotest.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ def process_one_subject(self, subject_id):
print("The subject id: {} has no {}".format(subject_id, colname))
pass
elif modality == "CT" or modality == 'MR':
image = read_results[i]
image = read_results[i].image
if len(image.GetSize()) == 4:
assert image.GetSize()[-1] == 1, f"There is more than one volume in this CT file for {subject_id}."
extractor = sitk.ExtractImageFilter()
Expand All @@ -124,7 +124,13 @@ def process_one_subject(self, subject_id):
image = self.resample(image)
#Saving the output
self.output(subject_id, image, output_stream)

if hasattr(read_results[i], "metadata"):
metadata.update(read_results[i].metadata)

metadata[f"size_{output_stream}"] = str(image.GetSize())


print(subject_id, " SAVED IMAGE")
elif modality == "RTDOSE":
try: #For cases with no image present
Expand All @@ -140,6 +146,10 @@ def process_one_subject(self, subject_id):
self.output(f"{subject_id}_{num}", doses, output_stream)
metadata[f"size_{output_stream}"] = str(doses.GetSize())
metadata[f"metadata_{colname}"] = [read_results[i].get_metadata()]

if hasattr(structure_set, "metadata"):
metadata.update(doses.metadata)

print(subject_id, " SAVED DOSE")
elif modality == "RTSTRUCT":
#For RTSTRUCT, you need image or PT
Expand Down Expand Up @@ -181,6 +191,10 @@ def process_one_subject(self, subject_id):
self.output(subject_id, mask_to_process, output_stream, True, roi_names_list[i])
else:
self.output(f"{subject_id}_{num}", mask_to_process, output_stream, True, roi_names_list[i])

if hasattr(structure_set, "metadata"):
metadata.update(structure_set.metadata)

metadata[f"metadata_{colname}"] = [structure_set.roi_names]

print(subject_id, "SAVED MASK ON", conn_to)
Expand All @@ -198,6 +212,10 @@ def process_one_subject(self, subject_id):
self.output(f"{subject_id}_{num}", pet, output_stream)
metadata[f"size_{output_stream}"] = str(pet.GetSize())
metadata[f"metadata_{colname}"] = [read_results[i].get_metadata()]

if hasattr(structure_set, "metadata"):
metadata.update(pet.metadata)

print(subject_id, " SAVED PET")
#Saving all the metadata in multiple text files
with open(pathlib.Path(self.output_directory,".temp",f'{subject_id}.pkl').as_posix(),'wb') as f:
Expand Down Expand Up @@ -238,7 +256,7 @@ def run(self):
output_directory="C:/Users/qukev/BHKLAB/autopipelineoutputshort",
modalities="CT,RTSTRUCT",
visualize=False,
overwrite=False)
overwrite=True)

# pipeline = AutoPipeline(input_directory="C:/Users/qukev/BHKLAB/hnscc_testing/HNSCC",
# output_directory="C:/Users/qukev/BHKLAB/hnscc_testing_output",
Expand Down
4 changes: 3 additions & 1 deletion examples/ct_rtstruct_quickstart.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ def __init__(self,

def process_one_subject(self, subject_id):
# calling the classes initialized in __init__()
image = self.image_input(subject_id)
image = self.image_input(subject_id).image
structure_set = self.structure_set_input(subject_id)

# print all the regions of interest in the RTSTRUCT
Expand All @@ -106,6 +106,8 @@ def process_one_subject(self, subject_id):
parser.add_argument("output_directory", type=str,
help="The directory where the output will be stored")

# sample run: python ct_rtstruct_quickstart.py C:\Users\qukev\BHKLAB\datasetshort\manifest-1598890146597\NSCLC-Radiomics-Interobserver1 C:\Users\qukev\BHKLAB\starteroutput

# look at your input directory and look at how all the DICOM files are named
CT_file_convention = "*/NA-*"
RTSTRUCT_file_convention = "*/1.000000-ARIA RadOnc Structure Sets-*/1-1.dcm"
Expand Down
3 changes: 2 additions & 1 deletion examples/radcure_simple.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ def process_one_subject(self, subject_id):
The ID of currently processed subject
"""

image = self.image_input(subject_id)
image = self.image_input(subject_id).image

structure_set = self.structure_set_input(subject_id)
dose_set = self.rtdose_input(subject_id)
pet_set = self.petscan_input(subject_id)
Expand Down
24 changes: 22 additions & 2 deletions imgtools/io/loaders.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from ..modules import StructureSet
from ..modules import Dose
from ..modules import PET
from ..modules import CTMRScan
from ..utils.crawl import *


Expand All @@ -28,7 +29,7 @@ def read_header(path):

def read_dicom_series(path: str,
series_id: Optional[str] = None,
recursive: bool = False) -> sitk.Image:
recursive: bool = False) -> CTMRScan:
"""Read DICOM series as SimpleITK Image.
Parameters
Expand All @@ -55,6 +56,7 @@ def read_dicom_series(path: str,
dicom_names = reader.GetGDCMSeriesFileNames(path,
seriesID=series_id if series_id else "",
recursive=recursive)
# extract the names of the dicom files that are in the path variable, which is a directory
reader.SetFileNames(dicom_names)

# Configure the reader to load all of the DICOM tags (public+private):
Expand All @@ -65,7 +67,25 @@ def read_dicom_series(path: str,
reader.MetaDataDictionaryArrayUpdateOn()
reader.LoadPrivateTagsOn()

return reader.Execute()
metadata = {}
dicom_data = dcmread(dicom_names[0])
if hasattr(dicom_data, 'KVP'):
metadata["KVP"] = str(dicom_data.KVP)
if hasattr(dicom_data, 'ScanOptions'):
metadata["ScanOptions"] = str(dicom_data.ScanOptions)
if hasattr(dicom_data, 'ReconstructionAlgorithm'):
metadata["ReconstructionAlgorithm"] = str(dicom_data.ReconstructionAlgorithm)
if hasattr(dicom_data, 'ContrastFlowRate'):
metadata["ContrastFlowRate"] = str(dicom_data.ContrastFlowRate)
if hasattr(dicom_data, 'ContrastFlowDuration'):
metadata["ContrastFlowDuration"] = str(dicom_data.ContrastFlowDuration)

# is this contrast type?
# if hasattr(dicom_data, 'ContrastBolusAgent'):
# metadata["ContrastType"] = str(dicom_data.ContrastBolusAgent)


return CTMRScan(reader.Execute(), metadata)


def read_dicom_rtstruct(path):
Expand Down
4 changes: 3 additions & 1 deletion imgtools/modules/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@
from .structureset import *
from .pet import *
from .dose import *
from .datagraph import *
from .datagraph import *
from .sparsemask import *
from .ctmrscan import *
9 changes: 9 additions & 0 deletions imgtools/modules/ctmrscan.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import SimpleITK as sitk
from typing import Dict, TypeVar

T = TypeVar('T')

class CTMRScan:
def __init__(self, image: sitk.Image, metadata: Dict[str, T]):
self.image = image
self.metadata = metadata
12 changes: 10 additions & 2 deletions imgtools/modules/dose.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import os, pathlib
import warnings

from typing import Dict, Optional, TypeVar

import numpy as np
from matplotlib import pyplot as plt

import SimpleITK as sitk
from pydicom import dcmread


T = TypeVar('T')

def read_image(path):
reader = sitk.ImageSeriesReader()
Expand All @@ -20,10 +22,12 @@ def read_image(path):


class Dose(sitk.Image):
def __init__(self, img_dose, df):
def __init__(self, img_dose, df, metadata: Optional[Dict[str, T]] = None):
super().__init__(img_dose)
self.img_dose = img_dose
self.df = df
if metadata:
self.metadata = metadata

@classmethod
def from_dicom_rtdose(cls, path):
Expand All @@ -41,6 +45,10 @@ def from_dicom_rtdose(cls, path):
factor = float(df.DoseGridScaling)
img_dose = sitk.Cast(dose, sitk.sitkFloat32)
img_dose = img_dose * factor

# metadata = {}
# metadata["DoseType"] = df.DoseType
#return cls(img_dose, df, metadata)
return cls(img_dose, df)

def resample_dose(self,
Expand Down
24 changes: 21 additions & 3 deletions imgtools/modules/pet.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import os, pathlib
import warnings
import datetime
from typing import Optional
from typing import Optional, Dict, TypeVar
import numpy as np
from matplotlib import pyplot as plt
import SimpleITK as sitk
from pydicom import dcmread

T = TypeVar('T')

def read_image(path:str,series_id: Optional[str]=None):
reader = sitk.ImageSeriesReader()
dicom_names = reader.GetGDCMSeriesFileNames(path,seriesID=series_id if series_id else "")
Expand All @@ -17,12 +19,14 @@ def read_image(path:str,series_id: Optional[str]=None):
return reader.Execute()

class PET(sitk.Image):
def __init__(self, img_pet, df, factor, calc):
def __init__(self, img_pet, df, factor, calc, metadata: Optional[Dict[str, T]] = None):
super().__init__(img_pet)
self.img_pet = img_pet
self.df = df
self.factor = factor
self.calc = calc
if metadata:
self.metadata = metadata

@classmethod
def from_dicom_pet(cls, path,series_id=None,type="SUV"):
Expand Down Expand Up @@ -55,7 +59,21 @@ def from_dicom_pet(cls, path,series_id=None,type="SUV"):

#SimpleITK reads some pixel values as negative but with correct value
img_pet = sitk.Abs(img_pet * factor)
return cls(img_pet, df, factor, calc)

metadata = {}
# metadata["factor"] = df.factor

if hasattr(df, 'RescaleType'):
metadata["RescaleType"] = str(pet.RescaleType)
if hasattr(df, 'RescaleSlope'):
metadata["RescaleSlope"] = str(pet.RescaleSlope)
if hasattr(df, 'RadionuclideTotalDose'):
metadata["RadionuclideTotalDose"] = str(pet.RadionuclideTotalDose)
if hasattr(df, 'RadionuclideHalfLife'):
metadata["RadionuclideHalfLife"] = str(pet.RadionuclideHalfLife)

return cls(img_pet, df, factor, calc, metadata)
# return cls(img_pet, df, factor, calc)

def get_metadata(self):
'''
Expand Down
16 changes: 12 additions & 4 deletions imgtools/modules/structureset.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import re
from warnings import warn
from typing import Dict, List, Optional, Union, Tuple, Set
from typing import Dict, List, Optional, Union, Tuple, Set, TypeVar

import numpy as np
import SimpleITK as sitk
Expand All @@ -11,27 +11,35 @@
from .segmentation import Segmentation
from ..utils import physical_points_to_idxs

T = TypeVar('T')

def _get_roi_points(rtstruct, roi_index):
return [np.array(slc.ContourData).reshape(-1, 3) for slc in rtstruct.ROIContourSequence[roi_index].ContourSequence]


class StructureSet:
def __init__(self, roi_points: Dict[str, np.ndarray]):
def __init__(self, roi_points: Dict[str, np.ndarray], metadata: Optional[Dict[str, T]] = None):
self.roi_points = roi_points
if metadata:
self.metadata = metadata

@classmethod
def from_dicom_rtstruct(cls, rtstruct_path: str) -> 'StructureSet':
rtstruct = dcmread(rtstruct_path, force=True)
roi_names = [roi.ROIName for roi in rtstruct.StructureSetROISequence]

roi_points = {}
for i, name in enumerate(roi_names):
try:
roi_points[name] = _get_roi_points(rtstruct, i)
except AttributeError:
warn(f"Could not get points for ROI {name} (in {rtstruct_path}).")
return cls(roi_points)

metadata = {}
if hasattr(rtstruct, 'StructureSetROISequence'):
metadata["num_ROIs"] = str(len(rtstruct.StructureSetROISequence))

return cls(roi_points, metadata)
# return cls(roi_points)

@property
def roi_names(self) -> List[str]:
Expand Down

0 comments on commit 4ff60a8

Please sign in to comment.