DICOM, windowing and image intensity
A medical scan is not a photograph — its pixels store a physical measurement, and you choose which slice of that range to actually look at.
- 9 min read
- 3 reading levels
- Published
Read these first
On this page 6
One lesson, three depths. Pick the one that fits you today — you can switch any time.
Beginner — No maths. Plain English.
A CT or MRI scan stores a measurement at every pixel, not a color.
Think about a thermometer with far more markings than you need at once. A weather thermometer shows minus-twenty to fifty degrees. A cooking thermometer shows zero to three hundred.
Both measure temperature. Each one is built to show the range that actually matters for its job. A CT scan works the same way — one wide measurement, viewed through a chosen range.
Why it exists
A phone photo stores brightness from 0 to 255. That is the whole range, forever fixed.
A CT scanner measures something different: how much X-ray each tissue blocks. Bone blocks a lot. Air blocks almost none. That range is far wider than 0 to 255. Bone, soft tissue, and air are wildly different things.
Cramming that whole wide range onto one screen would wash out most of the detail. A radiologist would see bone brightly, but lose all the soft-tissue detail in the middle. So instead, a window is chosen: a narrower range, picked for the tissue being studied. It gets stretched to fill the visible brightness scale.
DICOM stands for Digital Imaging and Communications in Medicine. It is the file format that carries all of this — the measurements, the patient information, and the scanner's own settings.
How it works
Raw scanner value -> real physical measurement -> choose a window -> image on screen
2191 -> +1167 (dense bone) -> "bone window" -> bright
128 -> -896 (air / lung) -> "soft tissue" -> blackThe same scan, viewed through two different windows, can look like two different images. The tissue you care about depends on the question being asked.
Where you have already seen it
- A radiology report photo you have seen online usually shows one chosen window, not the raw scan.
- A weather map does something similar — the same temperature data, colored differently for a heat-wave map versus a frost-warning map.
An honest warning
Picking the wrong window can hide a real finding, even though the data was captured correctly. The measurement was always there. The chosen view was not showing it.
This is why radiologists routinely scroll through several windows on the same scan, not only one. A single screenshot can miss what a full review would catch.
Any model trained on this data still needs a radiologist's review, before it plays any role in real patient care.
Remember this
- A scan pixel stores a physical measurement, not a display-ready color.
- A window is a chosen range, stretched to fill the visible brightness scale.
- The same raw scan can look completely different depending on which window is used.
What to learn next
- How images are stored in a computer — the general version of pixels and brightness this lesson builds on.
- Segmenting 3D scans — what happens once a whole stack of these images needs labelling.
- Image classification — where a model eventually gets applied to images prepared this way.
Developer — Code and libraries.
Setup
pip install pydicom numpypydicom is the standard Python library for reading DICOM files, and it ships a handful of real, de-identified sample scans for exactly this kind of testing — no download needed.
Minimal runnable code
import numpy as np
import pydicom
from pydicom.data import get_testdata_file
path = get_testdata_file("CT_small.dcm")
ds = pydicom.dcmread(path)
raw = ds.pixel_array.astype(np.int16)
print(f"modality: {ds.Modality}, image size: {raw.shape}")
print(f"raw pixel values range from {raw.min()} to {raw.max()}")
# The scanner does not store Hounsfield Units directly. It stores a raw
# number that needs this formula, taken straight from the file's own tags.
slope = float(ds.RescaleSlope)
intercept = float(ds.RescaleIntercept)
hu = raw * slope + intercept
print(f"in Hounsfield Units, this ranges from {hu.min():.0f} to {hu.max():.0f}")
def apply_window(image_hu, center, width):
low, high = center - width / 2, center + width / 2
clipped = np.clip(image_hu, low, high)
return (clipped - low) / (high - low) # scaled to 0-1 for display
# "Soft tissue" window: the range radiologists use to read organs and muscle.
soft_tissue = apply_window(hu, center=40, width=400)
# "Bone" window: a much wider, brighter range, tuned for dense bone.
bone = apply_window(hu, center=400, width=1800)
print(f"soft-tissue window keeps HU {40-400//2} to {40+400//2}; "
f"{(soft_tissue == 0).mean():.1%} of pixels clip to pure black")
print(f"bone window keeps HU {400-1800//2} to {400+1800//2}; "
f"{(bone == 0).mean():.1%} of pixels clip to pure black")modality: CT, image size: (128, 128) raw pixel values range from 128 to 2191 in Hounsfield Units, this ranges from -896 to 1167 soft-tissue window keeps HU -160 to 240; 23.0% of pixels clip to pure black bone window keeps HU -500 to 1300; 21.4% of pixels clip to pure black
What actually happened
The raw pixel values (128 to 2191) mean nothing physical on their own — they are whatever numbers this particular scanner happened to store. RescaleSlope and RescaleIntercept, both read straight from the file, convert them into Hounsfield Units (HU), a standardised physical scale where 0 is water, roughly -1000 is air, and dense bone sits above 700.
The two windows then each keep a different slice of that same HU range. Almost a quarter of pixels clip to pure black under the soft-tissue window — mostly air and low-density regions that window was never meant to show.
Line by line, the parts that are not obvious:
ds.pixel_arrayreturns the raw stored values, not Hounsfield Units — the rescale step is a separate, required operation, and skipping it is a common source of visibly wrong images.RescaleSlopeandRescaleInterceptcome from the DICOM file itself, tag(0028,1053)and(0028,1052). They are not universal constants — every scanner and every file can set them differently.np.clipis what makes a window a window: every value outside the chosen range gets pushed to one of the two edges, rather than shown as-is.
Common mistakes
Training a model on raw pixel values instead of Hounsfield Units. Two scanners can store the same tissue as different raw numbers, while agreeing perfectly once converted to HU. Skipping the conversion quietly bakes in a scanner-specific bias.
Applying one fixed window to every case. A window chosen for a chest CT can hide the exact finding a brain CT needs. The right window depends on what is being looked for, not on convenience.
Assuming a display window changes the underlying data. It never does. Windowing only changes what is shown, not what is stored — the full HU range stays in the file no matter which window is displayed.
Try it yourself
Add a "lung window" — center -600, width 1500 — and print what fraction of pixels clip to black under it, compared to the soft-tissue and bone windows already shown.
What to learn next
- How images are stored in a computer — the general pixel and brightness concepts this lesson specialises.
- Segmenting 3D scans — stacking many of these 2D slices into one volume.
- Datasets that do not fit in memory — relevant once a study's worth of DICOM files needs loading at scale.
Researcher — Mathematics and papers.
The DICOM data model
A DICOM file is a sequence of tags, each identified by a (group, element) hexadecimal pair, holding either patient/study metadata or the pixel data itself:
(0010,0010) Patient Name
(0028,0010) Rows
(0028,0011) Columns
(0028,1052) Rescale Intercept
(0028,1053) Rescale Slope
(7FE0,0010) Pixel DataThe transfer syntax UID, also stored as a tag, declares how the pixel data itself is encoded — uncompressed, or with a specific compression codec (JPEG, JPEG 2000, RLE). A reader must consult this tag before it can safely decode the pixel data at all.
Hounsfield Units
The Hounsfield scale (Hounsfield, 1973) is defined relative to the linear X-ray attenuation coefficient μ of the imaged material against water:
HU = 1000 * (mu - mu_water) / (mu_water - mu_air)mu— the material's linear attenuation coefficientmu_water,mu_air— the attenuation coefficients of water and air, the scale's two fixed reference points
By construction, water is defined as exactly 0 HU and air as approximately -1000 HU. The scanner's raw output is converted to this standardised scale via the per-file affine transform shown in the developer block: HU = raw * RescaleSlope + RescaleIntercept.
Windowing, formally
A window is a linear remap from a chosen HU interval to display intensity:
display(x) = clip( (x - (center - width/2)) / width, 0, 1 )center— the window level (WL), the HU value mapped to mid-greywidth— the window width (WW), the total HU range mapped to the full display range
DICOM files may carry default WindowCenter/WindowWidth tags (0028,1050)/(0028,1051) set by the scanner, but clinical viewers routinely override these with standard presets per body region and clinical question, since no single default window serves every diagnostic purpose.
Cost and scale
A single-slice 512x512 CT image at 16-bit depth is 512 KB uncompressed. A modern CT study commonly contains several hundred slices, putting a single study in the range of hundreds of megabytes before any compression — a scale factor that motivates the tiling and patch-based approaches covered in gigapixel pathology slides and the memory-management approaches in segmenting 3D scans.
Key references
- Hounsfield, G. (1973). Computerized transverse axial scanning (tomography): Part 1. Description of system. British Journal of Radiology 46(552). The original CT paper defining the scale that bears his name.
- NEMA PS3 (2023). Digital Imaging and Communications in Medicine (DICOM) Standard. The full, freely available standard specification.
- Mason, D. (2011). SU-E-T-33: Pydicom: An Open Source DICOM Library. Medical Physics 38(6). The library used in the developer block above.
Current state
DICOM remains the universal interchange format for clinical imaging, and no serious alternative has displaced it. Most modern deep learning pipelines convert DICOM to a simpler array format (NIfTI for volumes, or plain NumPy arrays) early in preprocessing, keeping only the metadata needed for the task — an engineering trade-off between DICOM's completeness and the simplicity a training pipeline needs.
What to learn next
- How images are stored in a computer — the general representation this lesson extends into the clinical domain.
- Segmenting 3D scans — moving from one windowed slice to a full volume.
- Reconstructing scans with learned priors — what happens even earlier, before a Hounsfield Unit is assigned at all.