Generic selectors
Exact matches only
Search in title
Search in content
Post Type Selectors

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 iswhat 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 →

We build custom medical imaging platforms — advanced DICOM viewers, AI segmentation, and the clinical systems around them.

Get in Touch

Copyright © 2026 PYCAD. All Rights Reserved.