from fastai.vision.all import *
from fastai.medical.imaging import *
from torchvision.utils import save_image
matplotlib.rcParams['image.cmap'] = 'bone'

from fmi.explore import *
from fmi.pipeline import *

System Info

system_info is a quick and convenient way of relevant information about what version of fastai, fastcore, torch, pydicom, kornia cuda and what gpu you are using

system_info[source]

system_info()

system_info()
fastai Version: 2.1.5
fastcore Version: 1.3.6
python Version: 3.7.9 (default, Aug 31 2020, 17:10:11) [MSC v.1916 64 bit (AMD64)]
torchvision: 0.8.1
torch version: 1.7.0

Cuda: True
cuda Version: 11.0
GPU: GeForce GTX 1060

pydicom Version: 2.1.1
kornia Version: 0.2.0

Instance Sort

Many dicom datasets have multiple slices of images for the same patient. For example with this dataset each folder represents a single patient and each folder can have multiple slices.

Note: View sort tutorial on Kaggle (click on Kaggle icon)

kaggle

s = 'D:/Datasets/osic-pulmonary-fibrosis-progression/train/'
sort_items = get_dicom_files(s, folders='ID00007637202177411956430')
sort_items
(#30) [Path('D:/Datasets/osic-pulmonary-fibrosis-progression/train/ID00007637202177411956430/1.dcm'),Path('D:/Datasets/osic-pulmonary-fibrosis-progression/train/ID00007637202177411956430/10.dcm'),Path('D:/Datasets/osic-pulmonary-fibrosis-progression/train/ID00007637202177411956430/11.dcm'),Path('D:/Datasets/osic-pulmonary-fibrosis-progression/train/ID00007637202177411956430/12.dcm'),Path('D:/Datasets/osic-pulmonary-fibrosis-progression/train/ID00007637202177411956430/13.dcm'),Path('D:/Datasets/osic-pulmonary-fibrosis-progression/train/ID00007637202177411956430/14.dcm'),Path('D:/Datasets/osic-pulmonary-fibrosis-progression/train/ID00007637202177411956430/15.dcm'),Path('D:/Datasets/osic-pulmonary-fibrosis-progression/train/ID00007637202177411956430/16.dcm'),Path('D:/Datasets/osic-pulmonary-fibrosis-progression/train/ID00007637202177411956430/17.dcm'),Path('D:/Datasets/osic-pulmonary-fibrosis-progression/train/ID00007637202177411956430/18.dcm')...]

In this example there are 30 images within the folder. To view them:

imgs = []
for filename in sort_items:
    file = dcmread(filename).pixel_array
    img = TensorDicom(file)
    imgs.append(img)
show_images(imgs, nrows=3)

We notice that the images are not in sequence. Dicoms typically have an InstanceNumber which can be used to display the images in sequence.

def instance_sort(folder:(Path, L)):
    "Helper to sort files by instance number"
    if isinstance(folder, Path): folder = get_dicom_files(folder)
    if isinstance(folder, L): folder = folder
    sorted_files = []
    for file in folder:
        instance = dcmread(file)[0x20, 0x13].value
        sorted_files.append([instance, file])
    return L(sorted(sorted_files))

instance_sort[source]

instance_sort(folder:L'>))

Helper to sort files by instance number

def instance_dcmread(folder:(L)):
    "instance dcmread"
    file = [dcmread(o[1]) for o in folder]
    return file

instance_dcmread[source]

instance_dcmread(folder:L)

instance dcmread

def instance_show(folder: (L), nrows=1):
    "Helper to display sorted files by instance number"
    f_list = []; t_list = []
    for file in instance_sort(folder):
        f = TensorDicom(dcmread(file[1]).pixel_array)
        f_list.append(f); t_list.append(file[0])
    return show_images(f_list, titles=t_list, nrows=nrows)

instance_show[source]

instance_show(folder:L, nrows=1)

Helper to display sorted files by instance number

We can simply view the images in sequence by using instance_show

instance_show(sort_items, nrows=3)

View images

fastai has a handy method from.dicoms that can access dicom metadata and display this in a dataframe.

m_items = get_dicom_files('D:/Datasets/osic-pulmonary-fibrosis-progression/train/ID00007637202177411956430')
source = 'D:/Datasets/osic-pulmonary-fibrosis-progression/train/'
dicom_dataframe = pd.DataFrame.from_dicoms(m_items)
dicom_dataframe[:2]
SpecificCharacterSet ImageType SOPInstanceUID Modality Manufacturer ManufacturerModelName PatientName PatientID PatientSex DeidentificationMethod ... ImageOrientationPatient3 ImageOrientationPatient4 ImageOrientationPatient5 MultiPixelSpacing PixelSpacing1 img_min img_max img_mean img_std img_pct_window
0 ISO_IR 100 ORIGINAL 2.25.12297650151329871895440507938349160734 CT GE MEDICAL SYSTEMS LightSpeed VCT (I, D, 0, 0, 0, 0, 7, 6, 3, 7, 2, 0, 2, 1, 7, 7, 4, 1, 1, 9, 5, 6, 4, 3, 0) ID00007637202177411956430 Table; ... 0.0 1.0 0.0 1 0.652344 -2000 2842 -1.454884 1137.488858 0.058094
1 ISO_IR 100 ORIGINAL 2.25.37611372879908126511187998276199853341 CT GE MEDICAL SYSTEMS LightSpeed VCT (I, D, 0, 0, 0, 0, 7, 6, 3, 7, 2, 0, 2, 1, 7, 7, 4, 1, 1, 9, 5, 6, 4, 3, 0) ID00007637202177411956430 Table; ... 0.0 1.0 0.0 1 0.652344 -2000 2918 19.038597 1138.876560 0.068130

2 rows × 67 columns

def get_dicom_image(df, key, nrows=3, source=None):
    "Helper to view images by key"
    imgs=[]
    title=[]
    for i in df.index:
        file_path = f"{source}/{df.iloc[i]['PatientID']}/{df.iloc[i]['InstanceNumber']}.dcm"
        dcc = dcmread(file_path).pixel_array
        imgs.append(dcc)
        pct = df.iloc[i][key]
        title.append(pct)
    return show_images(imgs, titles=title, nrows=nrows)

get_dicom_image[source]

get_dicom_image(df, key, nrows=3, source=None)

Helper to view images by key

get_dicom_image easily allows to view images based on the chosen dataframe key. For example we can reduce the dataframe created earlier.

pct = dicom_dataframe[['PatientID', 'InstanceNumber', 'img_pct_window', 'img_mean', 'img_std']].sort_values(by=['img_pct_window'], ascending=False).reset_index(drop=True)
pct[:5]
PatientID InstanceNumber img_pct_window img_mean img_std
0 ID00007637202177411956430 20 0.077923 109.478535 1174.014672
1 ID00007637202177411956430 21 0.075516 127.095284 1182.195403
2 ID00007637202177411956430 29 0.075508 210.377762 1217.328780
3 ID00007637202177411956430 18 0.075157 97.442841 1172.540524
4 ID00007637202177411956430 28 0.075096 212.950813 1219.356338

View images by img_pct_window

get_dicom_image(pct[:30], 'img_pct_window', source=source) 

View by img_mean

mean = dicom_dataframe[['PatientID', 'InstanceNumber', 'img_pct_window', 'img_mean', 'img_std']].sort_values(by=['img_mean'], ascending=False).reset_index(drop=True)
mean[:5]
PatientID InstanceNumber img_pct_window img_mean img_std
0 ID00007637202177411956430 26 0.074780 216.025375 1223.787277
1 ID00007637202177411956430 27 0.074970 215.649502 1221.412337
2 ID00007637202177411956430 28 0.075096 212.950813 1219.356338
3 ID00007637202177411956430 29 0.075508 210.377762 1217.328780
4 ID00007637202177411956430 25 0.073563 208.641216 1222.713558
get_dicom_image(mean[:30], 'img_mean', source=source)