What Is DICOM?
DICOM — Digital Imaging and Communications in Medicine — is the international standard for storing, transmitting, and displaying medical images and associated information. Developed jointly by the American College of Radiology (ACR) and the National Electrical Manufacturers Association (NEMA), DICOM 3.0 was released in 1993 and remains the dominant standard today, used by virtually every hospital, radiology department, and medical device manufacturer worldwide.
DICOM is two things in one: a file format for storing image data with rich patient and acquisition metadata, and a network protocol (built on TCP/IP) for transmitting images between PACS (Picture Archiving and Communication Systems), modalities (scanners), and viewing workstations. Every CT scanner, MRI machine, digital X-ray system, ultrasound unit, and PET scanner produces DICOM files.
The DICOM File Structure
A DICOM file has a fixed structure:
┌─────────────────────────────────────────────────┐
│ 128-byte File Preamble (usually all zeros) │
├─────────────────────────────────────────────────┤
│ 4-byte DICM prefix ("DICM" in ASCII) │
├─────────────────────────────────────────────────┤
│ File Meta Information Group (tags 0002,xxxx) │
│ (0002,0000) MetaElementGroupLength │
│ (0002,0001) FileMetaInformationVersion │
│ (0002,0002) MediaStorageSOPClassUID │
│ (0002,0003) MediaStorageSOPInstanceUID │
│ (0002,0010) TransferSyntaxUID │
│ (0002,0012) ImplementationClassUID │
├─────────────────────────────────────────────────┤
│ Data Set (all remaining data elements) │
│ (0008,0016) SOPClassUID │
│ (0008,0018) SOPInstanceUID │
│ (0008,0060) Modality = "CT" │
│ (0008,103E) SeriesDescription │
│ (0010,0010) PatientName │
│ (0010,0020) PatientID │
│ (0010,0030) PatientBirthDate │
│ (0018,0050) SliceThickness │
│ (0020,0013) InstanceNumber │
│ (0028,0010) Rows │
│ (0028,0011) Columns │
│ (0028,0030) PixelSpacing │
│ (0028,1050) WindowCenter │
│ (0028,1051) WindowWidth │
│ (7FE0,0010) PixelData │
└─────────────────────────────────────────────────┘
Data Elements and Tags
Every piece of information in DICOM is a data element identified by a tag — a hexadecimal pair (group, element). Tags are the backbone of DICOM:
| Tag | Keyword | Example Value |
|---|---|---|
| (0008,0016) | SOPClassUID | 1.2.840.10008.5.1.4.1.1.2 (CT Image) |
| (0008,0060) | Modality | CT, MR, CR, DX, PT, US, NM |
| (0008,103E) | SeriesDescription | "HEAD CT W/O CONTRAST" |
| (0010,0010) | PatientName | Smith^John^A |
| (0010,0020) | PatientID | 12345678 |
| (0010,0030) | PatientBirthDate | 19650312 |
| (0018,0050) | SliceThickness | 2.5 (mm) |
| (0018,0088) | SpacingBetweenSlices | 2.5 (mm) |
| (0020,0013) | InstanceNumber | 47 (slice number) |
| (0020,0032) | ImagePositionPatient | -245.7, -151.3, 112.0 |
| (0020,0037) | ImageOrientationPatient | 1,0,0,0,1,0 (axial) |
| (0028,0010) | Rows | 512 |
| (0028,0011) | Columns | 512 |
| (0028,0030) | PixelSpacing | 0.625, 0.625 (mm) |
| (0028,0100) | BitsAllocated | 16 |
| (0028,1050) | WindowCenter | 40 (Hounsfield units) |
| (0028,1051) | WindowWidth | 400 (HU) |
| (0028,1052) | RescaleIntercept | -1024 |
| (0028,1053) | RescaleSlope | 1 |
| (7FE0,0010) | PixelData | [binary pixel array] |
Image Data and Hounsfield Units (CT)
CT images use Hounsfield Units (HU) — a calibrated scale where:
- −1000 HU = air
- −100 HU = fat
- 0 HU = water
- 700–3000 HU = bone/cortical
- 4000+ HU = metallic implants
Stored pixel values are encoded as unsigned integers. The actual HU value is calculated:
HU = (stored_pixel_value × RescaleSlope) + RescaleIntercept
For most CT: RescaleSlope = 1, RescaleIntercept = -1024, so a stored value of 1000 → 1000 × 1 + (−1024) = −24 HU (approximately water/soft tissue).
Windowing controls what part of the HU range is displayed as visible grayscale:
- Window Center (WC) and Window Width (WW) define the display range
- Common presets:
- Lung window: WC = −600, WW = 1500
- Brain: WC = 40, WW = 80
- Bone: WC = 400, WW = 1800
- Abdomen/soft tissue: WC = 40, WW = 400
Reading DICOM with Python (pydicom)
pydicom is the standard Python library for DICOM:
import pydicom
import numpy as np
import matplotlib.pyplot as plt
# Load a DICOM file
ds = pydicom.dcmread("CT_slice_047.dcm")
# Access metadata
print(f"Patient: {ds.PatientName}")
print(f"Patient ID: {ds.PatientID}")
print(f"Modality: {ds.Modality}")
print(f"Series: {ds.SeriesDescription}")
print(f"Image size: {ds.Rows} × {ds.Columns}")
print(f"Pixel spacing: {ds.PixelSpacing} mm")
print(f"Slice thickness: {ds.SliceThickness} mm")
print(f"Window Center: {ds.WindowCenter}, Width: {ds.WindowWidth}")
# Get the pixel array
pixels = ds.pixel_array # shape (512, 512), dtype uint16
# Convert to Hounsfield Units
hu = pixels * float(ds.RescaleSlope) + float(ds.RescaleIntercept)
print(f"HU range: {hu.min():.0f} to {hu.max():.0f}")
# Apply windowing for display
wc = float(ds.WindowCenter)
ww = float(ds.WindowWidth)
img_min = wc - ww / 2
img_max = wc + ww / 2
windowed = np.clip(hu, img_min, img_max)
windowed = ((windowed - img_min) / ww * 255).astype(np.uint8)
plt.imshow(windowed, cmap="gray")
plt.title(f"CT slice {ds.InstanceNumber}")
plt.axis("off")
plt.savefig("ct_slice.png", dpi=150, bbox_inches="tight")
# Load an entire series (multiple slices)
import os
dicom_files = sorted(
[os.path.join("ct_series/", f) for f in os.listdir("ct_series/") if f.endswith(".dcm")],
key=lambda f: pydicom.dcmread(f).InstanceNumber
)
slices = [pydicom.dcmread(f).pixel_array for f in dicom_files]
volume = np.stack(slices, axis=0) # shape (N_slices, 512, 512)
print(f"3D volume shape: {volume.shape}")
DICOM Anonymization
DICOM files contain patient-identifying information that must be removed before sharing for research:
import pydicom
def anonymize_dicom(input_path, output_path):
ds = pydicom.dcmread(input_path)
# Remove or replace identifying tags
tags_to_clear = [
(0x0010, 0x0010), # PatientName
(0x0010, 0x0020), # PatientID
(0x0010, 0x0030), # PatientBirthDate
(0x0010, 0x0040), # PatientSex
(0x0010, 0x1010), # PatientAge
(0x0008, 0x0020), # StudyDate
(0x0008, 0x0030), # StudyTime
(0x0008, 0x0090), # ReferringPhysicianName
(0x0008, 0x1030), # StudyDescription
(0x0008, 0x103E), # SeriesDescription (optional — may carry diagnostic info)
]
for tag in tags_to_clear:
if tag in ds:
ds[tag].value = "ANONYMOUS"
# Remove burned-in annotation pixel data
ds.BurnedInAnnotation = "NO"
ds.save_as(output_path)
print(f"Anonymized: {output_path}")
anonymize_dicom("original.dcm", "anonymized.dcm")
For robust DICOM de-identification, use the DICOM PS 3.15 Appendix E profile — implemented in tools like dicom-anonymizer, dciodvfy, and Orthanc's de-identification plugin.
Converting DICOM to NIfTI for Neuroimaging
NIfTI (Neuroimaging Informatics Technology Initiative) is the standard format used by neuroimaging analysis software (FSL, FreeSurfer, SPM, ANTs, nilearn):
# dcm2niix — the gold standard DICOM → NIfTI converter
dcm2niix -o ./output/ -f "%p_%t_%s" -z y ./dicom_series/
# This produces:
# output/HeadCT_20240315_001.nii.gz (compressed NIfTI)
# output/HeadCT_20240315_001.json (BIDS sidecar with acquisition parameters)
dcm2niix correctly handles multi-frame DICOM, mosaic encoding (Siemens fMRI), and extracts diffusion gradient tables for DTI (b-values, b-vectors).
DICOM Viewing and PACS
- 3D Slicer: free, open-source medical image analysis platform — loads DICOM series, renders 3D volumes, performs segmentation
- OsiriX / Horos (macOS): PACS workstation with curved MPR and 3D rendering
- OHIF Viewer: web-based DICOM viewer via DICOMweb REST API (WADO-RS/STOW-RS)
- Orthanc: open-source DICOM server for building local PACS
- dwv: browser-based viewer (JavaScript) using pure web APIs
DICOM Transfer Syntaxes (Compression)
The Transfer Syntax UID determines how pixel data is compressed:
| UID | Name | Notes |
|---|---|---|
| 1.2.840.10008.1.2 | Implicit VR Little Endian | Original; no explicit type tags |
| 1.2.840.10008.1.2.1 | Explicit VR Little Endian | Most common uncompressed |
| 1.2.840.10008.1.2.4.70 | JPEG Lossless (process 14) | Lossless, widely supported |
| 1.2.840.10008.1.2.4.90 | JPEG 2000 Lossless | Better compression |
| 1.2.840.10008.1.2.4.91 | JPEG 2000 Lossy | Smaller files, may not be acceptable for diagnosis |
| 1.2.840.10008.1.2.5 | RLE Lossless | Run-length encoding |
Related conversions
Frequent conversions across the catalogue: