Skip to content

dicom_to_itk

Generate an ITK compatible image from a dicom series/folder

Parameters:

Name Type Description Default
dicom_urlpath str

path to dicom series within a folder

required
output_urlpath str

output/working directory

required
itk_image_type str

ITK volume image type to output (mhd, nrrd, nii, etc.)

required
itk_c_type str

pixel (C) type for pixels, e.g. float or unsigned short

required

Returns:

Name Type Description
dict

metadata about function call

Source code in src/luna/radiology/cli/dicom_to_itk.py
def dicom_to_itk(
    dicom_urlpath, output_urlpath, itk_image_type, itk_c_type, convert_to_suv=False
):
    """Generate an ITK compatible image from a dicom series/folder

    Args:
        dicom_urlpath (str): path to dicom series within a folder
        output_urlpath (str): output/working directory
        itk_image_type (str): ITK volume image type to output (mhd, nrrd, nii, etc.)
        itk_c_type (str): pixel (C) type for pixels, e.g. float or unsigned short

    Returns:
        dict: metadata about function call
    """
    PixelType = itk.ctype(itk_c_type)
    ImageType = itk.Image[PixelType, 3]

    namesGenerator = itk.GDCMSeriesFileNames.New()
    namesGenerator.SetUseSeriesDetails(True)
    namesGenerator.AddSeriesRestriction("0008|0021")
    namesGenerator.SetGlobalWarningDisplay(False)
    namesGenerator.SetDirectory(dicom_urlpath)

    seriesUIDs = namesGenerator.GetSeriesUIDs()
    num_dicoms = len(seriesUIDs)

    if num_dicoms < 1:
        logger.warning("No DICOMs in: " + dicom_urlpath)
        return None

    logger.info(
        "The directory {} contains {} DICOM Series".format(
            dicom_urlpath, str(num_dicoms)
        )
    )

    n_slices = 0
    volume = {}
    for uid in seriesUIDs:
        logger.info("Reading: " + uid)
        fileNames = namesGenerator.GetFileNames(uid)
        if len(fileNames) < 1:
            continue

        n_slices = len(fileNames)

        reader = itk.ImageSeriesReader[ImageType].New()
        dicomIO = itk.GDCMImageIO.New()
        reader.SetImageIO(dicomIO)
        reader.SetFileNames(fileNames)
        reader.ForceOrthogonalDirectionOff()

        writer = itk.ImageFileWriter[ImageType].New()

        outFileName = os.path.join(
            output_urlpath, uid + "_volumetric_image." + itk_image_type
        )
        writer.SetFileName(outFileName)
        writer.UseCompressionOn()
        writer.SetInput(reader.GetOutput())
        logger.info("Writing: " + outFileName)
        writer.Update()

        img, _ = medpy.io.load(outFileName)
        volume[outFileName] = np.prod(img.shape)

    if convert_to_suv:
        convert_pet_volume_to_suv(dicom_urlpath, outFileName)

    path = next(Path(dicom_urlpath).glob("*.dcm"))
    ds = dcmread(path)

    # If there are multiple seriesUIDs in a single DICOM dir, return
    # the largest one by volume in the output properties
    outFileName = max(volume, key=volume.get)

    # Prepare metadata and commit
    properties = {
        "itk_volume": outFileName,
        "num_slices": n_slices,
        "segment_keys": {
            "radiology_patient_name": str(ds.PatientName),
            "radiology_accession_number": str(ds.AccessionNumber),
            "radiology_series_instance_uuid": str(ds.SeriesInstanceUID),
            "radiology_series_number": str(ds.SeriesNumber),
            "radiology_modality": str(ds.Modality),
        },
    }

    return properties