CT
fpc.ct
ct.py - computed tomography: Hounsfield units, windowing, and dose metrics.
A CT scanner measures linear attenuation coefficients; the Hounsfield scale re-expresses them relative to water so that water = 0 HU and air = -1000 HU. A CT image spans ~4000 HU, but a monitor shows ~256 grey levels and the eye far fewer, so radiologists choose a WINDOW (a slice of the HU range) to display. This module does both steps with NumPy, so it works on a single number or on a whole 512 x 512 image in one call (vectorization).
CT
Computed-tomography image and dose calculations.
Source code in fpc/ct.py
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | |
hounsfield_units(*, attenuation_coefficient, water_attenuation, air_attenuation=0.0)
Convert a linear attenuation coefficient to Hounsfield units.
HU = 1000 * (mu - mu_water) / (mu_water - mu_air)
Works element-wise on NumPy arrays as well as single numbers.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
attenuation_coefficient
|
tissue mu [1/cm] (number or array) |
required | |
water_attenuation
|
mu of water at the same beam energy [1/cm] |
required | |
air_attenuation
|
mu of air [1/cm]; ~0 so it defaults to 0 |
0.0
|
Returns:
| Type | Description |
|---|---|
|
CT number [HU] |
Source code in fpc/ct.py
46 47 48 49 50 51 52 53 54 55 56 57 58 59 | |
rescale_to_hounsfield(*, stored_values, rescale_slope=1.0, rescale_intercept=-1024.0)
Convert raw stored pixel values to HU: HU = value * slope + intercept.
DICOM files usually store unsigned integers; the RescaleSlope and
RescaleIntercept tags (0028,1053 / 0028,1052) say how to recover HU.
Forgetting this step is a classic beginner bug: every value is off by
~1024. See :class:fpc.dicom.Dicom for reading these from a file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
stored_values
|
raw pixel values (number or array) |
required | |
rescale_slope
|
DICOM RescaleSlope |
1.0
|
|
rescale_intercept
|
DICOM RescaleIntercept |
-1024.0
|
Returns:
| Type | Description |
|---|---|
|
values in HU (float array) |
Source code in fpc/ct.py
61 62 63 64 65 66 67 68 69 70 71 72 73 74 | |
window_bounds(*, window_width=None, window_level=None, preset=None)
Lowest and highest HU shown by a window.
Anything below level - width/2 displays black, anything above
level + width/2 displays white. Pass either width AND level, or a
preset name from :attr:WINDOW_PRESETS.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
window_width
|
window width W [HU] |
None
|
|
window_level
|
window level / centre L [HU] |
None
|
|
preset
|
optional preset name, e.g. "lung" |
None
|
Returns:
| Type | Description |
|---|---|
|
tuple (lower HU, upper HU) |
Source code in fpc/ct.py
76 77 78 79 80 81 82 83 84 85 86 87 88 89 | |
apply_window(*, hounsfield, window_width=None, window_level=None, preset=None, output_max=255)
Map HU values to display grey levels for a chosen window.
Values are clipped to the window, then scaled linearly to 0..output_max. A narrow window (brain, W=80) spreads a small HU range over all grey levels -> high contrast; a wide window (bone, W=1800) shows everything but with low contrast.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
hounsfield
|
HU value or array (e.g. a full CT slice) |
required | |
window_width
|
window width W [HU] |
None
|
|
window_level
|
window level L [HU] |
None
|
|
preset
|
optional preset name instead of width/level |
None
|
|
output_max
|
brightest grey level (255 for 8-bit display) |
255
|
Returns:
| Type | Description |
|---|---|
|
numpy array of grey levels (uint8 when output_max == 255) |
Source code in fpc/ct.py
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | |
classify_hounsfield(*, hounsfield)
Return a rough tissue label for a single HU value (teaching aid).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
hounsfield
|
CT number [HU] |
required |
Returns:
| Type | Description |
|---|---|
|
label string from :attr: |
Source code in fpc/ct.py
121 122 123 124 125 126 127 128 129 130 | |
dose_length_product(*, ctdi_vol_mgy, scan_length_cm)
Dose-length product DLP = CTDIvol * scan length [mGy*cm].
CTDIvol is the average dose within one slice of a standard phantom; DLP multiplies by how much of the patient was scanned. Both appear on every scanner's dose report.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ctdi_vol_mgy
|
volume CT dose index [mGy] |
required | |
scan_length_cm
|
irradiated scan length [cm] |
required |
Returns:
| Type | Description |
|---|---|
|
DLP [mGy*cm] |
Source code in fpc/ct.py
132 133 134 135 136 137 138 139 140 141 142 143 | |
effective_dose_from_dlp(*, dlp_mgy_cm, region)
Estimate adult effective dose: E ~= k * DLP.
Example: a routine head CT with DLP ~ 1000 mGy*cm gives ~2 mSv.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dlp_mgy_cm
|
dose-length product [mGy*cm] |
required | |
region
|
key of :attr: |
required |
Returns:
| Type | Description |
|---|---|
|
effective dose estimate [mSv] |
Source code in fpc/ct.py
156 157 158 159 160 161 162 163 164 165 166 167 168 169 | |