{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.7.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":36363,"databundleVersionId":4050810,"sourceType":"competition"},{"sourceId":6974691,"sourceType":"datasetVersion","datasetId":4007672},{"sourceId":6974891,"sourceType":"datasetVersion","datasetId":4007814},{"sourceId":6975086,"sourceType":"datasetVersion","datasetId":4007928},{"sourceId":6979150,"sourceType":"datasetVersion","datasetId":4010520},{"sourceId":6979419,"sourceType":"datasetVersion","datasetId":4010702}],"dockerImageVersionId":30028,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"pip install typing-extensions --upgrade\n","metadata":{"execution":{"iopub.status.busy":"2024-01-06T13:00:38.530192Z","iopub.execute_input":"2024-01-06T13:00:38.530535Z","iopub.status.idle":"2024-01-06T13:03:14.356512Z","shell.execute_reply.started":"2024-01-06T13:00:38.530501Z","shell.execute_reply":"2024-01-06T13:03:14.355448Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install matplotlib","metadata":{"execution":{"iopub.status.busy":"2024-01-06T13:05:06.338013Z","iopub.execute_input":"2024-01-06T13:05:06.33837Z","iopub.status.idle":"2024-01-06T13:05:33.578055Z","shell.execute_reply.started":"2024-01-06T13:05:06.338336Z","shell.execute_reply":"2024-01-06T13:05:33.577152Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install pydicom","metadata":{"execution":{"iopub.status.busy":"2024-01-06T13:05:33.579946Z","iopub.execute_input":"2024-01-06T13:05:33.580252Z","iopub.status.idle":"2024-01-06T13:06:00.798011Z","shell.execute_reply.started":"2024-01-06T13:05:33.58022Z","shell.execute_reply":"2024-01-06T13:06:00.797115Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from tqdm import tqdm\nimport os\nimport glob\nfrom random import randint\nimport numpy as np\nimport pandas as pd\nimport nibabel as nib\nimport pydicom as pdm\nimport pydicom\nimport nilearn as nl\nimport nilearn.plotting as nlplt\n#import nrrd\n#import h5py\nimport matplotlib.pyplot as plt\nfrom matplotlib import cm\nimport matplotlib.animation as anim\nimport matplotlib.patches as mpatches\nimport matplotlib.gridspec as gridspec\nimport imageio\nfrom skimage.transform import resize\nfrom skimage.util import montage\nfrom IPython.display import Image as show_gif\n\nimport warnings\nwarnings.simplefilter(\"ignore\")","metadata":{"execution":{"iopub.status.busy":"2024-01-06T13:07:46.421437Z","iopub.execute_input":"2024-01-06T13:07:46.421841Z","iopub.status.idle":"2024-01-06T13:07:47.930527Z","shell.execute_reply.started":"2024-01-06T13:07:46.421804Z","shell.execute_reply":"2024-01-06T13:07:47.929692Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The easiest way to render a 3d image is to draw its slices one by one in 2d , for easy viewing we can make a GIF from each slice","metadata":{}},{"cell_type":"code","source":"class ImageToGIF:\n    \"\"\"Create GIF without saving image files.\"\"\"\n    def __init__(self,\n                 size=(600, 400), \n                 xy_text=(80, 10),\n                 dpi=100, \n                 cmap='CMRmap'):\n\n        self.fig = plt.figure()\n        self.fig.set_size_inches(size[0] / dpi, size[1] / dpi)\n        self.xy_text = xy_text\n        self.cmap = cmap\n        \n        self.ax = self.fig.add_axes([0, 0, 1, 1])\n        self.ax.set_xticks([])\n        self.ax.set_yticks([])\n        self.images = []\n \n    def add(self, *args, label, with_mask=True):\n        \n        image = args[0]\n        mask = args[-1]\n        plt.set_cmap(self.cmap)\n        plt_img = self.ax.imshow(image, animated=True)\n        if with_mask:\n            plt_mask = self.ax.imshow(np.ma.masked_where(mask == False, mask),\n                                      alpha=0.7, animated=True)\n\n        plt_text = self.ax.text(*self.xy_text, label, color='red')\n        to_plot = [plt_img, plt_mask, plt_text] if with_mask else [plt_img, plt_text]\n        self.images.append(to_plot)\n        plt.close()\n \n    def save(self, filename, fps):\n        animation = anim.ArtistAnimation(self.fig, self.images)\n        animation.save(filename, writer='imagemagick', fps=fps)\n        \n################################From pixel to voxel###############################################  \n        \nclass Image3dToGIF3d:\n    \"\"\"\n    Displaying 3D images in 3d axes.\n    Parameters:\n        img_dim: shape of cube for resizing.\n        figsize: figure size for plotting in inches.\n    \"\"\"\n    def __init__(self, \n                 img_dim: tuple = (55, 55, 55),\n                 figsize: tuple = (15, 10),\n                ):\n        \"\"\"Initialization.\"\"\"\n        self.img_dim = img_dim\n        print(img_dim)\n        self.figsize = figsize\n    \n    def _explode(self, data: np.ndarray):\n        \"\"\"\n        Takes: array and return an array twice as large in each dimension,\n        with an extra space between each voxel.\n        \"\"\"\n        shape_arr = np.array(data.shape)\n        size = shape_arr[:3] * 2 - 1\n        exploded = np.zeros(np.concatenate([size, shape_arr[3:]]),\n                            dtype=data.dtype)\n        exploded[::2, ::2, ::2] = data\n        return exploded\n\n    def _expand_coordinates(self, indices: np.ndarray):\n        x, y, z = indices\n        x[1::2, :, :] += 1\n        y[:, 1::2, :] += 1\n        z[:, :, 1::2] += 1\n        return x, y, z\n    \n    def _normalize(self, arr: np.ndarray):\n        \"\"\"Normilize image value between 0 and 1.\"\"\"\n        return arr / arr.max()\n    \n    def _scale_by(self, arr: np.ndarray, factor: int):\n        \"\"\"\n        Scale 3d Image to factor.\n        Parameters:\n            arr: 3d image for scalling.\n            factor: factor for scalling.\n        \"\"\"\n        mean = np.mean(arr)\n        return (arr - mean) * factor + mean\n    \n    def get_transformed_data(self, data: np.ndarray):\n        \"\"\"Data transformation: normalization, scaling, resizing.\"\"\"\n        norm_data = np.clip(self._normalize(data)-0.1, 0, 1) ** 0.4\n        scaled_data = np.clip(self._scale_by(norm_data, 2) - 0.1, 0, 1)\n        resized_data = resize(scaled_data, self.img_dim, mode='constant')\n        return resized_data\n    \n    def plot_cube(self,\n                  cube,\n                  title: str = '', \n                  init_angle: int = 0,\n                  make_gif: bool = False,\n                  path_to_save: str = 'filename.gif'\n                 ):\n        \"\"\"\n        Plot 3d data.\n        Parameters:\n            cube: 3d data\n            title: title for figure.\n            init_angle: angle for image plot (from 0-360).\n            make_gif: if True create gif from every 5th frames from 3d image plot.\n            path_to_save: path to save GIF file.\n            \"\"\"\n        cube = self._normalize(cube)\n\n        facecolors = cm.gist_stern(cube)\n        facecolors[:,:,:,-1] = cube\n        facecolors = self._explode(facecolors)\n\n        filled = facecolors[:,:,:,-1] != 0\n        x, y, z = self._expand_coordinates(np.indices(np.array(filled.shape) + 1))\n\n        with plt.style.context(\"dark_background\"):\n\n            fig = plt.figure(figsize=self.figsize)\n            ax = fig.gca(projection='3d')\n\n            ax.view_init(30, init_angle)\n            ax.set_xlim(right = self.img_dim[0] * 2)\n            ax.set_ylim(top = self.img_dim[1] * 2)\n            ax.set_zlim(top = self.img_dim[2] * 2)\n            ax.set_title(title, fontsize=18, y=1.05)\n\n            ax.voxels(x, y, z, filled, facecolors=facecolors, shade=False)\n\n            if make_gif:\n                images = []\n                for angle in tqdm(range(0, 360, 5)):\n                    ax.view_init(30, angle)\n                    fname = str(angle) + '.png'\n\n                    plt.savefig(fname, dpi=120, format='png', bbox_inches='tight')\n                    images.append(imageio.imread(fname))\n                    #os.remove(fname)\n                imageio.mimsave(path_to_save, images)\n                plt.close()\n\n            else:\n                plt.show()","metadata":{"execution":{"iopub.status.busy":"2024-01-06T13:07:58.365294Z","iopub.execute_input":"2024-01-06T13:07:58.365702Z","iopub.status.idle":"2024-01-06T13:07:58.406097Z","shell.execute_reply.started":"2024-01-06T13:07:58.365664Z","shell.execute_reply":"2024-01-06T13:07:58.405206Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"","metadata":{}},{"cell_type":"markdown","source":"#Get the input for processing","metadata":{}},{"cell_type":"code","source":"sample_filename = '../input/rsna-2022-cervical-spine-fracture-detection/segmentations/1.2.826.0.1.3680043.18480.nii'\nsample_filename_mask = '../input/rsna-2022-cervical-spine-fracture-detection/segmentations/1.2.826.0.1.3680043.18480.nii'\n\nsample_img = nib.load(sample_filename)\nsample_img = np.asanyarray(sample_img.dataobj)\nsample_mask = nib.load(sample_filename_mask)\nsample_mask = np.asanyarray(sample_mask.dataobj)\nprint(\"img shape ->\", sample_img.shape)\nprint(\"mask shape ->\", sample_mask.shape)","metadata":{"execution":{"iopub.status.busy":"2024-01-06T13:08:05.01626Z","iopub.execute_input":"2024-01-06T13:08:05.016641Z","iopub.status.idle":"2024-01-06T13:08:05.041217Z","shell.execute_reply.started":"2024-01-06T13:08:05.016604Z","shell.execute_reply":"2024-01-06T13:08:05.040318Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Rendering the images into slices","metadata":{}},{"cell_type":"markdown","source":"visualization of 3d data in 2d slices","metadata":{}},{"cell_type":"code","source":"slice_n = 100\nfig, ax = plt.subplots(2, 3, figsize=(20, 12))\n\nax[0, 0].imshow(sample_img[slice_n, :, :])\nax[0, 0].set_title(f\"image slice number {slice_n} along the x-axis\", fontsize=16, color=\"red\")\nax[1, 0].imshow(sample_mask[slice_n, :, :])\nax[1, 0].set_title(f\"mask slice {slice_n} along the x-axis\", fontsize=16, color=\"red\")\n\nax[0, 1].imshow(sample_img[:, slice_n, :])\nax[0, 1].set_title(f\"image slice number {slice_n} along the y-axis\", fontsize=16, color=\"red\")\nax[1, 1].imshow(sample_mask[:, slice_n, :])\nax[1, 1].set_title(f\"mask slice number {slice_n} along the y-axis\", fontsize=16, color=\"red\")\n\nax[0, 2].imshow(sample_img[:, :, slice_n])\nax[0, 2].set_title(f\"image slice number {slice_n} along the z-axis\", fontsize=16, color=\"red\")\nax[1, 2].imshow(sample_mask[:, :, slice_n])\nax[1, 2].set_title(f\"mask slice number {slice_n}along the z-axis\", fontsize=16, color=\"red\")\nfig.tight_layout()\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2024-01-06T13:08:08.983947Z","iopub.execute_input":"2024-01-06T13:08:08.984297Z","iopub.status.idle":"2024-01-06T13:08:12.101913Z","shell.execute_reply.started":"2024-01-06T13:08:08.984266Z","shell.execute_reply":"2024-01-06T13:08:12.101076Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"## matching colormaps\n#Greys_r RdGy_r  CMRmap afmhot binary_r bone copper cubehelix gist_heat gist_stern gnuplot hot inferno magma nipy_spectral\n\nsample_data_gif = ImageToGIF()\nlabel = sample_filename.replace('/', '.').split('.')[-2]\nfilename = f'{label}_3d_2d.gif'\n\nfor i in range(sample_img.shape[0]):\n    image = np.rot90(sample_img[i])\n    mask = np.clip(np.rot90(sample_mask[i]), 0, 1)\n    sample_data_gif.add(image, mask,label=f'{label}_{str(i)}')\n \nsample_data_gif.save(filename, fps=15)\nshow_gif(filename, format='png')","metadata":{"execution":{"iopub.status.busy":"2024-01-06T13:08:30.156642Z","iopub.execute_input":"2024-01-06T13:08:30.157015Z","iopub.status.idle":"2024-01-06T13:10:17.527984Z","shell.execute_reply.started":"2024-01-06T13:08:30.156983Z","shell.execute_reply":"2024-01-06T13:10:17.526313Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"image = np.rot90(montage(sample_img))\nmask = np.rot90(montage(sample_mask)) \nmask = np.clip(mask, 0, 1)\n\nfig, ax1 = plt.subplots(1, 1, figsize = (20, 20))\nax1.imshow(image, cmap ='bone')\nax1.imshow(np.ma.masked_where(mask == False, mask),\n           cmap='cool', alpha=0.6, animated=True)\nfig.savefig(f'{label}_3d_to_2d.png', format='png', bbox_inches='tight', pad_iches=0.0)","metadata":{"execution":{"iopub.status.busy":"2024-01-06T13:13:19.662582Z","iopub.execute_input":"2024-01-06T13:13:19.663004Z","iopub.status.idle":"2024-01-06T13:14:00.679759Z","shell.execute_reply.started":"2024-01-06T13:13:19.662962Z","shell.execute_reply":"2024-01-06T13:14:00.678672Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"and 3d","metadata":{}},{"cell_type":"code","source":"%%time\ntitle = sample_filename.replace(\".\", \"/\").split(\"/\")[-2]\nfilename = title+\"_3d.gif\"\n\ndata_to_3dgif = Image3dToGIF3d()#img_dim = (120, 120, 78)\ntransformed_data = data_to_3dgif.get_transformed_data(sample_img)\ndata_to_3dgif.plot_cube(\n    #transformed_data[:38, :47, :35]#,[:77, :105, :55]\n    transformed_data[:38, :47, :35],\n    title=title,\n    make_gif=True,\n    path_to_save=filename\n)\nshow_gif(filename, format='png')","metadata":{"execution":{"iopub.status.busy":"2024-01-06T13:14:11.838959Z","iopub.execute_input":"2024-01-06T13:14:11.839333Z","iopub.status.idle":"2024-01-06T13:39:09.837267Z","shell.execute_reply.started":"2024-01-06T13:14:11.839298Z","shell.execute_reply":"2024-01-06T13:39:09.835568Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import re\nimport cv2\nimport random\nfrom glob import glob\nfrom pprint import pprint\nimport warnings\nimport itertools\nimport pandas as pd\nimport numpy as np\nimport seaborn as sns\nimport matplotlib.patches as patches\nimport matplotlib.pyplot as plt\nfrom matplotlib.colors import ListedColormap\nfrom IPython.display import display_html\n\nplt.rcParams.update({'font.size': 16})\n\n# .dcm handling\nimport pydicom\nimport nibabel as nib\nfrom pydicom.pixel_data_handlers.util import apply_voi_lut\n\n# Environment check\nwarnings.filterwarnings('ignore')","metadata":{"execution":{"iopub.status.busy":"2024-01-06T13:40:19.381015Z","iopub.execute_input":"2024-01-06T13:40:19.381424Z","iopub.status.idle":"2024-01-06T13:40:19.389239Z","shell.execute_reply.started":"2024-01-06T13:40:19.381384Z","shell.execute_reply":"2024-01-06T13:40:19.38829Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Custom colors\nclass clr:\n    S = '\\033[1m' + '\\033[94m'\n    E = '\\033[0m'\n\n\nmy_colors = [\n    '#5EAFD9',\n    '#449DD1',\n    '#3977BB',\n    '#2D51A5',\n    '#5C4C8F',\n    '#8B4679',\n    '#C53D4C',\n    '#E23836',\n    '#FF4633',\n    '#FF5746',\n]\nCMAP1 = ListedColormap(my_colors)","metadata":{"execution":{"iopub.status.busy":"2024-01-06T13:40:24.891074Z","iopub.execute_input":"2024-01-06T13:40:24.891396Z","iopub.status.idle":"2024-01-06T13:40:24.896751Z","shell.execute_reply.started":"2024-01-06T13:40:24.891368Z","shell.execute_reply":"2024-01-06T13:40:24.895795Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Get .nii paths\nnii_paths = glob('../input/rsna-2022-cervical-spine-fracture-detection/segmentations/*')\nprint(f'{clr.S}Total paths in [segmentations] folder:{clr.E}', len(nii_paths))","metadata":{"execution":{"iopub.status.busy":"2024-01-06T13:40:30.497407Z","iopub.execute_input":"2024-01-06T13:40:30.497795Z","iopub.status.idle":"2024-01-06T13:40:30.534315Z","shell.execute_reply.started":"2024-01-06T13:40:30.49776Z","shell.execute_reply":"2024-01-06T13:40:30.533427Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class DrawMaskSample:\n    def __init__(self, nii_paths, i, ax):\n        self.xyz_li = None\n        self.i = i\n        self.ax = ax\n        self.nii_sample = nib.load(nii_paths[self.i]).get_fdata()\n        self.get_xyz()\n        self.draw_sample_3d()\n\n    def get_xyz(self):\n        self.xyz_li = []\n        cnt = 0\n        max_cnt = self.nii_sample.shape[-1]\n        for iter_z, (iter_img) in enumerate(self.nii_sample.transpose(2, 0, 1)):\n            for iter_x, iter_arr_y in enumerate(iter_img):\n                iter_arr_y = np.where(iter_arr_y)[0]\n                if len(iter_arr_y) >= 1:\n                    iter_arr_y = list(\n                        {iter_arr_y.max(), iter_arr_y.min()})\n                    xyz = [\n                        (iter_x, iter_y, iter_z)\n                        for iter_y in iter_arr_y\n                        if np.any(iter_y)\n                    ]\n                    self.xyz_li.append(xyz)\n            cnt += 1\n\n    def draw_sample_3d(self):\n        xyz_matrix = np.array(list(itertools.chain.from_iterable(self.xyz_li)))\n        X = xyz_matrix[:, 0]\n        Y = xyz_matrix[:, 1]\n        Z = xyz_matrix[:, 2]\n\n        self.ax.scatter(X, Y, Z, s=1, alpha=0.05, color='#e3dac9')\n        xlim, ylim, zlim = self.nii_sample.shape\n        self.ax.set_xlim(0, xlim)\n        self.ax.set_ylim(0, ylim)\n        self.ax.set_zlim(0, zlim)\n        self.ax.set_title(f'sample - ({self.i + 1})')\n        self.ax.set_yticklabels([])\n        self.ax.set_xticklabels([])\n        self.ax.set_zticklabels([])\n        self.ax.set_facecolor('#081921')","metadata":{"execution":{"iopub.status.busy":"2024-01-06T13:40:37.191835Z","iopub.execute_input":"2024-01-06T13:40:37.192174Z","iopub.status.idle":"2024-01-06T13:40:37.208917Z","shell.execute_reply.started":"2024-01-06T13:40:37.192143Z","shell.execute_reply":"2024-01-06T13:40:37.208065Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"conversion of 3d gif to 2d","metadata":{}},{"cell_type":"code","source":"fig = plt.figure(figsize=(24, 24))\nfor i in range(9):\n    ax = fig.add_subplot(int(f'33{i + 1}'), projection='3d')\n    DrawMaskSample(nii_paths, i, ax)\n\nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-01-06T13:40:46.206738Z","iopub.execute_input":"2024-01-06T13:40:46.207112Z","iopub.status.idle":"2024-01-06T13:41:29.5282Z","shell.execute_reply.started":"2024-01-06T13:40:46.207074Z","shell.execute_reply":"2024-01-06T13:41:29.527014Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"","metadata":{}},{"cell_type":"code","source":"","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"","metadata":{}},{"cell_type":"markdown","source":"","metadata":{}},{"cell_type":"markdown","source":"","metadata":{}},{"cell_type":"markdown","source":"","metadata":{}},{"cell_type":"markdown","source":"","metadata":{}}]}