{"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":"Adapted from : https://www.kaggle.com/code/theoviel/dicom-resized-png-jpg\n\n**Dataset Links :**\n- Part 1 : https://www.kaggle.com/datasets/theoviel/rsna-abdominal-trauma-detection-png-pt1\n- Part 2 : https://www.kaggle.com/datasets/theoviel/rsna-abdominal-trauma-detection-png-pt2\n- Part 3 : https://www.kaggle.com/datasets/theoviel/rsna-2023-abdominal-trauma-detection-pngs-3-8\n- Part 4 : https://www.kaggle.com/datasets/theoviel/rsna-abdominal-trauma-detection-png-pt4\n- Part 5 : https://www.kaggle.com/datasets/theoviel/rsna-abdominal-trauma-detection-png-pt5\n- Part 6 : https://www.kaggle.com/datasets/theoviel/rsna-abdominal-trauma-detection-png-pt6\n- Part 7 : https://www.kaggle.com/datasets/theoviel/rsna-abdominal-trauma-detection-pngs-pt7\n- Part 8 : https://www.kaggle.com/datasets/theoviel/rsna-2023-abdominal-trauma-detection-pngs-18\n\n**Changes :**\n- Apply `standardize_pixel_array` function\n- Update links\n- Remove `apply_voi_luit`\n- Add rescaling, thanks @sukharev !\n\n**TODO :**\n- Dicom processing on GPU\n- Figure out why example dicom is too dark","metadata":{}},{"cell_type":"code","source":"!pip install -qU python-gdcm pydicom pylibjpeg","metadata":{"execution":{"iopub.status.busy":"2023-08-12T15:59:53.592407Z","iopub.execute_input":"2023-08-12T15:59:53.593522Z","iopub.status.idle":"2023-08-12T16:00:07.852296Z","shell.execute_reply.started":"2023-08-12T15:59:53.593477Z","shell.execute_reply":"2023-08-12T16:00:07.850568Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport cv2\nimport glob\nimport gdcm\nimport pydicom\nimport zipfile\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\nimport matplotlib.pyplot as plt\n\nfrom tqdm import tqdm\nfrom joblib import Parallel, delayed\nfrom pydicom.pixel_data_handlers.util import apply_voi_lut","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-08-12T16:00:07.854267Z","iopub.execute_input":"2023-08-12T16:00:07.854672Z","iopub.status.idle":"2023-08-12T16:00:07.864835Z","shell.execute_reply.started":"2023-08-12T16:00:07.85463Z","shell.execute_reply":"2023-08-12T16:00:07.86277Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def standardize_pixel_array(dcm: pydicom.dataset.FileDataset) -> np.ndarray:\n    \"\"\"\n    Source : https://www.kaggle.com/competitions/rsna-2023-abdominal-trauma-detection/discussion/427217\n    \"\"\"\n    # Correct DICOM pixel_array if PixelRepresentation == 1.\n    pixel_array = dcm.pixel_array\n    if dcm.PixelRepresentation == 1:\n        bit_shift = dcm.BitsAllocated - dcm.BitsStored\n        dtype = pixel_array.dtype \n        pixel_array = (pixel_array << bit_shift).astype(dtype) >>  bit_shift\n#         pixel_array = pydicom.pixel_data_handlers.util.apply_modality_lut(new_array, dcm)\n\n    intercept = float(dcm.RescaleIntercept)\n    slope = float(dcm.RescaleSlope)\n    center = int(dcm.WindowCenter)\n    width = int(dcm.WindowWidth)\n    low = center - width / 2\n    high = center + width / 2    \n    \n    pixel_array = (pixel_array * slope) + intercept\n    pixel_array = np.clip(pixel_array, low, high)\n\n    return pixel_array","metadata":{"execution":{"iopub.status.busy":"2023-08-12T16:00:07.866599Z","iopub.execute_input":"2023-08-12T16:00:07.867291Z","iopub.status.idle":"2023-08-12T16:00:07.893027Z","shell.execute_reply.started":"2023-08-12T16:00:07.867236Z","shell.execute_reply":"2023-08-12T16:00:07.891671Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"TRAIN_PATH = \"/kaggle/input/rsna-2023-abdominal-trauma-detection/train_images/\"\n\nprint('Number of training patients :', len(os.listdir(TRAIN_PATH)))","metadata":{"execution":{"iopub.status.busy":"2023-08-12T16:00:07.894733Z","iopub.execute_input":"2023-08-12T16:00:07.895273Z","iopub.status.idle":"2023-08-12T16:00:07.918102Z","shell.execute_reply.started":"2023-08-12T16:00:07.895229Z","shell.execute_reply":"2023-08-12T16:00:07.91662Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for patient in sorted(os.listdir(TRAIN_PATH)):\n    for study in os.listdir(TRAIN_PATH + patient):\n        imgs = {}\n        for f in sorted(glob.glob(TRAIN_PATH + f\"{patient}/{study}/*.dcm\"))[::10]:\n            dicom = pydicom.dcmread(f)\n\n            pos_z = dicom[(0x20, 0x32)].value[-1]  # to retrieve the order of frames\n\n            img = standardize_pixel_array(dicom)\n            img = (img - img.min()) / (img.max() - img.min() + 1e-6)\n\n            if dicom.PhotometricInterpretation == \"MONOCHROME1\":\n                img = 1 - img\n\n            imgs[pos_z] = img\n\n        for i, k in enumerate(sorted(imgs.keys())):\n            img = imgs[k]\n            \n            if not (i % 100):\n                plt.figure(figsize=(5, 5))\n                plt.imshow(img, cmap=\"gray\")\n                plt.title(f\"Patient {patient} - Study {study} - Frame {i}/{len(imgs)}\")\n                plt.axis(False)\n                plt.show()\n    \n        break\n    break","metadata":{"execution":{"iopub.status.busy":"2023-08-12T16:00:07.919947Z","iopub.execute_input":"2023-08-12T16:00:07.920361Z","iopub.status.idle":"2023-08-12T16:00:11.795446Z","shell.execute_reply.started":"2023-08-12T16:00:07.920327Z","shell.execute_reply":"2023-08-12T16:00:11.794281Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Save the processed data","metadata":{}},{"cell_type":"code","source":"def process(patient, size=512, save_folder=\"\", data_path=\"\"):\n    for study in sorted(os.listdir(data_path + patient)):\n        imgs = {}\n        for f in sorted(glob.glob(data_path + f\"{patient}/{study}/*.dcm\")):\n            dicom = pydicom.dcmread(f)\n\n            pos_z = dicom[(0x20, 0x32)].value[-1]\n\n            img = standardize_pixel_array(dicom)\n            img = (img - img.min()) / (img.max() - img.min() + 1e-6)\n\n            if dicom.PhotometricInterpretation == \"MONOCHROME1\":\n                img = 1 - img\n\n            imgs[pos_z] = img\n\n        for i, k in enumerate(sorted(imgs.keys())):\n            img = imgs[k]\n\n            if size is not None:\n                img = cv2.resize(img, (size, size))\n\n            if isinstance(save_folder, str):\n                cv2.imwrite(save_folder + f\"{patient}_{study}_{i}.png\", (img * 255).astype(np.uint8))\n            else:\n                im = cv2.imencode('.png', (img * 255).astype(np.uint8))[1]\n                save_folder.writestr(f'{patient}_{study}_{i:04d}.png', im)","metadata":{"execution":{"iopub.status.busy":"2023-08-12T16:00:37.932616Z","iopub.execute_input":"2023-08-12T16:00:37.933032Z","iopub.status.idle":"2023-08-12T16:00:37.94629Z","shell.execute_reply.started":"2023-08-12T16:00:37.932991Z","shell.execute_reply":"2023-08-12T16:00:37.944598Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"patients = os.listdir(TRAIN_PATH)\n\n# Chunking\npatients = (\n#     patients[:400],\n#     patients[400:  800],\n#     patients[800:  1200],\n#     patients[1200: 1600],\n#     patients[1600: 2000],\n#     patients[2000: 2400],\n#     patients[2400: 2800],\n    patients[2800:],\n)\n\npatients = patients[0]  # [:10]  # subsample","metadata":{"execution":{"iopub.status.busy":"2023-07-27T13:24:43.851168Z","iopub.execute_input":"2023-07-27T13:24:43.851696Z","iopub.status.idle":"2023-07-27T13:24:43.861Z","shell.execute_reply.started":"2023-07-27T13:24:43.851656Z","shell.execute_reply":"2023-07-27T13:24:43.858729Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"with zipfile.ZipFile(\"output.zip\", 'w') as save_folder:\n    for patient in tqdm(patients):\n        process(patient, size=None, save_folder=save_folder, data_path=TRAIN_PATH)","metadata":{"execution":{"iopub.status.busy":"2023-07-27T13:28:33.225763Z","iopub.execute_input":"2023-07-27T13:28:33.227353Z","iopub.status.idle":"2023-07-27T13:29:29.324828Z","shell.execute_reply.started":"2023-07-27T13:28:33.227263Z","shell.execute_reply":"2023-07-27T13:29:29.323243Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Done ! ","metadata":{}}]}