{"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":"# Setup and helper functions","metadata":{}},{"cell_type":"code","source":"# !pip install pydicom\n# !pip install python-gdcm\n# !pip install pylibjpeg pylibjpeg-libjpeg pydicom","metadata":{"execution":{"iopub.status.busy":"2023-05-16T14:46:40.99493Z","iopub.execute_input":"2023-05-16T14:46:40.995368Z","iopub.status.idle":"2023-05-16T14:46:41.036471Z","shell.execute_reply.started":"2023-05-16T14:46:40.995332Z","shell.execute_reply":"2023-05-16T14:46:41.035604Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport re\nimport csv\nimport cv2\nimport random\nimport shutil\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nfrom matplotlib.patches import Rectangle\n\nimport pydicom as dicom\n\nimport nibabel as nib","metadata":{"execution":{"iopub.status.busy":"2023-05-16T14:46:41.042139Z","iopub.execute_input":"2023-05-16T14:46:41.042805Z","iopub.status.idle":"2023-05-16T14:46:41.420296Z","shell.execute_reply.started":"2023-05-16T14:46:41.042772Z","shell.execute_reply":"2023-05-16T14:46:41.4181Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"rsna_root = '/kaggle/input/rsna-2022-cervical-spine-fracture-detection'","metadata":{"execution":{"iopub.status.busy":"2023-05-16T14:46:41.421587Z","iopub.execute_input":"2023-05-16T14:46:41.421964Z","iopub.status.idle":"2023-05-16T14:46:41.427125Z","shell.execute_reply.started":"2023-05-16T14:46:41.421925Z","shell.execute_reply":"2023-05-16T14:46:41.426027Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Helper functions\n\ndef load_img_from_dcm(path):\n    img = dicom.dcmread(path)\n    img.PhotometricInterpretation = 'YBR_FULL'\n    data = img.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 cv2.cvtColor(data, cv2.COLOR_GRAY2RGB)\n\ndef CT_path_to_3D_arr(folder_path, l=None): # folder_path is for folder of dcm files constituting one CT scan\n    if l == None:\n        l = os.listdir(folder_path) # list of 2D slices of the CT scan\n        l.sort()\n        l = sorted(l, key=len)\n    \n    CT_arr = [] # the full 3D CT\n    for dcm in l:\n        dcm_path = os.path.join(folder_path, dcm)\n        dcm_arr = load_img_from_dcm(dcm_path)\n        CT_arr.append(dcm_arr)\n    CT_arr = np.asarray(CT_arr)\n    return CT_arr","metadata":{"execution":{"iopub.status.busy":"2023-05-16T14:46:41.430592Z","iopub.execute_input":"2023-05-16T14:46:41.431743Z","iopub.status.idle":"2023-05-16T14:46:41.441574Z","shell.execute_reply.started":"2023-05-16T14:46:41.431705Z","shell.execute_reply":"2023-05-16T14:46:41.440576Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Bounding boxes around vertebrae\ncan be obtained from the segmentations data. First I will visualize the segmentation slices side-by-side with their corresponding CT slices.","metadata":{}},{"cell_type":"code","source":"# patient_id = \"1.2.826.0.1.3680043.780\"\n\n# segm_path = os.path.join(rsna_root, 'segmentations', patient_id+'.nii')\n# segm_arr = nib.load(segm_path).get_fdata()\n# segm_arr = np.transpose(segm_arr, (2, 0, 1))\n\n# CT_path = os.path.join(rsna_root, 'train_images', patient_id)\n# CT_arr = CT_path_to_3D_arr(CT_path)","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-05-16T14:46:41.443128Z","iopub.execute_input":"2023-05-16T14:46:41.443508Z","iopub.status.idle":"2023-05-16T14:46:41.450827Z","shell.execute_reply.started":"2023-05-16T14:46:41.443475Z","shell.execute_reply":"2023-05-16T14:46:41.449765Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# fig, ax = plt.subplots(1, 2, figsize=(12, 6))\n\n# slice_num = 80 # from 0 to len(array)-1\n# segm_slice = segm_arr[len(segm_arr)-1 - slice_num]\n# segm_slice = np.rot90(segm_slice)\n# CT_slice = CT_arr[slice_num]\n# ax[0].imshow(CT_slice, cmap=plt.get_cmap('bone'))\n# ax[1].imshow(segm_slice, cmap=plt.get_cmap('bone'))","metadata":{"execution":{"iopub.status.busy":"2023-05-16T14:46:41.452438Z","iopub.execute_input":"2023-05-16T14:46:41.452823Z","iopub.status.idle":"2023-05-16T14:46:41.461801Z","shell.execute_reply.started":"2023-05-16T14:46:41.452792Z","shell.execute_reply":"2023-05-16T14:46:41.460612Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We can draw a bounding box (bbox) around the vertebrae by using the segmentation slice like this:","metadata":{}},{"cell_type":"code","source":"# rows = np.any(segm_slice, axis=1)\n# cols = np.any(segm_slice, axis=0)\n# rmin, rmax = np.where(rows)[0][[0, -1]]\n# cmin, cmax = np.where(cols)[0][[0, -1]]\n# width = cmax - cmin\n# height = rmax - rmin\n\n# fig, ax = plt.subplots(1, 1, figsize=(6,6))\n# ax.imshow(segm_slice)\n# rect = Rectangle((cmin, rmin), width, height,\n#                  linewidth=1, edgecolor='r', facecolor='none')\n# ax.add_patch(rect)","metadata":{"execution":{"iopub.status.busy":"2023-05-16T14:46:41.463793Z","iopub.execute_input":"2023-05-16T14:46:41.464187Z","iopub.status.idle":"2023-05-16T14:46:41.471609Z","shell.execute_reply.started":"2023-05-16T14:46:41.464155Z","shell.execute_reply":"2023-05-16T14:46:41.470475Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Drawing the bbox on the original CT scan:","metadata":{}},{"cell_type":"code","source":"# fig, ax = plt.subplots(1, 1, figsize=(6,6))\n# ax.imshow(CT_slice, cmap=plt.get_cmap('bone'))\n# rect = Rectangle((cmin, rmin), width, height,\n#                  linewidth=1, edgecolor='r', facecolor='none')\n# ax.add_patch(rect)\n\n# print(cmin, rmin, width, height)","metadata":{"execution":{"iopub.status.busy":"2023-05-16T14:46:41.473303Z","iopub.execute_input":"2023-05-16T14:46:41.474036Z","iopub.status.idle":"2023-05-16T14:46:41.483809Z","shell.execute_reply.started":"2023-05-16T14:46:41.474003Z","shell.execute_reply":"2023-05-16T14:46:41.482722Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Save labels (bboxes) in YOLOv5 format to use for training\nI used [Ultralytics YOLOv5](https://docs.ultralytics.com/quick-start/), which I found super easy to use. The specifics are well-documented on their website, but here is the gist:\n- one txt file per image\n- one row per object/bbox\n- each row in 'class_number, xcentre, ycentre, width, height' format (here, we only have one class '0: vertebra')\n- bbox coordinates are normalized, ie divided by width/height in length\n- (0,0) is top-left","metadata":{}},{"cell_type":"code","source":"# import csv\n\n# def save_yolo_coord(pt_num, slice_num, slice_, destination_folder):\n#     '''\n#     Saves the yolov5 coord csv file for a single slice segmentation mask\n    \n#     pt_num: number that follows 1.2.826.0.1.3680043.\n#     slice_num: which slice\n#     slice_: 2D array of slice\n#     destination_folder: where to save the csv files\n#     '''\n#     rows = np.any(slice_, axis=1)\n#     cols = np.any(slice_, axis=0)\n#     rmin, rmax = np.where(rows)[0][[0, -1]]\n#     cmin, cmax = np.where(cols)[0][[0, -1]]\n    \n#     xcentre = int((cmin+cmax)/2)\n#     ycentre = int((rmin+rmax)/2)\n#     width = cmax - cmin\n#     height = rmax - rmin\n#     img_width = slice_.shape[1]\n#     img_height = slice_.shape[0]\n    \n#     # YOLO coordinates: StudyInstanceUID, x, y, width, height, slice_number\n#     yolo_coord = [\n#         str(pt_num),\n#         xcentre,\n#         ycentre,\n#         width,\n#         height,\n#         slice_num\n#     ]\n    \n#     filename = os.path.join(destination_folder, str(pt_num)+\"_\"+str(slice_num)+'.csv')\n#     with open(filename, 'w', newline='') as file:\n#         writer = csv.writer(file)\n#         writer.writerow(['StudyInstanceUID', 'x', 'y', 'width', 'height', 'slice_number'])\n#         writer.writerow(yolo_coord)\n","metadata":{"execution":{"iopub.status.busy":"2023-05-16T14:46:41.485486Z","iopub.execute_input":"2023-05-16T14:46:41.486245Z","iopub.status.idle":"2023-05-16T14:46:41.498801Z","shell.execute_reply.started":"2023-05-16T14:46:41.48621Z","shell.execute_reply":"2023-05-16T14:46:41.497881Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# def save_yolo_coord(pt_num, slice_num, slice_, destination_folder):\n#     '''\n#     Saves the yolov5 coord txt file for a single slice segmentation mask\n    \n#     pt_num: number that follows 1.2.826.0.1.3680043.\n#     slice_num: which slice\n#     arr: 2D array of slice\n#     destination_folder: where to save the txt files\n#     '''\n#     rows = np.any(slice_, axis=1)\n#     cols = np.any(slice_, axis=0)\n#     rmin, rmax = np.where(rows)[0][[0, -1]]\n#     cmin, cmax = np.where(cols)[0][[0, -1]]\n    \n#     xcentre = int((cmin+cmax)/2)\n#     ycentre = int((rmin+rmax)/2)\n#     width = cmax - cmin\n#     height = rmax - rmin\n#     img_width = slice_.shape[1]\n#     img_height = slice_.shape[0]\n    \n#     # yolo coordiates: class, xcentre, ycentre, width, height (normalized by width/hegith of image)\n#     yolo_coord = [0, xcentre/img_width, ycentre/img_height, width/img_width, height/img_height]\n    \n#     filename = os.path.join(destination_folder, str(pt_num)+\"_\"+str(slice_num)+'.txt')\n#     with open(filename, 'w') as file:\n#         writer = csv.writer(file, delimiter=' ')\n#         writer.writerow(yolo_coord)","metadata":{"execution":{"iopub.status.busy":"2023-05-16T14:46:41.50024Z","iopub.execute_input":"2023-05-16T14:46:41.501061Z","iopub.status.idle":"2023-05-16T14:46:41.508514Z","shell.execute_reply.started":"2023-05-16T14:46:41.501026Z","shell.execute_reply":"2023-05-16T14:46:41.507602Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# import csv\n\n# def save_bboxes_from_nii(pt_num, nii_folder, dest_folder_name):\n#     '''\n#     Saves yolov5 coord csv files for one patient's segmentation masks (ie, one nii file)\n#     '''\n#     destination_folder = os.path.join(os.getcwd(), dest_folder_name)\n#     if not os.path.exists(destination_folder):\n#         print(f'Creating destination folder in current directory: {dest_folder_name}')\n#         os.mkdir(destination_folder)\n    \n#     arr = nib.load(os.path.join(nii_folder, '1.2.826.0.1.3680043.'+str(pt_num)+'.nii')).get_fdata()\n#     arr = np.transpose(arr, (2, 0, 1))\n#     arr = np.flip(arr, axis=0)\n    \n#     coords = []  # List to store all YOLO coordinates\n    \n#     for slice_num, slice_ in enumerate(arr):\n#         if not slice_.any():\n#             continue\n#         slice_ = np.rot90(slice_)\n        \n#         coords.append(get_yolo_coord(pt_num, slice_num, slice_))\n    \n#     save_coords_to_csv(pt_num, coords, destination_folder)\n\n# def get_yolo_coord(pt_num, slice_num, slice_):\n#     '''\n#     Returns the YOLO coordinates for a single slice segmentation mask\n    \n#     pt_num: number that follows 1.2.826.0.1.3680043.\n#     slice_num: which slice\n#     slice_: 2D array of slice\n    \n#     Returns:\n#     yolo_coord: List of YOLO coordinates [StudyInstanceUID, x, y, width, height, slice_number]\n#     '''\n#     rows = np.any(slice_, axis=1)\n#     cols = np.any(slice_, axis=0)\n#     rmin, rmax = np.where(rows)[0][[0, -1]]\n#     cmin, cmax = np.where(cols)[0][[0, -1]]\n    \n#     xcentre = int((cmin+cmax)/2)\n#     ycentre = int((rmin+rmax)/2)\n#     width = cmax - cmin\n#     height = rmax - rmin\n#     img_width = slice_.shape[1]\n#     img_height = slice_.shape[0]\n    \n#     # YOLO coordinates: StudyInstanceUID, x, y, width, height, slice_number\n#     yolo_coord = [\n#         str(pt_num),\n#         xcentre,\n#         ycentre,\n#         width,\n#         height,\n#         slice_num\n#     ]\n    \n#     return yolo_coord\n\n# def save_coords_to_csv(pt_num, coords, destination_folder):\n#     '''\n#     Saves the YOLO coordinates to a CSV file\n    \n#     pt_num: number that follows 1.2.826.0.1.3680043.\n#     coords: List of YOLO coordinates\n#     destination_folder: where to save the CSV file\n#     '''\n#     filename = os.path.join(destination_folder, str(pt_num) + '_coords.csv')\n#     with open(filename, 'w', newline='') as file:\n#         writer = csv.writer(file)\n#         writer.writerow(['StudyInstanceUID', 'x', 'y', 'width', 'height', 'slice_number'])\n#         writer.writerows(coords)\n","metadata":{"execution":{"iopub.status.busy":"2023-05-16T14:46:44.622103Z","iopub.execute_input":"2023-05-16T14:46:44.623116Z","iopub.status.idle":"2023-05-16T14:46:44.630552Z","shell.execute_reply.started":"2023-05-16T14:46:44.623072Z","shell.execute_reply":"2023-05-16T14:46:44.629293Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# def save_bboxes_from_nii(pt_num, nii_folder, dest_folder_name):\n#     '''\n#     Saves yolov5 coord csv files for one patient's segmentation masks (ie, one nii file)\n#     '''\n#     destination_folder = os.path.join(os.getcwd(), dest_folder_name)\n#     if not os.path.exists(destination_folder):\n#         print(f'Creating destination folder in current directory: {dest_folder_name}')\n#         os.mkdir(destination_folder)\n    \n#     arr = nib.load(os.path.join(nii_folder, '1.2.826.0.1.3680043.'+str(pt_num)+'.nii')).get_fdata()\n#     arr = np.transpose(arr, (2, 0, 1))\n#     arr = np.flip(arr, axis=0)\n    \n#     for slice_num, slice_ in enumerate(arr):\n#         if not slice_.any():\n#             continue\n#         slice_ = np.rot90(slice_)\n        \n#         save_yolo_coord(pt_num, slice_num, slice_, destination_folder)","metadata":{"execution":{"iopub.status.busy":"2023-05-16T14:46:44.695837Z","iopub.execute_input":"2023-05-16T14:46:44.696227Z","iopub.status.idle":"2023-05-16T14:46:44.701208Z","shell.execute_reply.started":"2023-05-16T14:46:44.6962Z","shell.execute_reply":"2023-05-16T14:46:44.699953Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# def save_bboxes_from_nii(pt_num, nii_folder, dest_folder_name):\n#     '''\n#     Saves yolov5 coord txt files for one patient's segmentation masks (ie, one nii file)\n#     '''\n#     destination_folder = os.path.join(os.getcwd(), dest_folder_name)\n#     if not os.path.exists(destination_folder):\n#         print(f'Creating destination folder in current directory: {dest_folder_name}')\n#         os.mkdir(destination_folder)\n    \n#     arr = nib.load(os.path.join(nii_folder, '1.2.826.0.1.3680043.'+str(pt_num)+'.nii')).get_fdata()\n#     arr = np.transpose(arr, (2, 0, 1))\n#     arr = np.flip(arr, axis=0)\n    \n#     for slice_num, slice_ in enumerate(arr):\n#         if not slice_.any():\n#             continue\n#         slice_ = np.rot90(slice_)\n        \n#         save_yolo_coord(pt_num, slice_num, slice_, destination_folder)","metadata":{"execution":{"iopub.status.busy":"2023-05-16T14:46:44.703314Z","iopub.execute_input":"2023-05-16T14:46:44.704412Z","iopub.status.idle":"2023-05-16T14:46:44.716155Z","shell.execute_reply.started":"2023-05-16T14:46:44.704374Z","shell.execute_reply":"2023-05-16T14:46:44.715055Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def save_yolo_coords(pt_num, arr, destination_folder):\n    '''\n    Saves the YOLO coordinates for all slices of a patient's segmentation mask\n    \n    pt_num: number that follows 1.2.826.0.1.3680043.\n    arr: 3D array of slices\n    destination_folder: where to save the CSV file\n    \n    Returns:\n    coords: List of YOLO coordinates\n    '''\n    coords = []  # List to store all YOLO coordinates\n    \n    for slice_num, slice_ in enumerate(arr):\n        if not slice_.any():\n            continue\n        slice_ = np.rot90(slice_)\n        \n        yolo_coord = get_yolo_coord(pt_num, slice_num, slice_)\n        coords.append(yolo_coord)\n    \n    return coords\n\ndef get_yolo_coord(pt_num, slice_num, slice_):\n    '''\n    Returns the YOLO coordinates for a single slice segmentation mask\n    \n    pt_num: number that follows 1.2.826.0.1.3680043.\n    slice_num: which slice\n    slice_: 2D array of slice\n    \n    Returns:\n    yolo_coord: List of YOLO coordinates [StudyInstanceUID, x, y, width, height, slice_number]\n    '''\n    rows = np.any(slice_, axis=1)\n    cols = np.any(slice_, axis=0)\n    rmin, rmax = np.where(rows)[0][[0, -1]]\n    cmin, cmax = np.where(cols)[0][[0, -1]]\n    \n    xcentre = int((cmin+cmax)/2)\n    ycentre = int((rmin+rmax)/2)\n    width = cmax - cmin\n    height = rmax - rmin\n    img_width = slice_.shape[1]\n    img_height = slice_.shape[0]\n    \n    # YOLO coordinates: StudyInstanceUID, x, y, width, height, slice_number\n    yolo_coord = [\n        str(pt_num),\n        xcentre,\n        ycentre,\n        width,\n        height,\n        slice_num\n    ]\n    \n    return yolo_coord","metadata":{"execution":{"iopub.status.busy":"2023-05-16T14:46:44.746315Z","iopub.execute_input":"2023-05-16T14:46:44.7472Z","iopub.status.idle":"2023-05-16T14:46:44.757224Z","shell.execute_reply.started":"2023-05-16T14:46:44.747162Z","shell.execute_reply":"2023-05-16T14:46:44.756292Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def save_coords_to_csv(coords, destination_folder, csv_filename):\n    '''\n    Saves the YOLO coordinates to a CSV file\n    \n    coords: List of YOLO coordinates\n    destination_folder: where to save the CSV file\n    csv_filename: name of the CSV file\n    '''\n    filename = os.path.join(destination_folder, csv_filename)\n    with open(filename, 'w', newline='') as file:\n        writer = csv.writer(file)\n        writer.writerow(['StudyInstanceUID', 'x', 'y', 'width', 'height', 'slice_number'])\n        writer.writerows(coords)","metadata":{"execution":{"iopub.status.busy":"2023-05-16T14:46:44.759126Z","iopub.execute_input":"2023-05-16T14:46:44.759786Z","iopub.status.idle":"2023-05-16T14:46:44.772066Z","shell.execute_reply.started":"2023-05-16T14:46:44.759749Z","shell.execute_reply":"2023-05-16T14:46:44.771099Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def save_bboxes_from_nii(nii_folder, dest_folder_name, csv_filename):\n    '''\n    Saves YOLO coordinates for all patients' segmentation masks (NII files) in a single CSV file\n    '''\n    destination_folder = os.path.join(os.getcwd(), dest_folder_name)\n    if not os.path.exists(destination_folder):\n        print(f'Creating destination folder in current directory: {dest_folder_name}')\n        os.mkdir(destination_folder)\n\n    coords = []  # List to store all YOLO coordinates\n\n    nii_files = os.listdir(nii_folder)\n    \n    for nii_file in nii_files:\n        pt_num = nii_file.split('.')[3]\n        arr = nib.load(os.path.join(nii_folder, nii_file)).get_fdata()\n        arr = np.transpose(arr, (2, 0, 1))\n        arr = np.flip(arr, axis=0)\n        coords += save_yolo_coords(pt_num, arr, destination_folder)\n    \n    save_coords_to_csv(coords, destination_folder, csv_filename)","metadata":{"execution":{"iopub.status.busy":"2023-05-16T14:46:44.773512Z","iopub.execute_input":"2023-05-16T14:46:44.774244Z","iopub.status.idle":"2023-05-16T14:46:44.786166Z","shell.execute_reply.started":"2023-05-16T14:46:44.774208Z","shell.execute_reply":"2023-05-16T14:46:44.785227Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"nii_folder = '/kaggle/input/rsna-2022-cervical-spine-fracture-detection/segmentations'\ndest_folder_name = 'bounding_boxes'\ncsv_filename = 'bounding_boxes.csv'\nsave_bboxes_from_nii(nii_folder, dest_folder_name, csv_filename)","metadata":{"execution":{"iopub.status.busy":"2023-05-16T14:46:44.788497Z","iopub.execute_input":"2023-05-16T14:46:44.789079Z","iopub.status.idle":"2023-05-16T14:48:32.113873Z","shell.execute_reply.started":"2023-05-16T14:46:44.789049Z","shell.execute_reply":"2023-05-16T14:48:32.112808Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# # List of patient numbers in segmentations folder\n# niis = os.listdir('/kaggle/input/rsna-2022-cervical-spine-fracture-detection/segmentations')\n# pts = [re.search('(?<=1.2.826.0.1.3680043.)([0-9]*)(?=.nii)', filename).group(0) for filename in niis]\n# pts = [int(s) for s in pts]\n# print(\"List of pts with segmentations: \", pts)","metadata":{"execution":{"iopub.status.busy":"2023-05-16T14:48:32.119118Z","iopub.execute_input":"2023-05-16T14:48:32.119505Z","iopub.status.idle":"2023-05-16T14:48:32.124917Z","shell.execute_reply.started":"2023-05-16T14:48:32.119469Z","shell.execute_reply":"2023-05-16T14:48:32.123949Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# dest_folder_name = 'yolo_coords'\n# nii_folder = '/kaggle/input/rsna-2022-cervical-spine-fracture-detection/segmentations'\n# for pt_num in pts:\n#     save_bboxes_from_nii(pt_num, nii_folder, dest_folder_name)","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2023-05-16T14:48:32.12673Z","iopub.execute_input":"2023-05-16T14:48:32.127882Z","iopub.status.idle":"2023-05-16T14:48:32.143448Z","shell.execute_reply.started":"2023-05-16T14:48:32.12785Z","shell.execute_reply":"2023-05-16T14:48:32.142313Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# import csv\n\n# def save_bboxes_from_nii(nii_folder, dest_folder_name, csv_filename):\n#     '''\n#     Saves yolov5 coord csv file for all patients' segmentation masks (nii files) in a single CSV file\n#     '''\n#     destination_folder = os.path.join(os.getcwd(), dest_folder_name)\n#     if not os.path.exists(destination_folder):\n#         print(f'Creating destination folder in current directory: {dest_folder_name}')\n#         os.mkdir(destination_folder)\n\n#     coords = []  # List to store all YOLO coordinates\n\n#     nii_files = os.listdir(nii_folder)\n    \n#     for nii_file in nii_files:\n#         pt_num = nii_file.split('.')[3]\n#         arr = nib.load(os.path.join(nii_folder, nii_file)).get_fdata()\n#         arr = np.transpose(arr, (2, 0, 1))\n#         arr = np.flip(arr, axis=0)\n\n#         for slice_num, slice_ in enumerate(arr):\n#             if not slice_.any():\n#                 continue\n#             slice_ = np.rot90(slice_)\n\n#             yolo_coord = get_yolo_coord(pt_num, slice_num, slice_)\n#             coords.append(yolo_coord)\n\n#     save_coords_to_csv(coords, destination_folder, csv_filename)\n\n# def get_yolo_coord(pt_num, slice_num, slice_):\n#     '''\n#     Returns the YOLO coordinates for a single slice segmentation mask\n    \n#     pt_num: number that follows 1.2.826.0.1.3680043.\n#     slice_num: which slice\n#     slice_: 2D array of slice\n    \n#     Returns:\n#     yolo_coord: List of YOLO coordinates [StudyInstanceUID, x, y, width, height, slice_number]\n#     '''\n#     rows = np.any(slice_, axis=1)\n#     cols = np.any(slice_, axis=0)\n#     rmin, rmax = np.where(rows)[0][[0, -1]]\n#     cmin, cmax = np.where(cols)[0][[0, -1]]\n    \n#     xcentre = int((cmin+cmax)/2)\n#     ycentre = int((rmin+rmax)/2)\n#     width = cmax - cmin\n#     height = rmax - rmin\n#     img_width = slice_.shape[1]\n#     img_height = slice_.shape[0]\n    \n#     # YOLO coordinates: StudyInstanceUID, x, y, width, height, slice_number\n#     yolo_coord = [\n#         str(pt_num),\n#         xcentre,\n#         ycentre,\n#         width,\n#         height,\n#         slice_num\n#     ]\n    \n#     return yolo_coord\n\n# def save_coords_to_csv(coords, destination_folder, csv_filename):\n#     '''\n#     Saves the YOLO coordinates to a CSV file\n    \n#     coords: List of YOLO coordinates\n#     destination_folder: where to save the CSV file\n#     csv_filename: name of the CSV file\n#     '''\n#     filename = os.path.join(destination_folder, csv_filename)\n#     with open(filename, 'w', newline='') as file:\n#         writer = csv.writer(file)\n#         writer.writerow(['StudyInstanceUID', 'x', 'y', 'width', 'height', 'slice_number'])\n#         writer.writerows(coords)\n","metadata":{"execution":{"iopub.status.busy":"2023-05-16T14:48:32.145189Z","iopub.execute_input":"2023-05-16T14:48:32.145624Z","iopub.status.idle":"2023-05-16T14:48:32.159163Z","shell.execute_reply.started":"2023-05-16T14:48:32.145589Z","shell.execute_reply":"2023-05-16T14:48:32.158165Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Test to see if saved coords are correct\n\nl = os.listdir('/kaggle/working/yolo_coords')\nl = sorted(l)\nl.sort(key=len)\n\nf = np.random.choice(l)\nprint(f)\npt_num = re.search(\"^([0-9]*)(?=_)\", f).group(0)\nslice_num = re.search(\"(?<=_)([0-9]*)(?=.txt)\", f).group(0)\n\nCT_path = os.path.join(rsna_root, 'train_images', \"1.2.826.0.1.3680043.\"+pt_num)\nCT_arr = CT_path_to_3D_arr(CT_path)\nCT_slice = CT_arr[int(slice_num)]\nimg_width = CT_slice.shape[1]\nimg_height = CT_slice.shape[0]\n\nfig, ax = plt.subplots(1,1,figsize=(6,6))\nax.imshow(CT_slice, cmap=plt.get_cmap('bone'))\n\np = '/kaggle/working/yolo_coords/'+f\nwith open(p, 'r') as txt_file:\n    reader = csv.reader(txt_file)\n    row = next(reader)\n\nrow = [float(num) for num in row[0].split()]\nbbox_xcentre = img_width * row[1]\nbbox_ycentre = img_height * row[2]\nbbox_width = img_width * row[3]\nbbox_height = img_height * row[4]\nrect = Rectangle((bbox_xcentre-int(bbox_width/2), bbox_ycentre-int(bbox_height/2)),\n                  bbox_width, bbox_height,\n                  linewidth=1, edgecolor='r', facecolor='none')\nax.add_patch(rect)","metadata":{"execution":{"iopub.status.busy":"2023-05-16T14:48:32.163054Z","iopub.execute_input":"2023-05-16T14:48:32.163325Z","iopub.status.idle":"2023-05-16T14:48:32.454303Z","shell.execute_reply.started":"2023-05-16T14:48:32.163302Z","shell.execute_reply":"2023-05-16T14:48:32.452716Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Save Images for YOLOv5 training\nI found it easier to save the CT slices as jpegs for training Ultralytics YOLO.","metadata":{}},{"cell_type":"code","source":"# # yolo coord txt files for all patients\n# txt_files = os.listdir('/kaggle/working/yolo_coords')\n\n# # patients with segmentation data\n# niis = os.listdir('/kaggle/input/rsna-2022-cervical-spine-fracture-detection/segmentations')\n# pts = [re.search('(?<=1.2.826.0.1.3680043.)([0-9]*)(?=.nii)', filename).group(0) for filename in niis]\n# pts = [int(s) for s in pts]\n\n# # Save slices corresponding to each yolo_coord txt file\n# train_images = '/kaggle/input/rsna-2022-cervical-spine-fracture-detection/train_images'\n\n# yolo_slices = os.path.join(os.getcwd(), 'yolo_slices')\n# if not os.path.exists(yolo_slices):\n#     os.mkdir(yolo_slices)\n    \n# for pt in pts:\n#     slice_nums = []\n#     for txt_file in txt_files:\n#         if re.search('^([0-9]*)(?=_)', txt_file).group(0) == str(pt): # txt files for pt\n#             slice_num = int(re.search(\"(?<=_)([0-9]*)(?=.txt)\", txt_file).group(0))\n#             slice_nums.append(slice_num)\n    \n#     pt_CT = os.path.join(train_images, f\"1.2.826.0.1.3680043.{str(pt)}\") \n\n#     pt_slices_all = os.listdir(pt_CT) # list of dcms\n#     pt_slices_all = sorted(pt_slices_all)\n#     pt_slices_all.sort(key=len)\n    \n#     pt_slices = [pt_slices_all[slice_num] for slice_num in sorted(slice_nums)]\n    \n#     if min(pt_slices_all, key=len) == '2.dcm': # scans that are missing 1.dcm\n#         for slice_ in pt_slices:\n#             img_path = os.path.join(train_images, \"1.2.826.0.1.3680043.\"+str(pt), slice_)\n#             img = load_img_from_dcm(img_path)\n\n#             imgs_savepath = os.path.join(yolo_slices, f\"{str(pt)}_{int(slice_[:-4])-2}.jpg\")\n#             cv2.imwrite(imgs_savepath, img)        \n    \n#     else: # normal scans that start from 1.dcm\n#         for slice_ in pt_slices:\n#             img_path = os.path.join(train_images, \"1.2.826.0.1.3680043.\"+str(pt), slice_)\n#             img = load_img_from_dcm(img_path)\n\n#             imgs_savepath = os.path.join(yolo_slices, f\"{str(pt)}_{int(slice_[:-4])-1}.jpg\")\n#             cv2.imwrite(imgs_savepath, img)","metadata":{"scrolled":true,"_kg_hide-input":false,"_kg_hide-output":false,"execution":{"iopub.status.busy":"2023-05-16T14:48:32.455607Z","iopub.status.idle":"2023-05-16T14:48:32.456701Z","shell.execute_reply.started":"2023-05-16T14:48:32.456418Z","shell.execute_reply":"2023-05-16T14:48:32.456451Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Organize images and labels into directories","metadata":{}},{"cell_type":"code","source":"# # Split into train and valid set\n# all_images = os.listdir('/kaggle/working/yolo_slices')\n# all_images = [f[:-4] for f in all_images]\n# random.shuffle(all_images)\n# SPLIT_POINT = int(len(all_images) * 0.9)\n# train_set = all_images[:SPLIT_POINT]\n# valid_set = all_images[SPLIT_POINT:]\n\n# # Put each image/label into right directory\n# folders = [\"train/images\", \"train/labels\", \"valid/images\", \"valid/labels\"]\n# for folder in folders:\n#     if not os.path.exists(folder):\n#         os.makedirs(folder)\n        \n# for idx in train_set:\n#     jpg_file = f'/kaggle/working/yolo_slices/{idx}.jpg'\n#     txt_file = f'/kaggle/working/yolo_coords/{idx}.txt'\n    \n#     shutil.move(jpg_file, '/kaggle/working/train/images')\n#     shutil.move(txt_file, '/kaggle/working/train/labels')\n\n# for idx in valid_set:\n#     jpg_file = f'/kaggle/working/yolo_slices/{idx}.jpg'\n#     txt_file = f'/kaggle/working/yolo_coords/{idx}.txt'\n    \n#     shutil.move(jpg_file, '/kaggle/working/valid/images')\n#     shutil.move(txt_file, '/kaggle/working/valid/labels')","metadata":{"execution":{"iopub.status.busy":"2023-05-16T14:48:32.458534Z","iopub.status.idle":"2023-05-16T14:48:32.459035Z","shell.execute_reply.started":"2023-05-16T14:48:32.458797Z","shell.execute_reply":"2023-05-16T14:48:32.458819Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}