{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":52254,"databundleVersionId":6863140,"sourceType":"competition"}],"dockerImageVersionId":30698,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":" **This kernel showcases the image processing approach we used for the [RSNA 2023 Abdominal Trauma Detection Challenge](https://www.kaggle.com/code/ashery/rsna-2023-abdominal-trauma-detection-training). It involves processing a sample of 9 images using a windowing technique to emphasize key anatomical structures. This technique facilitates the highlighting of soft tissues, bones, and lungs, enabling the model to learn distinctive features effectively. Specifically, we employed soft tissue, bone, and lung windows to highlight these respective structures. The complete dataset can be found [here](https://www.kaggle.com/datasets/ashery/rsna-2023-abdominal-trauma-processed-dataset). For additional information on the windowing technique, please refer to: [CT Windowing Technique](https://kevalnagda.github.io/ct-windowing).**","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\nimport cv2\nimport pydicom\nimport matplotlib.pyplot as plt\nfrom math import ceil\n\n%matplotlib inline\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\n\nimage_paths = []\nfor index,(dirname, _, filenames) in enumerate(os.walk('/kaggle/input')):\n    for filename in filenames:\n        if filename.endswith(\".dcm\"):\n            ## get dicom image paths\n            path = os.path.join(dirname, filename)\n            #print(path)\n            image_paths.append(path)\n    if index == 9:\n        break\n        \n    \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","execution":{"iopub.status.busy":"2024-05-03T05:04:37.734852Z","iopub.execute_input":"2024-05-03T05:04:37.735291Z","iopub.status.idle":"2024-05-03T05:04:38.227693Z","shell.execute_reply.started":"2024-05-03T05:04:37.73526Z","shell.execute_reply":"2024-05-03T05:04:38.226482Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(image_paths)","metadata":{"execution":{"iopub.status.busy":"2024-05-03T05:04:38.229427Z","iopub.execute_input":"2024-05-03T05:04:38.229748Z","iopub.status.idle":"2024-05-03T05:04:38.235818Z","shell.execute_reply.started":"2024-05-03T05:04:38.22972Z","shell.execute_reply":"2024-05-03T05:04:38.234972Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Standardize the Image**","metadata":{}},{"cell_type":"code","source":"def standardize_image(dicom_image):\n    pixel_array = dicom_image.pixel_array   \n    \n    if dicom_image.PixelRepresentation == 1:\n        bit_shift = dicom_image.BitsAllocated - dicom_image.BitsStored\n        dtype = pixel_array.dtype \n        pixel_array = (pixel_array << bit_shift).astype(dtype) >>  bit_shift\n    \n    if dicom_image.PhotometricInterpretation == \"MONOCHROME1\":\n        pixel_array = 1 - pixel_array\n    \n    # transform to hounsfield units\n    intercept = dicom_image.RescaleIntercept\n    slope = dicom_image.RescaleSlope\n    pixel_array = pixel_array * slope + intercept\n    return pixel_array","metadata":{"execution":{"iopub.status.busy":"2024-05-03T05:04:40.118617Z","iopub.execute_input":"2024-05-03T05:04:40.119369Z","iopub.status.idle":"2024-05-03T05:04:40.126382Z","shell.execute_reply.started":"2024-05-03T05:04:40.119323Z","shell.execute_reply":"2024-05-03T05:04:40.125026Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Applying Windowing Technique**","metadata":{}},{"cell_type":"code","source":"def apply_window(image_stack, window, normalize = True):\n    \n    window_width = window[0]\n    window_center = window[1]\n    img_min = window_center - window_width//2 #minimum HU level\n    img_max = window_center + window_width//2 #maximum HU level\n    img = np.clip(image_stack, img_min, img_max)\n    \n    if normalize:\n        img = (img - img_min) / (img_max - img_min)\n    return img","metadata":{"execution":{"iopub.status.busy":"2024-05-03T05:04:50.180536Z","iopub.execute_input":"2024-05-03T05:04:50.18096Z","iopub.status.idle":"2024-05-03T05:04:50.188523Z","shell.execute_reply.started":"2024-05-03T05:04:50.180929Z","shell.execute_reply":"2024-05-03T05:04:50.186902Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Convert DICOM images to PNG format by applying windowing techniques to highlight specific anatomical features.**","metadata":{}},{"cell_type":"code","source":"def dicom_to_png(dicom_image):\n    \"\"\"\n    Read the dicom file and preprocess appropriately.\n    \"\"\"\n    pixel_array = standardize_image(dicom_image)\n    \n    windows = [(2,1),(2048,1),(300,150)]\n    imgs = []\n    for window in windows:\n        windowed_array = apply_window(pixel_array,window, normalize = True)\n        img = (windowed_array * 255).astype(np.uint8)\n        img = cv2.resize(img, (256,256))\n        imgs.append(img)\n    \n    return np.stack(imgs,axis=-1)","metadata":{"execution":{"iopub.status.busy":"2024-05-03T05:04:50.829148Z","iopub.execute_input":"2024-05-03T05:04:50.829534Z","iopub.status.idle":"2024-05-03T05:04:50.835852Z","shell.execute_reply.started":"2024-05-03T05:04:50.829506Z","shell.execute_reply":"2024-05-03T05:04:50.834698Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Show images before preprocessing**","metadata":{}},{"cell_type":"code","source":"\nnum_images = len(image_paths[:9])\nnum_rows = ceil(num_images / 3)\nfig, axes = plt.subplots(num_rows, 3, figsize=(15, 5 * num_rows))\n\nfor i, path in enumerate(image_paths[:9]):\n    dicom_data = pydicom.dcmread(path)\n    img = dicom_data.pixel_array\n    row = i // 3\n    col = i % 3\n    axes[row, col].imshow(img, cmap='gray')\n    axes[row, col].axis('off')\n    axes[row, col].set_title(f\"Image {i+1}\")\n\n#Remove empty subplots\nfor i in range(num_images, num_rows*3):\n    row = i // 3\n    col = i % 3\n    fig.delaxes(axes[row, col])\n\nplt.tight_layout()\nplt.show()\n\n","metadata":{"execution":{"iopub.status.busy":"2024-05-03T05:04:51.663432Z","iopub.execute_input":"2024-05-03T05:04:51.663783Z","iopub.status.idle":"2024-05-03T05:04:53.5053Z","shell.execute_reply.started":"2024-05-03T05:04:51.663755Z","shell.execute_reply":"2024-05-03T05:04:53.503662Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Process 9 sample images and show them**","metadata":{}},{"cell_type":"code","source":"num_images = min(len(image_paths), 9)\nnum_rows = (num_images + 2) // 3\nfig, axes = plt.subplots(num_rows, 3, figsize=(15, 5 * num_rows))\n\nfor i, path in enumerate(image_paths[:9]):\n    dicom_data = pydicom.dcmread(path)\n    img = dicom_to_png(dicom_data)\n    row = i // 3\n    col = i % 3\n    axes[row, col].imshow(img, cmap='gray')\n    axes[row, col].axis('off')\n    axes[row, col].set_title(f\"Image {i+1}\")\n\n# Remove empty subplots\nfor i in range(num_images, num_rows*3):\n    row = i // 3\n    col = i % 3\n    fig.delaxes(axes[row, col])\n\nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-05-03T05:04:53.507442Z","iopub.execute_input":"2024-05-03T05:04:53.507821Z","iopub.status.idle":"2024-05-03T05:04:56.104806Z","shell.execute_reply.started":"2024-05-03T05:04:53.50779Z","shell.execute_reply":"2024-05-03T05:04:56.101931Z"},"trusted":true},"execution_count":null,"outputs":[]}]}