DICOM (Digital Imaging and Communications in Medicine) is a standard format for medical images that is widely used for storing and transferring medical image data.
The code on this page uses the Matplotlib and Pydicom packages, especially the latter which is a specialist package for working with DICOM images in Python. See its documentation and its homepage for more. Install the packages by running the following in the terminal:
# "python3.12" should correspond to the version of Python you are using
python3.12 -m pip install matplotlib
python3.12 -m pip install pydicom
Once finished, import these packages along with the datetime
module into your Python script as follows:
# Matplotlib is for creating static, animated and interactive visualizations
from matplotlib import pyplot as plt
# pydicom is a pure Python package for working with DICOM files
import pydicom
# The datetime module supplies classes for manipulating dates and times
from datetime import datetime
If you’re on an Ubuntu machine or similar it’s possible that you will need to change some environment variables to be compatible with the Wayland system:
# os provides a portable way of using operating system dependent functionality
import os
# Set the QT_QPA_PLATFORM environment variable to wayland
os.environ['QT_QPA_PLATFORM'] = 'wayland'
# Set the Matplotlib backend to one that is compatible with Wayland
plt.switch_backend('Agg')
This can be done with the dcmread()
function from Pydicom:
# Path to the DICOM file
path = 'I0000001.dcm'
# Load the DICOM file
ds = pydicom.dcmread(path)
print(type(ds))
## <class 'pydicom.dataset.FileDataset'>
The FileDataset
object will have a number of attributes that can be viewed (the below code is based on the Read a Dataset and plot Pixel Data tutorial that is provided in the documentation):
print(f'SOP Class........: {ds.SOPClassUID} ({ds.SOPClassUID.name})')
patient_name = ds.PatientName
display_name = patient_name.family_name + ', ' + patient_name.given_name
print(f"Patient's Name...: {display_name}")
print(f'Patient ID.......: {ds.PatientID}')
print(f'Modality.........: {ds.Modality}')
dt = datetime.strptime(ds.StudyDate, '%Y%m%d')
print(f'Study Date.......: {dt.date()}')
print(f'Image size.......: {ds.Rows} x {ds.Columns}')
print(f'Pixel Spacing....: {ds.PixelSpacing}')
## SOP Class........: 1.2.840.10008.5.1.4.1.1.1.1 (Digital X-Ray Image Storage - For Presentation)
## Patient's Name...: NICHOLLS, ROWAN
## Patient ID.......: RTH10437278
## Modality.........: DX
## Study Date.......: 2019-08-02
## Image size.......: 1435 x 2948
## Pixel Spacing....: [0.0800, 0.0800]
Use .get()
if you are not sure if the attribute exists or not and you want to get a default value if it is missing:
print(f'Slice location...: {ds.get('SliceLocation', '(missing)')}')
## Slice location...: (missing)
You can see a list of all the attributes that the object has by running dir()
(you can also view all of them by using the to_json
attribute - print(ds.to_json)
):
print(dir(ds))
## ['AccessionNumber', 'AcquisitionContextSequence', 'AcquisitionDate', 'AcquisitionTime', 'AnatomicRegionSequence', 'BitsAllocated', 'BitsStored', 'BodyPartExamined', 'BurnedInAnnotation', 'Columns', 'ContentDate', 'ContentTime', 'DetectorID', 'DetectorType', 'DeviceSerialNumber', 'ExposureTime', 'HighBit', 'HistogramSequence', 'ImageAndFluoroscopyAreaDoseProduct', 'ImageLaterality', 'ImageType', 'ImagerPixelSpacing', 'InstanceCreationDate', 'InstanceCreationTime', 'InstanceNumber', 'KVP', 'LargestImagePixelValue', 'LossyImageCompression', 'Manufacturer', 'ManufacturerModelName', 'Modality', 'NameOfPhysiciansReadingStudy', 'OtherPatientIDs', 'PatientBirthDate', 'PatientID', 'PatientName', 'PatientOrientation', 'PatientSex', 'PerformingPhysicianName', 'PhotometricInterpretation', 'PhysiciansOfRecord', 'PixelData', 'PixelIntensityRelationship', 'PixelIntensityRelationshipSign', 'PixelRepresentation', 'PixelSpacing', 'PresentationIntentType', 'PresentationLUTShape', 'ProcedureCodeSequence', 'ReferringPhysicianName', 'RequestAttributesSequence', 'RequestingPhysician', 'RescaleIntercept', 'RescaleSlope', 'RescaleType', 'Rows', 'SOPClassUID', 'SOPInstanceUID', 'SamplesPerPixel', 'SeriesDate', 'SeriesInstanceUID', 'SeriesNumber', 'SeriesTime', 'SmallestImagePixelValue', 'SoftwareVersions', 'SpecificCharacterSet', 'StationName', 'StudyDate', 'StudyDescription', 'StudyID', 'StudyInstanceUID', 'StudyTime', 'WindowCenter', 'WindowWidth', 'XRayTubeCurrent', '__array__', '__class__', '__contains__', '__copy__', '__deepcopy__', '__delattr__', '__delitem__', '__dict__', '__dir__', '__doc__', '__enter__', '__eq__', '__exit__', '__format__', '__ge__', '__getattr__', '__getattribute__', '__getitem__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_character_set', '_convert_pixel_data_using_handler', '_convert_pixel_data_without_handler', '_copy_implementation', '_dataset_slice', '_dict', '_do_pixel_data_conversion', '_parent_encoding', '_parent_seq', '_pixel_array', '_pixel_id', '_pretty_str', '_private_blocks', '_set_file_meta', '_slice_dataset', 'add', 'add_new', 'clear', 'compress', 'convert_pixel_data', 'copy', 'data_element', 'decode', 'decompress', 'default_element_format', 'default_sequence_element_format', 'dir', 'elements', 'ensure_file_meta', 'file_meta', 'filename', 'fileobj_type', 'fix_meta_info', 'formatted_lines', 'from_json', 'get', 'get_item', 'get_private_item', 'group_dataset', 'indent_chars', 'is_decompressed', 'is_implicit_VR', 'is_little_endian', 'is_original_encoding', 'is_undefined_length_sequence_item', 'items', 'iterall', 'keys', 'overlay_array', 'parent', 'parent_seq', 'pixel_array', 'pop', 'popitem', 'preamble', 'private_block', 'private_creators', 'read_encoding', 'read_implicit_vr', 'read_little_endian', 'remove_private_tags', 'save_as', 'set_original_encoding', 'setdefault', 'timestamp', 'to_json', 'to_json_dict', 'top', 'trait_names', 'update', 'values', 'walk', 'waveform_array']
Use Matplotlib to create a figure containing the image:
# Create the image without axes or whitespace
figsize = (ds.pixel_array.shape[1] / 400, ds.pixel_array.shape[0] / 400)
plt.figure(figsize=figsize)
plt.imshow(ds.pixel_array, cmap='gray')
plt.axis('off')
plt.subplots_adjust(left=0, right=1, top=1, bottom=0)
plt.show()
This particular image is of my mouth prior to some dental work a few years back.