Reading a DICOM file in Python is two steps: parse the header with pydicom (dcmread), then take .pixel_array and display or window it. This page is that how-to. It is not “what is a .dcm” and it is not “pick a viewer.”
If you meant what a .dcm is (tags, extension) → what is a DCM file. If you meant what DICOM the standard is → what is DICOM. If you meant pick a viewer → how to open a DCM file / DICOM viewer software. If you meant DICOM→NIfTI → DICOM to NIfTI.
SimpleITK is the other common path (sitk.ReadImage, then sitk.GetArrayFromImage). This page stays on pydicom. If you already live in ITK / SimpleITK, use that stack; do not mix both as a first script.
Toolkit
| Library | Job |
|---|---|
| pydicom | Open the file, read and write tags, hand you the pixels |
| NumPy | .pixel_array is a ndarray. Analysis starts here |
| Matplotlib / Pillow | Show the slice, or write a PNG of it |
Environment
python -m venv dicom_env
source dicom_env/bin/activate # Windows: dicom_envScriptsactivate
pip install pydicom numpy pillow matplotlib
Sanity check: import pydicom, numpy, PIL with no ImportError. Pin versions with pip freeze > requirements.txt if the script has to run on another machine.
dcmread and the header
import pydicom
ds = pydicom.dcmread("path/to/image.dcm")
print(ds)
print(ds.PatientName) # (0010,0010)
print(ds.PatientID)
print(ds.StudyDescription) # (0008,1030)
print(ds.StudyDate)
dcmread returns a FileDataset. Keywords (PatientName, StudyDescription) are easier than hex tags; both work. Print the whole dataset once so you see what is actually in this file — modalities omit tags, and a missing keyword raises AttributeError.
The file should start with a 128-byte preamble and DICM. If pydicom raises InvalidDicomError / FileMetaInformationMissingError, you usually have the wrong path, a JPEG renamed to .dcm, or an object that never got a meta header. Open it in RadiAnt or Horos before debugging the script.
Pixels and windowing
import pydicom
import matplotlib.pyplot as plt
ds = pydicom.dcmread("path/to/image.dcm")
pixels = ds.pixel_array
print(pixels.shape, pixels.dtype)
plt.imshow(pixels, cmap="bone")
plt.axis("off")
plt.show()
A raw CT often looks washed out. The useful contrast is a window: center and width, usually already in the header.
center = float(ds.WindowCenter if not hasattr(ds.WindowCenter, "__iter__") else ds.WindowCenter[0])
width = float(ds.WindowWidth if not hasattr(ds.WindowWidth, "__iter__") else ds.WindowWidth[0])
lo = center - width / 2.0
hi = center + width / 2.0
windowed = pixels.astype("float32")
windowed = (windowed - lo) / (hi - lo)
windowed = windowed.clip(0, 1)
Some files store several window values (a sequence). Take the first unless you know you want a lung or bone preset. Apply RescaleSlope / RescaleIntercept before windowing on CT if those tags exist, or Hounsfield numbers will be wrong.
A folder of slices (3D)
A CT or MR study is many files. Sort on (0020,0032) Image Position (Patient) — the Z of the slice — not on the filename.
from pathlib import Path
import numpy as np
import pydicom
files = list(Path("path/to/series").glob("*.dcm"))
datasets = [pydicom.dcmread(p) for p in files]
datasets.sort(key=lambda d: float(d.ImagePositionPatient[2]))
volume = np.stack([d.pixel_array for d in datasets])
print(volume.shape) # (slices, rows, cols)
If ImagePositionPatient is missing, InstanceNumber is the weaker fallback. Do not assume directory order.
A note on AI pipelines
Once you have arrays: same size (resize 256 or 512 if the model demands it), same intensity scale (0–1 or z-score), and a table of the tags you still need (PatientID only after anonymization, Modality, spacing). That is data prep, not a second tutorial. This page stops when the volume is a ndarray.
FAQ
DICOM vs JPG?
JPG is pixels. DICOM is pixels plus the header. A model trained on JPGs never saw spacing, window, or which slice is which. Keep the DCM; export a PNG only for a figure.
Not a DICOM file?
Check the path. Then the preamble + DICM. Then open it in a real viewer. pydicom is strict; a broken export from a USB viewer is more common than a pydicom bug.
Why not SimpleITK on this page?
SimpleITK is the right tool when you already want ITK filters, resampling, and registration in one object. pydicom is the right tool when you want the tags in your face. Pick one for the first script. Registration how-to lives under image registration in Python, not here.
PYCAD builds the imaging side of products that have to read these files for real. Case studies.
Keep Reading
Related Articles
Explore the full DICOM HubAll services, tools, and guides on this topic — in one place.
Visit Hub →