Medical Imaging AI

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.

On this page 6
  1. Why it exists
  2. How it works
  3. Where you have already seen it
  4. An honest warning
  5. Remember this
  6. What to learn next

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"   ->  black

The 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

Developer — Code and libraries.

Setup

bash
pip install pydicom numpy

pydicom 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

dicom_windowing.py
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")
Output
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_array returns 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.
  • RescaleSlope and RescaleIntercept come 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.clip is 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

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 Data

The 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 coefficient
  • mu_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-grey
  • width — 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