{"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":"code","source":"import numpy as np\nimport cv2\nimport os\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport pydicom as pyd\n\n# 3D\nfrom mpl_toolkits.mplot3d import Axes3D\nfrom skimage.measure import marching_cubes ","metadata":{"execution":{"iopub.status.busy":"2023-08-14T21:30:02.930606Z","iopub.execute_input":"2023-08-14T21:30:02.931122Z","iopub.status.idle":"2023-08-14T21:30:02.938387Z","shell.execute_reply.started":"2023-08-14T21:30:02.931086Z","shell.execute_reply":"2023-08-14T21:30:02.936974Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def read_dicom(path, voi_lut = False, fix_monochrome = True):\n    dicom = pyd.read_file(path)\n    data = dicom.pixel_array\n\n    if dicom.PhotometricInterpretation == \"MONOCHROME1\":\n        data = np.amax(data) - data\n    \n    data = data.astype(np.float32)\n    height, width = data.shape \n    \n    # Robust Scaling\n    Q1 = np.nanpercentile(data, 10)\n    Q3 = np.nanpercentile(data, 99)\n    \n    dmin = Q1\n    dmax = Q3\n    data[data<Q1]=Q1\n    data[data>Q3]=Q3\n    delta = dmax - dmin\n    data = (data - dmin) / delta\n\n    return (data * 255).astype(np.uint8), dicom\n\ndef get_3d_mesh(file_list):\n    slices = []\n    for f in file_list:\n        img, _ = read_dicom(f)\n        \n        # Find contour mask that contains all (Change this algorithm to find a better 3D mesh)\n        img = (img > np.median(img)).astype(np.uint8)\n        img = cv2.erode(img, np.ones((5, 5)))\n        contours, hierarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)\n        mask = np.zeros_like(img)\n        if len(contours) != 0:\n            c = max(contours, key = cv2.contourArea)\n            cv2.drawContours(mask, [c], -1, 255, 3)\n\n        slices.append(mask)\n\n    slices = np.array(slices).transpose(1,2,0)\n    verts, faces, _, _ = marching_cubes(slices, 0.0)\n\n    return verts, faces\n        ","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-08-14T21:30:03.209217Z","iopub.execute_input":"2023-08-14T21:30:03.210089Z","iopub.status.idle":"2023-08-14T21:30:03.22552Z","shell.execute_reply.started":"2023-08-14T21:30:03.210036Z","shell.execute_reply":"2023-08-14T21:30:03.224617Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_plot(patient_id, series_id, n_slices=10):\n    patient_root = f\"/kaggle/input/rsna-2023-abdominal-trauma-detection/train_images/{patient_id}/{series_id}/\"\n\n    files = os.listdir(patient_root)\n    files = [int(f.replace(\".dcm\",\"\")) for f in files]\n    files = sorted(files)\n\n\n    files_3d = np.linspace(files[0], files[-1], n_slices).astype(int)\n    files_2d = np.linspace(files[0], files[-1],5).astype(int)\n    verts, faces = get_3d_mesh(\n            [os.path.join(patient_root,f\"{f}.dcm\") for f in files_3d]\n    )\n\n    fig = plt.figure(figsize=(24,4))\n    ax = fig.add_subplot(151, projection='3d')\n    # Extract the x, y, and z coordinates from the vertices\n    x = verts[:, 0]\n    y = verts[:, 1]\n    z = verts[:, 2]\n\n    # Plot the mesh surface\n    ax.plot_trisurf(x, y, z, triangles=faces, cmap='viridis') # You can change the colormap as desired\n\n    # Set labels and title\n    ax.set_xlabel('X')\n    ax.set_ylabel('Y')\n    ax.set_zlabel('Z')\n    ax.set_title('3D Mesh Surface')\n\n    for k, axi in enumerate([152,153,154,155,155]):\n        ax = fig.add_subplot(axi)\n        img, _ = read_dicom(os.path.join(patient_root, f\"{files_2d[k]}.dcm\"))\n        ax.imshow(img)\n\n    # Show the plot\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2023-08-14T21:30:08.199218Z","iopub.execute_input":"2023-08-14T21:30:08.199703Z","iopub.status.idle":"2023-08-14T21:30:08.213062Z","shell.execute_reply.started":"2023-08-14T21:30:08.199665Z","shell.execute_reply":"2023-08-14T21:30:08.211647Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"patient_id = 10004   # change this\nseries_id = 21057    # change this\n\nget_plot(patient_id, series_id)","metadata":{"execution":{"iopub.status.busy":"2023-08-14T21:30:08.618237Z","iopub.execute_input":"2023-08-14T21:30:08.618761Z","iopub.status.idle":"2023-08-14T21:30:34.248803Z","shell.execute_reply.started":"2023-08-14T21:30:08.618723Z","shell.execute_reply":"2023-08-14T21:30:34.247152Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"patient_id = 10275   # change this\nseries_id = 14254    # change this\n\nget_plot(patient_id, series_id)","metadata":{"execution":{"iopub.status.busy":"2023-08-14T21:30:34.251035Z","iopub.execute_input":"2023-08-14T21:30:34.251409Z","iopub.status.idle":"2023-08-14T21:31:06.634451Z","shell.execute_reply.started":"2023-08-14T21:30:34.251375Z","shell.execute_reply":"2023-08-14T21:31:06.633186Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"patient_id = 10503   # change this\nseries_id = 60534    # change this\n\nget_plot(patient_id, series_id)","metadata":{"execution":{"iopub.status.busy":"2023-08-14T21:31:47.250845Z","iopub.execute_input":"2023-08-14T21:31:47.251331Z","iopub.status.idle":"2023-08-14T21:32:33.557784Z","shell.execute_reply.started":"2023-08-14T21:31:47.251295Z","shell.execute_reply":"2023-08-14T21:32:33.556366Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}