Convert DICOM
DICOM to JPG
Converts a single dicom file to an 8 bit format
Convert
#Code modified from Ian Pan https://storage.googleapis.com/kaggle-forum-message-attachments/1010629/17014/convert_to_jpeg_for_kaggle.py
def convert_ct_dicom_to_8bit(dicom_file, windows = [[350,40],[1500,-500],[120,70]], imsize=(256.,256.), should_remove_padding = True):
'''
Given a DICOM file, window specifications, and image size, return the
image as a Numpy array scaled to [0,255] of the specified size.
Parameters
----------
dicom_file: str
filename that ends in .dcm
windows: list of lists of ints
list of window width and window level values
imsize: tuplet of float
desired output image size
should_remove_padding: bool
if True will remove extra rows/columns of zeroes around the image
'''
array = apply_slope_intercept(dicom_file)
if should_remove_padding:
array = remove_padding(array)
#different width, level for each RGB channel
image = apply_windows(array, windows)
#resize
image = resize(image, imsize)
return image
Save as jpg
image = convert_ct_dicom_to_8bit(dicom_file, windows = [[350,40],[1500,-500],[120,70]], imsize=(256.,256.), should_remove_padding = True)
im = Image.fromarray(image)
im.save(dicom_file[-4:] + '.jpg')
Supporting functions
import pandas as pd
import numpy as np
import pydicom
from scipy.ndimage.interpolation import zoom
#Applies slope and intercept from DICOM tags
def apply_slope_intercept(dicom_file):
array = dicom_file.pixel_array.copy()
try:
slope = float(dicom_file.RescaleSlope)
intercept = float(dicom_file.RescaleIntercept)
except Exception:
slope = 1
intercept = 0
if slope != 1 or intercept != 0:
array = array * slope
array = array + intercept
return array
#Removes zeroes around image
def remove_padding(array):
array = array.copy()
nonzeros = np.nonzero(array)
x1 = np.min(nonzeros[0]) ; x2 = np.max(nonzeros[0])
y1 = np.min(nonzeros[1]) ; y2 = np.max(nonzeros[1])
return array[x1:x2,y1:y2]
#Apply different W/L settings to different channels to take advantage of RGB structure
def apply_windows(array, windows):
layers = []
for values in windows:
if len(value) >= 2:
ww = values[0]
wl = values[1]
layers.append(np.expand_dims(window(array, WL=wl, WW=ww), axis=3))
if len(layers) == 0:
return np.expand_dims(window(array, WL=350, WW=40), axis=3)
else:
return np.concatenate(layers, axis=3)
#Resize
def resize(image, imsize):
rat = max(imsize) / np.max(image.shape[1:])
return zoom(image, [1.,rat,rat,1.], prefilter=False, order=1)
Common window width and window level for CT exams
Target | WW | WL |
---|---|---|
brain | 80 | 40 |
subdural | 215 | 75 |
stroke_1 | 8 | 32 |
stroke_2 | 40 | 40 |
temporal_bone | 2800 | 600 |
neck_soft_tissue | 375 | 40 |
lung | 1500 | -500 |
emphysema | 800 | -800 |
mediastinum | 400 | 40 |
pulmonary_embolism | 700 | 100 |
abdomen | 350 | 40 |
liver | 120 | 70 |
kidney | 700 | 50 |
bone | 2500 | 480 |
DICOM to/from nifti
Convert CT nifti to DICOM
Use the convert_ct function in common_utils to convert nifti files to DICOM for upload to MD.ai. You'll need to choose your input and output directories. Optionally, you can change the plane or default window/level settings. You'll also need a sample dicom which you can download from sample image
results = mdai.common_utils.convert_ct(
input_dir=None,
output_dir=None,
input_ext=".nii.gz",
plane="axial",
sample_dicom_fp=os.path.join(os.path.dirname(""), "./sample_dicom.dcm"),
window_center=40,
window_width=350,
)
This function will write the converted DICOM files to the output directory and will give each image from a nifti file the same Study and Series UIDs. Use the CLI tool to upload the newly created DICOM images into your project
Convert DICOM to nifti
Use the dicom2nifiti library from icometrix
!pip install dicom2nifti
import dicom2nifti
dicom2nifti.convert_directory(dicom_directory, output_folder, compression=True, reorient=True)
This will convert the dicom files from the dicom_directory to the output_folder.
Support functions
DICOM UIDs and tags from your original files
Use this code on your original data to create dictionaries of the UIDs from the image filenames. You can also use this as a base for getting additional DICOM tags such as PatientPosition, SeriesDescription, InstanceNumber, etc.
from pathlib import Path
import pydicom as py
images_path = Path('MY_PATH')
original_fn = list(images_path.glob('**/*.dcm'))
file_dict_sop = dict()
file_dict_series = dict()
file_dict_study = dict()
for f in original_fn:
d = py.dcmread(str(f))
file_dict_sop[f] = d.SOPInstanceUID
file_dict_series[f] = d.SeriesInstanceUID
file_dict_study[f] = d.StudyInstanceUID