{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Locating Cervical Scans\n\nThis notebook focuses on spatial positioning of the scans, and *maybe* be able to identify each section of the cervical spine by their position.\n\n![Drag Racing](https://storage.googleapis.com/kaggle-competitions/kaggle/36363/logos/header.png?t=2022-07-2)","metadata":{}},{"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\nimport matplotlib.pyplot as plt\nfrom glob import glob\nimport pydicom\nfrom pydicom.pixel_data_handlers.util import apply_voi_lut\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,"execution":{"iopub.status.busy":"2022-07-30T02:42:55.274063Z","iopub.execute_input":"2022-07-30T02:42:55.274461Z","iopub.status.idle":"2022-07-30T02:42:55.410609Z","shell.execute_reply.started":"2022-07-30T02:42:55.274428Z","shell.execute_reply":"2022-07-30T02:42:55.409453Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Medical scans operate on defined planes for referencing.\n\nThe DICOM images are in the Axial plane, which means the scans operate on a Z axis, head to feet.\n\nSagittal operates left to right, as a X axis, and Coronal operates front to back, as Y axis\n\nThe following image shows from left to right: Sagittal plane, Coronal plane, Axial plane\n\n![Drag Racing](https://www.researchgate.net/profile/Yancarlos-Ramos-Villegas/publication/334285265/figure/fig2/AS:778069900029952@1562517728335/Figura-2-A-B-y-C-TAC-de-craneo-simple-Corte-Sagital-coronal-y-axial-que-evidencia.png)","metadata":{}},{"cell_type":"markdown","source":"What we will do in this notebook is try to properly order and locate each scan in the planes","metadata":{}},{"cell_type":"markdown","source":"# Organizing the data","metadata":{}},{"cell_type":"markdown","source":"Function to read the DICOM images and retrieve the metadata in them\n\nProps to this notebook for the helper funciton: https://www.kaggle.com/code/ipythonx/cervical-spine-fracture-detection-quick-eda","metadata":{}},{"cell_type":"code","source":"def read_dicom(path, voi_lut = True, fix_monochrome = True):\n    '''ref: https://www.kaggle.com/code/raddar/convert-dicom-to-np-array-the-correct-way\n    '''\n    dicom = pydicom.read_file(path)\n    \n    # VOI LUT (if available by DICOM device) is used to transform raw DICOM data to \"human-friendly\" view\n    if voi_lut:\n        data = apply_voi_lut(dicom.pixel_array, dicom)\n    else:\n        data = dicom.pixel_array\n               \n    # depending on this value, X-ray may look inverted - fix that:\n    if fix_monochrome and dicom.PhotometricInterpretation == \"MONOCHROME1\":\n        data = np.amax(data) - data\n        \n    data = data - np.min(data)\n    data = data / np.max(data)\n    data = (data * 255).astype(np.uint8)\n    return data, dicom\n\n\n","metadata":{"execution":{"iopub.status.busy":"2022-07-30T02:42:57.74044Z","iopub.execute_input":"2022-07-30T02:42:57.740855Z","iopub.status.idle":"2022-07-30T02:42:57.74929Z","shell.execute_reply.started":"2022-07-30T02:42:57.740819Z","shell.execute_reply":"2022-07-30T02:42:57.748311Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Example of data","metadata":{}},{"cell_type":"code","source":"temp, data = read_dicom('../input/rsna-2022-cervical-spine-fracture-detection/train_images/1.2.826.0.1.3680043.10001/101.dcm')\n\nprint(data)\nplt.figure(figsize=(10, 10))\nplt.imshow(temp, cmap='bone')","metadata":{"execution":{"iopub.status.busy":"2022-07-30T02:42:58.212481Z","iopub.execute_input":"2022-07-30T02:42:58.21325Z","iopub.status.idle":"2022-07-30T02:42:58.653292Z","shell.execute_reply.started":"2022-07-30T02:42:58.213198Z","shell.execute_reply":"2022-07-30T02:42:58.652358Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"What we want to retrieve in the data is the **Image Position (Patient)** data, which contains the X, Y and Z variables that give the position of the scan. As we can see it is indexed at (0020, 0032), and we will use that index to retrieve it.","metadata":{}},{"cell_type":"markdown","source":"reference on the position data: https://dicom.innolitics.com/ciods/rt-dose/image-plane/00200032#:~:text=Image%20Position%20(0020%2C0032),with%20respect%20to%20the%20patient.","metadata":{}},{"cell_type":"markdown","source":"reference on how to get the data: https://pydicom.github.io/pydicom/stable/tutorials/dataset_basics.html#sequences","metadata":{}},{"cell_type":"markdown","source":"## Retrieving scan positions in a folder","metadata":{}},{"cell_type":"code","source":"\n\nimages = glob('../input/rsna-2022-cervical-spine-fracture-detection/train_images/1.2.826.0.1.3680043.10001/*')\npositions = []\nfor image in images:\n    data = read_dicom(image)[1]\n    \n    positions.append(data[0x0020, 0x0032][0:3])\n    \n\nprint(positions[-1])","metadata":{"execution":{"iopub.status.busy":"2022-07-30T02:46:58.570306Z","iopub.execute_input":"2022-07-30T02:46:58.570697Z","iopub.status.idle":"2022-07-30T02:47:03.11532Z","shell.execute_reply.started":"2022-07-30T02:46:58.570665Z","shell.execute_reply":"2022-07-30T02:47:03.113888Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Creating a *image->position* dict and ordering the images by the Z axis","metadata":{}},{"cell_type":"code","source":"image_dict = dict(zip(images, positions))\n\nimage_dict = dict(sorted(image_dict.items(), key=lambda item: item[-1]))","metadata":{"execution":{"iopub.status.busy":"2022-07-30T02:54:00.269402Z","iopub.execute_input":"2022-07-30T02:54:00.270155Z","iopub.status.idle":"2022-07-30T02:54:00.279422Z","shell.execute_reply.started":"2022-07-30T02:54:00.270112Z","shell.execute_reply":"2022-07-30T02:54:00.278438Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Visualizing and understanding\n\nAs we can see [here](https://dicom.innolitics.com/ciods/rt-dose/image-plane/00200032#:~:text=Image%20Position%20(0020%2C0032),with%20respect%20to%20the%20patient), the Z variable grows as it gets closer to the head of the patient. So the images shown below will be ordered from **bottom cervical** to **head**.","metadata":{}},{"cell_type":"markdown","source":"# What's next?\n\nNow with this information we can better locate each section of the cervical spine. Maybe with proper research we can properly seperate the images into their respective sections and better use the data for our models from there.","metadata":{}},{"cell_type":"code","source":"\n\nfor i, image in enumerate(image_dict.keys()):\n    temp = read_dicom(image)[0]\n    plt.figure(figsize=(10, 10))\n    plt.title(image_dict.get(image))\n    plt.imshow(temp, cmap='bone')\n","metadata":{"execution":{"iopub.status.busy":"2022-07-30T02:54:02.687825Z","iopub.execute_input":"2022-07-30T02:54:02.688609Z","iopub.status.idle":"2022-07-30T02:55:12.462673Z","shell.execute_reply.started":"2022-07-30T02:54:02.688562Z","shell.execute_reply":"2022-07-30T02:55:12.461647Z"},"trusted":true},"execution_count":null,"outputs":[]}]}