{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":61446,"databundleVersionId":6962461,"sourceType":"competition"}],"dockerImageVersionId":30579,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# **SenNet + HOA - Hacking the Human Vasculature in 3D**: <br /> Scan and Segmentation Mask Viewer Widget\nThis notebook provides a widget that allows the user to slide through scans and their associated labels in the training dataset. To run the widget, fork this notebook and run all cells.","metadata":{}},{"cell_type":"code","source":"import os\nimport warnings\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport ipywidgets as widgets","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_kg_hide-input":true,"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_img_path(train: bool, dataset: str, slice: str):\n    prefix = 'train' if train else 'test'\n    return f'/kaggle/input/blood-vessel-segmentation/{prefix}/{dataset}/images/{slice}.tif'\n\n\ndef get_label_path(train: bool, dataset: str, slice: str):\n    prefix = 'train' if train else 'test'\n    return f'/kaggle/input/blood-vessel-segmentation/{prefix}/{dataset}/labels/{slice}.tif'\n\n\ndef validate_paths():\n    exists = meta.img_path.apply(os.path.exists)\n    if exists.all():\n        return\n    n_missing = (~exists).sum()\n    warnings.warn(f'({n_missing}) image paths were missing ({100 * n_missing/len(exists):.3f}%).')\n    exists = meta.label_path.apply(os.path.exists)\n    if exists.all():\n        return\n    n_missing = (~exists).sum()\n    warnings.warn(f'({n_missing}) label paths were missing ({100 * n_missing/len(exists):.3f}%).')\n    \n\ndef load_meta():\n    out = pd.read_csv('/kaggle/input/blood-vessel-segmentation/train_rles.csv')\n    tmp = out.pop('id').str.split('_')\n    out['slice'] = tmp.apply(lambda x: x[-1])\n    out['dataset'] = tmp.apply(lambda x: '_'.join(x[:-1]))\n    out['img_path'] = out.apply(lambda x: get_img_path(train=True, dataset=x.dataset, slice=x.slice), axis=1)\n    # Fill in image paths for kidney_3_dense.\n    mask = out.dataset == 'kidney_3_dense'\n    out.loc[mask, 'img_path'] = out.slice[mask].apply(lambda x: os.path.join('/kaggle/input/blood-vessel-segmentation/train/kidney_3_sparse/images', f'{x}.tif'))    \n\n    out.loc[~out.img_path.apply(os.path.exists), 'img_path'] = np.nan\n    out['label_path'] = out.apply(lambda x: get_label_path(train=True, dataset=x.dataset, slice=x.slice), axis=1)\n    out.loc[~out.label_path.apply(os.path.exists), 'label_path'] = np.nan\n    out.sort_values(by=['dataset', 'slice'], inplace=True)\n    \n    assert not out.isnull().any().any(), out.isnull().any()\n    return out","metadata":{"_kg_hide-output":true,"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"meta = load_meta()\n#validate_paths()","metadata":{"_kg_hide-output":true,"_kg_hide-input":true,"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class _View(widgets.VBox):\n    def __init__(self):\n        super().__init__()\n        self.children = self._init_children()\n    \n    def _init_children(self):\n        self._dataset_widget = widgets.Dropdown(\n            options=meta.dataset.unique().tolist(),\n            value=None,\n            description='Dataset',\n            disabled=False\n        )\n#         self.view_plane_widget = widgets.RadioButtons(\n#             options=list(self.VIEW_PLANE_WIDGET_OPTIONS),\n#             layout={'width': 'max-content'}, # If the items' names are long\n#             description='View Plane:',\n#             disabled=False\n#         )\n        self._slice_ix_widget = widgets.IntSlider(\n            value=1,\n            min=0,\n            max=1,\n            step=1,\n            description='Slice Index',\n            disabled=False,\n            continuous_update=True,\n            orientation='horizontal',\n            readout=True,\n            readout_format='d'\n        )\n        self._labels_alpha_widget = widgets.FloatSlider(\n            value=0.3,\n            min=0.0,\n            max=1.0,\n            step=0.01,\n            description='Labels Alpha:',\n            disabled=False,\n            continuous_update=True,\n            orientation='horizontal',\n            readout=True,\n            readout_format='.2f',\n            style={'description_width': 'initial'}\n        )\n        self._info_widget = widgets.Textarea(\n            value='',\n            placeholder='',\n            description='Info:',\n            disabled=True,\n            layout=widgets.Layout(width='800px', height='60px')\n        )\n        self._img_widget = widgets.Image(\n            format='png',\n            width=600,\n        )\n\n        return [\n            self._dataset_widget,\n            #self.view_plane_widget,\n            self._slice_ix_widget,\n            self._labels_alpha_widget,\n            self._info_widget,\n            self._img_widget,\n        ]","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"debug_view = widgets.Output(layout={'border': '1px solid black'})\n\nimport cv2\nfrom PIL import Image\n\n\nclass _Controller:\n    def __init__(self, view, data):\n        super().__init__()\n        self._data = data.sort_values(by=['dataset', 'slice'])\n        self._view = view\n        self._init_handlers()\n        self._img_paths = np.array([])\n        self._label_paths = np.array([])\n    \n    def _init_handlers(self):\n        self._view._dataset_widget.observe(self.handle_dataset_update, names='value')\n#         self.view_plane_widget.observe(self.handle_view_plane_update, names='value')\n        self._view._slice_ix_widget.observe(self.handle_slice_ix_update, names='value')\n        self._view._labels_alpha_widget.observe(self.handle_labels_alpha_update, names='value')\n    \n    @debug_view.capture(clear_output=True)\n    def handle_dataset_update(self, change):\n        sub_df = self._data.loc[self._data.dataset == change['new']]\n        if sub_df.empty:\n            raise ValueError(change['new'])\n        self._view._slice_ix_widget.max = len(sub_df) - 1\n        self._img_paths = sub_df.img_path.values\n        self._label_paths = sub_df.label_path.values\n        self._view._slice_ix_widget.value = 0\n\n    def _set_current_img_data(self, ix):\n        # Load scan\n        path = self._img_paths[ix]\n        img = Image.open(path)\n        self._update_info(\n            path=path,\n            size=img.size,\n            mode=img.mode,\n        )\n        factor = (2 ** 8 - 1) / (2 ** 16 - 1)\n        img = img.point(lambda x: x * factor)\n        self._current_img = img.convert(\"RGBA\")\n    \n    def _set_current_label_data(self, ix):\n        # Load label\n        label = Image.open(self._label_paths[ix])\n        self._current_label = np.asarray(label)\n\n    def _update_img(self):\n        label = self._current_label\n        g = r = np.zeros_like(label)\n        alpha = int(self._view._labels_alpha_widget.value * (2 ** 8 - 1))\n        a = np.where(label == (2 ** 8) - 1, alpha, 0).astype(np.uint8)\n        b = label\n        label = Image.fromarray(np.dstack([r, g, b, a]))\n        \n        out = Image.alpha_composite(self._current_img, label)\n        a = np.asarray(out)\n        _, png = cv2.imencode('.png', a)\n        \n        self._view._img_widget.value = png.tobytes()\n    \n    def _update_info(self, path, size, mode):\n        self._view._info_widget.value = f'Path: {path}\\nShape: {size}\\nMode: {mode}'\n        \n    @debug_view.capture(clear_output=True)\n    def handle_slice_ix_update(self, change):\n        ix = change['new']\n        if not self._img_paths.size:\n            return\n        self._set_current_img_data(ix)\n        self._set_current_label_data(ix)\n        self._update_img()\n\n    @debug_view.capture(clear_output=True)\n    def handle_labels_alpha_update(self, change):\n        self._update_img()\n\n\ndef interact_widget():\n    view = _View()\n    controller = _Controller(view=view, data=meta)\n    return view\n\n\ndebug_view","metadata":{"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"interact_widget()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}