Skip to content

Commit

Permalink
feat: Add DICOM tags module and update DICOM sorting functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
jjjermiah committed Apr 1, 2024
1 parent 695f660 commit dfc41fa
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 5 deletions.
1 change: 1 addition & 0 deletions src/nbiatoolkit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from .auth import OAuth2
from .logger.logger import setup_logger
from .utils.nbia_endpoints import NBIA_ENDPOINTS
from .dicomtags import *

# define the __all__ variable
__all__ = [
Expand Down
3 changes: 2 additions & 1 deletion src/nbiatoolkit/dicomsort/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@

# ]

from .dicomsort import DICOMSorter
from .dicomsort import DICOMSorter, generateFilePathFromDICOMAttributes
from .helper_functions import parseDICOMKeysFromFormat, sanitizeFileName, _truncateUID

__all__ = [
"parseDICOMKeysFromFormat",
"sanitizeFileName",
"_truncateUID",
"DICOMSorter",
"generateFilePathFromDICOMAttributes",
]
7 changes: 6 additions & 1 deletion src/nbiatoolkit/dicomsort/dicomsort.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import shutil
from .helper_functions import parseDICOMKeysFromFormat, sanitizeFileName, _truncateUID
from concurrent.futures import ThreadPoolExecutor, as_completed
from typing import Union


def get_dicom_files(sourceDir) -> list[str]:
Expand All @@ -39,7 +40,7 @@ def read_in_dicom_file(filePath: str) -> pydicom.FileDataset:


def generateFilePathFromDICOMAttributes(
dataset: pydicom.FileDataset,
dataset: pydicom.Dataset,
targetPattern: str,
truncateUID: bool,
sanitizeFilename: bool,
Expand All @@ -57,6 +58,10 @@ def generateFilePathFromDICOMAttributes(
# Retrieve the attribute value if it exists or default to a placeholder string
value = str(getattr(dataset, key, "Unknown" + key))

# if value is exactly "UnknownInstanceNumber", replace it with "1"
if value == "UnknownInstanceNumber":
value = "1"

value = (
_truncateUID(uid=value, lastDigits=5)
if key.endswith("UID") and truncateUID
Expand Down
2 changes: 2 additions & 0 deletions src/nbiatoolkit/dicomtags/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
subsetSeriesTags,
getReferencedFrameOfReferenceSequence,
getReferencedSeriesUIDS,
extract_ROI_info,
)

__all__ = [
Expand All @@ -21,4 +22,5 @@
"subsetSeriesTags",
"getReferencedFrameOfReferenceSequence",
"getReferencedSeriesUIDS",
"extract_ROI_info",
]
30 changes: 28 additions & 2 deletions src/nbiatoolkit/dicomtags/tags.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from math import log
from pydicom.datadict import dictionary_VR
from pydicom.datadict import tag_for_keyword
import pydicom
from pydicom.datadict import dictionary_VR, tag_for_keyword
import pandas as pd
from typing import List

Expand Down Expand Up @@ -342,6 +342,32 @@ def extract_ROI_info(StructureSetROISequence) -> dict[str, dict[str, str]]:
return ROISet


def generateFileDatasetFromTags(tags_df: pd.DataFrame) -> pydicom.Dataset:
"""
Generate a pydicom Dataset object from a DataFrame of DICOM tags.
Args:
tags_df (pd.DataFrame): DataFrame containing DICOM tags.
Returns:
pydicom.Dataset: A pydicom Dataset object containing the DICOM tags.
"""

# Create a new FileDataset
ds = pydicom.Dataset()

for _, row in tags_df.iterrows():
tag = convert_element_to_int(row["element"])
value = row["data"]
if tag == -1:
continue
VR = element_VR_lookup(row["element"])[1]

ds.add_new(tag=tag, VR=VR, value=value)

return ds


# def getRTSTRUCT_ROI_info(seriesUID: str) -> dict[str, dict[str, str]]:
# """
# Given a SeriesInstanceUID of an RTSTRUCT, retrieves the ROI information.
Expand Down
46 changes: 45 additions & 1 deletion src/nbiatoolkit/nbia.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
import re
import zipfile
from tempfile import TemporaryDirectory
from .dicomsort import DICOMSorter

from pydicom import Dataset, FileDataset
from .dicomsort import DICOMSorter, generateFilePathFromDICOMAttributes

import multiprocessing
from .auth import OAuth2
Expand All @@ -26,6 +28,7 @@
getReferencedSeriesUIDS,
extract_ROI_info,
getSequenceElement,
generateFileDatasetFromTags,
)

import pandas as pd
Expand Down Expand Up @@ -637,6 +640,47 @@ def getRefSeriesUIDs(

return getReferencedSeriesUIDS(series_tags_df=tags_df)

def generateFilePathFromDICOMTags(
self,
SeriesInstanceUID: str,
filePattern: str = "%PatientName/%Modality-%SeriesNumber-%SeriesInstanceUID/%InstanceNumber.dcm",
) -> str:
"""
Generates a file path from DICOM tags.
Args:
SeriesInstanceUID (str): The Series Instance UID of the DICOM series.
filePattern (str, optional): The file pattern to use for generating the file path. Defaults to "%PatientName/%Modality-%SeriesNumber-%SeriesInstanceUID/%InstanceNumber.dcm".
Returns:
str: The generated file path.
Note:
This only considers the first instance of the series.
Meant to be used to determine the dirname of the series files.
"""
self.logger.debug("Getting DICOM tags for series %s", SeriesInstanceUID)
tags_df = self.getDICOMTags(
SeriesInstanceUID=SeriesInstanceUID,
return_type=ReturnType.DATAFRAME,
)

if type(tags_df) != pd.DataFrame:
raise ValueError("DICOM Tags not df or not found in the response.")

self.logger.debug("Generating file path from DICOM tags")
ds: Dataset = generateFileDatasetFromTags(tags_df=tags_df)
filePath: str = generateFilePathFromDICOMAttributes(
dataset=ds,
targetPattern=filePattern,
truncateUID=True,
sanitizeFilename=True,
)
self.logger.debug(
"Generated file path: %s for series %s", filePath, SeriesInstanceUID
)
return filePath

def downloadSeries(
self,
SeriesInstanceUID: Union[str, list],
Expand Down

0 comments on commit dfc41fa

Please sign in to comment.