{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.7.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":36363,"databundleVersionId":4050810,"sourceType":"competition"}],"dockerImageVersionId":30213,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2024-05-09T08:05:10.120108Z","iopub.execute_input":"2024-05-09T08:05:10.121158Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<center style=\"font-family:verdana;\"><h1 style=\"font-size:200%; padding: 10px; background: #001f3f;\"><b style=\"color:orange;\">Cervical Spine Fracture Detection Using CNN</b></h1></center>","metadata":{}},{"cell_type":"markdown","source":"CT Cervical Spine Fracture Detection Using a Convolutional Neural Network\n\nAuthors: J E Small , P Osler , A B Paul , M Kunst \n\nPMCID: PMC8324280 -  DOI: 10.3174/ajnr.A7094\n\n\"Multidetector CT has emerged as the standard of care imaging technique to evaluate cervical spine trauma. The authors aim was to evaluate the performance of a convolutional neural network in the detection of cervical spine fractures on CT.\"\n\n\"Convolutional neural network accuracy in cervical spine fracture detection was 92% (95% CI, 90%-94%), with 76% (95% CI, 68%-83%) sensitivity and 97% (95% CI, 95%-98%) specificity. The radiologist accuracy was 95% (95% CI, 94%-97%), with 93% (95% CI, 88%-97%) sensitivity and 96% (95% CI, 94%-98%) specificity. Fractures missed by the convolutional neural network and by radiologists were similar by level and location and included fractured anterior osteophytes, transverse processes, and spinous processes, as well as lower cervical spine fractures that are often obscured by CT beam attenuation.\"\n\n\"The convolutional neural network holds promise at both worklist prioritization and assisting radiologists in cervical spine fracture detection on CT. Understanding the strengths and weaknesses of the convolutional neural network is essential before its successful incorporation into clinical practice. Further refinements in sensitivity will improve convolutional neural network diagnostic utility.\"\n\nhttps://pubmed.ncbi.nlm.nih.gov/34255730/","metadata":{}},{"cell_type":"markdown","source":"![](https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ5xd3DNujsAqBejEQ7ktJoOtupWeofGX87UPZwJjnADGJuXUped_jw-W05MhDXmUe-w6M&usqp=CAU)http://www.ajnr.org/content/early/2021/04/01/ajnr.A7094","metadata":{}},{"cell_type":"code","source":"import os\nimport sys \nfrom tqdm import tqdm\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nfrom PIL import Image\nimport pydicom\n\nimport numpy as np\nimport nibabel as nib\nimport matplotlib.pyplot as plt\nimport SimpleITK as sitk\n\n\ntrain_path = '../input/rsna-2022-cervical-spine-fracture-detection/train_images/'","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_dirs = os.listdir(train_path)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport json\nimport glob\nimport random\nimport collections\nimport numpy as np\nimport pandas as pd\nimport pydicom\nfrom pydicom.pixel_data_handlers.util import apply_voi_lut\nimport cv2\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nfrom matplotlib import animation, rc\nrc('animation', html='jshtml')\nfrom tqdm import tqdm","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Code by stpete_ishii https://www.kaggle.com/stpeteishii/siim-acr-dicom-slide-show/notebook?select=stage_2_images\n\nscans = !ls ../input/rsna-2022-cervical-spine-fracture-detection/train_images/1.2.826.0.1.3680043.10001/ -d\nprint(len(scans))\nprint(scans[0])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Code by stpete_ishii https://www.kaggle.com/stpeteishii/siim-acr-dicom-slide-show/notebook?select=stage_2_images\n\nfiles=os.listdir('../input/rsna-2022-cervical-spine-fracture-detection/train_images/1.2.826.0.1.3680043.10001')\nprint(len(files))\nn=len(files)\nN=[]\nfor i in range(n//10):\n    N+=[i*10]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Code by stpete_ishii https://www.kaggle.com/stpeteishii/siim-acr-dicom-slide-show/notebook?select=stage_2_images\n\n\ndef load_dicom(path):\n    dicom=pydicom.read_file(path,force=True)\n    data=dicom.pixel_array\n    data=data-np.min(data)\n    if np.max(data) != 0:\n        data=data/np.max(data)\n    data=(data*255).astype(np.uint8)\n    return data","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Code by stpete_ishii https://www.kaggle.com/stpeteishii/siim-acr-dicom-slide-show/notebook?select=stage_2_images\n\ndef load_dicom_line(path):\n    t_paths = sorted(\n        glob.glob(os.path.join(path,\"*\")), \n        key=lambda x: x[:-4].split(\"_\")[-1],\n    )\n    images = []\n    for filename in tqdm(np.array(t_paths)[N]):\n        data = load_dicom(filename)\n        if data.max() == 0:\n            continue\n        images.append(data)\n        \n    return images","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Code by stpete_ishii https://www.kaggle.com/stpeteishii/siim-acr-dicom-slide-show/notebook?select=stage_2_images\n\ndef create_animation(ims):\n    fig=plt.figure(figsize=(7,7))\n    plt.axis('off')\n    im=plt.imshow(ims[0],cmap=\"gray\")\n\n    def animate_func(i):\n        im.set_array(ims[i])\n        return [im]\n\n    return animation.FuncAnimation(fig, animate_func, frames=len(ims), interval=1000)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"images = load_dicom_line(scans[0])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Code by stpete_ishii https://www.kaggle.com/stpeteishii/siim-acr-dicom-slide-show/notebook?select=stage_2_images\n\ncreate_animation(images)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install fastai","metadata":{"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install pydicom","metadata":{"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import warnings\nwarnings.filterwarnings(\"ignore\", category=DeprecationWarning)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import pydicom\nfrom fastai.vision.all import *\nfrom fastai.medical.imaging import *\n\ntry:\n    import cv2\n    cv2.setNumThreads(0)\nexcept: pass\n\nimport seaborn as sns\nsns.set(style=\"whitegrid\")\nsns.set_context(\"paper\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install scikit-image","metadata":{"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pip install kornia===0.2.0","metadata":{"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"source = '../input/rsna-2022-cervical-spine-fracture-detection'","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Code by Amrit Virdee  https://www.kaggle.com/avirdee/rsna-miccai-initial-fmi-fastai/notebook\n\nmri = '../input/rsna-2022-cervical-spine-fracture-detection'\ntrain_files = get_dicom_files(f'{source}/train_images')\nlabels = pd.read_csv(f'{source}/train_bounding_boxes.csv')\nprint(os.listdir(source))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#get dicom files\nitems = get_dicom_files(mri, recurse=True, folders='train_images')\nitems","metadata":{"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"Sample_DCM = Path('../input/rsna-2022-cervical-spine-fracture-detection/train_images/1.2.826.0.1.3680043.10001/104.dcm')\ndcm = Sample_DCM.dcmread()\ndcm","metadata":{"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"type(dcm)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dcm.pixels","metadata":{"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#None\n\nscaled_px uses RescaleSlope and RescaleIntercept values to correctly scale the image so that they represent the correct tissue densities.\n\nHistogram. DCM Pixels","metadata":{}},{"cell_type":"code","source":"plt.hist(dcm.pixels.flatten().numpy());","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#Histogram DCM scaled","metadata":{}},{"cell_type":"code","source":"plt.hist(dcm.scaled_px.flatten().numpy());","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"t_bin = dcm.pixels.freqhist_bins(n_bins=1)\nt_bin","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#Tensor.freqhist_bins\n\nA function to split the range of pixel values into groups, such that each group has around the same number of pixels.\n\nThough I have no clue about the importance for the Cervical Fracture","metadata":{}},{"cell_type":"code","source":"plt.hist(t_bin.numpy(), bins=t_bin, color='c')\nplt.plot(t_bin, torch.linspace(0,1,len(t_bin)));","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#With n_bins at 100","metadata":{}},{"cell_type":"code","source":"t_bin = dcm.pixels.freqhist_bins(n_bins=100)\nt_bin","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.hist(t_bin.numpy(), bins=t_bin, color='c'); plt.plot(t_bin, torch.linspace(0,1,len(t_bin)));","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.hist(dcm.pixels.flatten().numpy(), bins=100);","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#Tensor.hist_scaled\n\nScales a tensor using freqhist_bins to values between 0 and 1\n\nThe test image has pixel values that range between -1000 and 2500","metadata":{}},{"cell_type":"code","source":"tensor_hists = dcm.pixels.hist_scaled()\nplt.hist(tensor_hists.flatten().numpy(), bins=100);","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#Dataset.hist_scaled\n\nDataset.hist_scaled(brks=None, min_px=None, max_px=None)\n\nPixels scaled to a min_px and max_px value","metadata":{}},{"cell_type":"code","source":"data_scaled = dcm.hist_scaled()\nplt.imshow(data_scaled, cmap=plt.cm.bone);","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data_scaled = dcm.hist_scaled(min_px=100, max_px=1000)\nplt.imshow(data_scaled, cmap=plt.cm.bone);","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#Voxel Values\n\nDicom images can contain a high amount of voxel values and windowing can be thought of as a means of manipulating these values in order to change the apperance of the image so particular structures are highlighted. A window has 2 values:\n\nl = window level or center aka brightness\n\nw = window width or range aka contrast","metadata":{}},{"cell_type":"markdown","source":"#Dataset.windowed\n\nDataset.windowed(w, l)","metadata":{}},{"cell_type":"code","source":"plt.imshow(dcm.windowed(*dicom_windows.brain), cmap=plt.cm.bone);","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#Dataset.show\n\nDataset.show(frames=1, scale=True, cmap=<matplotlib.colors.LinearSegmentedColormap object at 0x7f1cb02ce6a0>, min_px=-1100, max_px=None, **kwargs)\n\nAdds functionality to view dicom images where each file may have more than 1 frame.","metadata":{}},{"cell_type":"code","source":"scales = False, True, dicom_windows.brain, dicom_windows.subdural\ntitles = 'raw','normalized','brain windowed','subdural windowed'\nfor s,a,t in zip(scales, subplots(2,2,imsize=4)[1].flat, titles):\n    dcm.show(scale=s, ax=a, title=t)","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#I don't know if the titles above are correct","metadata":{}},{"cell_type":"code","source":"dcm.show(cmap=plt.cm.gist_ncar, figsize=(6,6))","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dcm.show()","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#Dataset.pct_in_window\n\nDataset.pct_in_window(dcm:Dataset, w, l)\n\n% of pixels in the window (w,l)","metadata":{}},{"cell_type":"code","source":"dcm.pct_in_window(*dicom_windows.brain)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#uniform_blur2d\n\nuniform_blur2d(x, s)\n\nUniformly apply blurring","metadata":{}},{"cell_type":"code","source":"ims = dcm.hist_scaled(), uniform_blur2d(dcm.hist_scaled(), 20), uniform_blur2d(dcm.hist_scaled(), 50)\nshow_images(ims, titles=('original', 'blurred 20', 'blurred 50'))","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#gauss_blur2d\n\n\ngauss_blur2d(x, s)\n\nApply gaussian_blur2d kornia filter","metadata":{}},{"cell_type":"code","source":"ims = dcm.hist_scaled(), gauss_blur2d(dcm.hist_scaled(), 20), gauss_blur2d(dcm.hist_scaled(), 50)\nshow_images(ims, titles=('original', 'gauss_blur 20', 'gauss_blur 50'))","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#Tensor.mask_from_blur\n\nTensor.mask_from_blur(x:Tensor, window, sigma=0.3, thresh=0.05, remove_max=True)\n\nCreate a mask from the blurred image\n\nDataset.mask_from_blur\nDataset.mask_from_blur(x:Dataset, window, sigma=0.3, thresh=0.05, remove_max=True)\n\nCreate a mask from the blurred image.","metadata":{}},{"cell_type":"code","source":"mask = dcm.mask_from_blur(dicom_windows.brain, sigma=0.9, thresh=0.1, remove_max=True)\nwind = dcm.windowed(*dicom_windows.brain)\n\n_,ax = subplots(1,3)\nshow_image(wind, ax=ax[0], title='window')\nshow_image(mask, alpha=0.5, cmap=plt.cm.Reds, ax=ax[1], title='mask')\nshow_image(wind, ax=ax[2])\nshow_image(mask, alpha=0.5, cmap=plt.cm.Reds, ax=ax[2], title='window and mask');","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#mask2bbox\n\nmask2bbox(mask)","metadata":{}},{"cell_type":"code","source":"bbs = mask2bbox(mask)\nlo,hi = bbs\nshow_image(wind[lo[0]:hi[0],lo[1]:hi[1]]);","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#crop_resize\n\ncrop_resize(x, crops, new_sz)","metadata":{}},{"cell_type":"code","source":"px256 = crop_resize(to_device(wind[None]), bbs[...,None], 128)[0]\nshow_image(px256)\npx256.shape","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#Comparing the original image with the image from using the mask and crop_resize function","metadata":{}},{"cell_type":"code","source":"_,axs = subplots(1,2)\ndcm.show(ax=axs[0])\nshow_image(px256, ax=axs[1]);","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#Tensor.to_nchan\n\nTensor.to_nchan(x:Tensor, wins, bins=None)\n\n#Dataset.to_nchan\n\nDataset.to_nchan(x:Dataset, wins, bins=None)\n\nto_nchan takes a tensor or a dicom as the input and returns multiple one channel images (the first depending on the choosen windows and a normalized image). Setting bins to 0 only returns the windowed image.","metadata":{}},{"cell_type":"code","source":"show_images(dcm.to_nchan([dicom_windows.brain], bins=0))","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#Tensor.to_3chan\n\nTensor.to_3chan(x:Tensor, win1, win2, bins=None)\n\nDataset.to_3chan\nDataset.to_3chan(x:Dataset, win1, win2, bins=None)","metadata":{}},{"cell_type":"code","source":"show_images(dcm.to_nchan([dicom_windows.brain], bins=None))","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#Tensor.to_3chan\n\nTensor.to_3chan(x:Tensor, win1, win2, bins=None)\n\n#Dataset.to_3chan\n\nDataset.to_3chan(x:Dataset, win1, win2, bins=None)","metadata":{"_kg_hide-input":true}},{"cell_type":"code","source":"show_images(dcm.to_nchan([dicom_windows.brain,dicom_windows.subdural,dicom_windows.abdomen_soft]))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#Dataset.save_tif16\n\nDataset.save_tif16(x:Dataset'>), path, bins=None, compress=True)\n\nSave tensor or dicom image into tiff format.","metadata":{}},{"cell_type":"code","source":"_,axs=subplots(1,2)\nwith tempfile.TemporaryDirectory() as f:\n    f = Path(f)\n    dcm.save_jpg(f/'test.jpg', [dicom_windows.brain,dicom_windows.subdural])\n    show_image(Image.open(f/'test.jpg'), ax=axs[0])\n    dcm.save_tif16(f/'test.tif')\n    show_image(Image.open(str(f/'test.tif')), ax=axs[1]);","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#Dataset.set_pixels","metadata":{}},{"cell_type":"code","source":"dcm.pixel_array.shape","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#Dataset.zoom\n\nDataset.zoom(ratio)\n\nZoom image by specified ratio\n\nCheck to see the current size of the dicom image","metadata":{}},{"cell_type":"code","source":"dcm.zoom(7.0)\ndcm.show(); dcm.pixel_array.shape","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#Dataset.zoom_to\n\nDataset.zoom_to(sz)\n\nChange image size to specified pixel size","metadata":{}},{"cell_type":"code","source":"dcm.zoom_to(200); dcm.pixel_array.shape","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"TEST_DCM = Path('../input/rsna-2022-cervical-spine-fracture-detection/train_images/1.2.826.0.1.3680043.10001/113.dcm')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dcm2 = TEST_DCM.dcmread()\ndcm2.zoom_to(90)\ntest_eq(dcm2.shape, (90,90))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dcm2 = TEST_DCM.dcmread()\ndcm2.zoom(0.25)\ndcm2.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#Acknowledgemnts:\n\nFastai Medical Imaging. Helpers for working with DICOM files\nhttps://docs.fast.ai/medical.imaging.html#Dataset.set_pixels\n\nAmrit Virdee  https://www.kaggle.com/avirdee/rsna-miccai-initial-fmi-fastai/notebook\n\nstpete_ishii for the script https://www.kaggle.com/stpeteishii/siim-acr-dicom-slide-show/notebook?select=stage_2_images","metadata":{}}]}