{"cells":[{"metadata":{},"cell_type":"markdown","source":"# HuBMAP masks and probability density function\n\n> Idea: Knowing that the glomeruli are mainly found in the cortex, we should focus on this region during training."},{"metadata":{},"cell_type":"markdown","source":"## Motivation\n\n### Background\n\nA glomerulus is a network of small blood vessels located at the beginning of a nephron in the kidney ([Wikipedia](https://en.wikipedia.org/wiki/Glomerulus_(kidney))\n)). Glomeruli are mainly found in the renal **cortex**, while the renal **medulla** contains mainly the renal tubule. Since we are dealing with biological structures, the separation is not not absolute and the transitions are not always perfectly sharp.\n\n![Diagram of a nephron](http://s3-us-west-2.amazonaws.com/courses-images/wp-content/uploads/sites/1842/2017/05/26234530/m9skcbftjqzrokkkopam.png)\n[Diagram of a nephron from libretexts.org, Introductory and General Biology](https://bio.libretexts.org/Bookshelves/Introductory_and_General_Biology/Book%3A_General_Biology_(Boundless)/41%3A_Osmotic_Regulation_and_the_Excretory_System/41.4%3A_Human_Osmoregulatory_and_Excretory_Systems/41.4B%3A_Nephron%3A_The_Functional_Unit_of_the_Kidney)\n\n### HuBMAP 2020 dataset\n\nThe [HuBMAP 2020 dataset](https://www.kaggle.com/c/hubmap-kidney-segmentation/data) comprises several Formalin Fixed Paraffin Embedded (FFPE) PAS kidney images and corresponding glumeroli segmenation masks.\n\n![](https://www.kaggleusercontent.com/kf/48229620/eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0..eO4fOXGg1ZtY-GJPoGTPsw.Wqja5ZPpE4ZWFaiKMeUFgsbT3oDfdwT0vNrftefV1WXL76dL0Ng0psniKYw8vBWEtpreMrjUU9Ms3m42nuoEPxuQd5LEtu_zp26zVUTbqc6FJ0be5IfA_Z-cxnLUOoNAqLdazqZ_daCixtEkkRUhJcP5Y3jL3mZpZpOj2hB_q7swIvcNBKUbSCDQ7Cq8RGTIJLk220fVTGoq5cX4lmWxD4nFbTtJBi_QSx94q4rUvow898mxE9OTmpQvTlq4BNG-v7FlgMlkGDmV3IbP15Hualc3jh5kf8BiUVIRGq6rOZsoGF9W2X_egRt2GvjOrdKApkldh3caX5-2v8GZ560XDcZbQ139IixsJxZ8mP9jQXYO4jfG3uasd4Uqbf0DeLwXf5_KJ9eKR56M6mBflueyTtO2-Nm0OR9YbeJqAR95OHw-3egZ0SvZUCUb-PI7nFxDzjOWAb7Vc0_Fq_K9P_0cPhG-8bkDPNfWtLgGM0OJLgiBq0-iMMxJO_F3yuyVhI2QpSDqvJ8jTFvvfK8bqXlruFoSDo-ypTT9CMVkImokF0cBmo5TUrN1p03SaNT5O8jasrn8XdYCRraoqooivlebfrjsplfngo90KtbQdk8kyN0Ud97-DTEtWaNoZ22SWL5N5flwAUg26rh9xzfpN9lANvV56D98ua1-XiSAHIFbies.u-bNjVwxqDpkJ_vFdlP_GQ/__results___files/__results___30_0.png)\n[Example image 0486052bb, taken from ihelons EDA Notebook](https://www.kaggle.com/ihelon/hubmap-exploratory-data-analysis)\n\nBoth the training and public test sets also include anatomical structure segmentations (Example from this [notebook](https://www.kaggle.com/matjes/hubmap-anatomy-zarr), green=Cortex, yellow=Medulla)\n\n![](https://www.kaggleusercontent.com/kf/56694565/eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0..qGrbhci55WIxOMKHmwicjw.mgaY_seAj93TAYBdJaOgDP42sKLsBIUnUZW-bSqxcBTLaf_ovcCKDIkgwwnlw6qSPb4Z-QipJipsbek3aXzcOKOYvfvs8H0cKWxBPZ5jqNBLQkx3Q1is2ScTA2nDsA-H8zinmIaBNPH7sX53ZxpnX7bBQQfUlAKM7IJnuxOoLBhfqzEh7wXx5BgDYepzZlKvvM9OH09qcSsTQ2j0QwDfHc7cM-LaRtk1zEPbGaxED1eZS1aBvcHZKt5npSlgqf-cLDCzck2YB1MkdMiUoxlDFaZi8D4fD_ZYEfN3Hc4alQVLfKAdpGyqGeSgjhc_x5L6NkGf10eDzY9pfVKX2uNHbltOMrcpEoySOTSfpRrnKEzlUnjQ3c8h_dLjvNIbO_XUboEQuLXLYaAepYZv-xTfir34OzXQyjAgRnEbyZ4jMdts2nqZ2buwTWyJASs-MMaIuh3Lnw3JP3Enub_zdEaNfkcpsuvXvIyfr2lc5n0wP1gaJ_jM83CwVTrmrkHMa7FAsjM4ak0sfp7VAFjYcul-yMga17xf3Oqk8IisQjLpAcbGr_V0GVk_LFDoHD3oYjAIuLQL0H0r87hXn0A4z8q0vBaPQRZ5QP3gONya12gOFEwqzeqfFujbfc1NbEXAP2rwELDKX3I5MyFk81IgnbvJU_AyIkE7v59W-ThGWrmICzI.iFYFPts-eAsVDZ0ASGCmOQ/__results___files/__results___5_33.png)\n\n[Anatomical structure of 0486052bb](https://www.kaggle.com/matjes/hubmap-anatomy-zarr)\n\n\n### Key Idea\n\nA common approach to deal with the very large (>500MB - 5GB) TIFF files in the dataset is to decompose the images in smaller patches/tiles, for instance by using a sliding window apporach.\n> **Knowing that the glomeruli are mainly found in the cortex, we should focus on this region during training**. \n\nInstead of preprocessing the images and saving them into fixed tiles, we randomly sample random tiles from the entire images with a higher probability to sample tiles that contain glumeroli and cortex.\n\n\n## Advantages of this approach\n\nIn combination with [deepflash2](https://github.com/matjesg/deepflash2/tree/master/) and the deepflash2 [pytorch datasets](https://matjesg.github.io/deepflash2/data.html#Datasets) in particular, this approach has several advantages:\n- no preprocessing of the data (only saving them to .zarr files for memory efficient loading)\n    - flexible tile shapes (input shapes, e.g. 1024, 512, 256) at runtime\n    - flexible scaling (e.g., by facors of 2,3,4)\n- faster convergence during traing\n    - focusing on the relevant regions (e.g., tiles that contain glumeroli and cortex)\n    - \"additional\" data augmentation from random sampling (compared to fixed windows)"},{"metadata":{},"cell_type":"markdown","source":"## Implementation (masks and probability density function)\n\n> - Create segmentations masks from RLE\n> - Create probability density function (PDF) for efficient sampling from mask and anatmical structure\n\n\n**Inputs**\n- RLE glumeroli segmentations ([challenge dataset](https://www.kaggle.com/c/hubmap-kidney-segmentation/data))\n- Anatomical region masks ([.zarr converted](https://www.kaggle.com/matjes/hubmap-anatomy-zarr))\n    - Values: 0=other, 1=cortex, 2=medulla\n    \n\n**Settings**\n\nThe name of the notbook contains the parameters of the probability density function. \nGlumeroli pixels are fixed with a sampling weight of 1. Then, for instance, *pdf_0.5_0.25_0.01* means:\n\n- Sampling weight for cortex regions (`cortex_value`): 0.5 \n- Sampling weight for medulla regions (`medulla_value`): 0.25\n- Sampling weight for other regions (`fbr`, foreground-background-ratio): 0.01       \n"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"# Install zarr and load packages\n!pip install -qq zarr\nimport cv2, zarr, gc\nimport matplotlib.pyplot as plt, numpy as np, pandas as pd\nfrom pathlib import Path\ngc.enable()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"# from https://www.kaggle.com/paulorzp/rle-functions-run-lenght-encode-decode\ndef rle2mask(mask_rle, shape):\n    '''\n    mask_rle: run-length as string formated (start length)\n    shape: (width,height) of array to return \n    Returns numpy array, 1 - mask, 0 - background\n\n    '''\n    s = mask_rle.split()\n    starts, lengths = [\n        np.asarray(x, dtype=int) for x in (s[0:][::2], s[1:][::2])\n    ]\n    starts -= 1\n    ends = starts + lengths\n    img = np.zeros(shape[0] * shape[1], dtype=np.uint8)\n    for lo, hi in zip(starts, ends):\n        img[lo : hi] = 1\n    return img.reshape(shape).T","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Settings"},{"metadata":{"trusted":true},"cell_type":"code","source":"scale = 2\nresize=512 # For pdf\n\n# Input \npath = Path('/kaggle/input/hubmap-kidney-segmentation')\ndf_train = pd.read_csv(path/\"train.csv\")\ndf_info = pd.read_csv(path/\"HuBMAP-20-dataset_information.csv\")\ngrp_anatomy = zarr.open_group('../input/hubmap-anatomy-zarr/anatomy')\n\n# PDF Setting\nweight_dict = {\n    'fbr': 0.01,          # Background Weights\n    'cortex_value': 0.5,  # Cortex Weights\n    'medulla_value': 0.25 # Medulla Weights\n}\n\n# Output\nroot = zarr.group(f'/kaggle/working/masks_scale{scale}')\ng_msk, g_pdf = root.create_groups('labels', 'pdfs', overwrite=True)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Conversion"},{"metadata":{"trusted":true},"cell_type":"code","source":"for _, row in df_train.iterrows():\n    \n    idx = row.id\n    img_info = df_info[df_info.image_file==f'{idx}.tiff']\n    shape = (img_info.height_pixels.values[0], img_info.width_pixels.values[0])\n    print(idx, 'with shape', shape)\n    \n    msk = rle2mask(row.encoding, (shape[1], shape[0])).astype('uint8')\n    \n    # Plot\n    fig, ax = plt.subplots(ncols=2, figsize=(15,15))\n    resize_w = int((msk.shape[1]/msk.shape[0])*resize)\n    ax[0].imshow(cv2.resize(msk, dsize=(resize_w, resize)))\n    ax[0].set_title('Mask')\n    ax[0].set_axis_off()\n    \n    anatomy = grp_anatomy[idx][:]\n    \n    if scale:\n        new_size = (msk.shape[1] // scale, msk.shape[0] // scale)\n        print('Scaling to', new_size)\n        msk = cv2.resize(msk, new_size)\n        anatomy = cv2.resize(anatomy, new_size)\n        \n    anatomy = anatomy.astype('float16')     \n    anatomy[anatomy==0] = weight_dict['fbr']\n    anatomy[anatomy==1] = weight_dict['cortex_value']\n    anatomy[anatomy>1] = weight_dict['medulla_value']\n    anatomy[msk>0] = 1\n    \n    print('Saving msk')\n    g_msk[idx] = msk\n    del msk\n    gc.collect()\n        \n    if resize:\n        print('Resizing PDF')\n        if anatomy.shape[0]>resize:\n            resize_w = int((anatomy.shape[1]/anatomy.shape[0])*resize)\n            anatomy = cv2.resize(anatomy[:].astype('float32'), dsize=(resize_w, resize))\n            \n    ax[1].imshow(anatomy)\n    ax[1].set_title('Probability density function for sampling')\n    ax[1].set_axis_off() \n            \n    print('Saving pdf cumsum')\n    g_pdf[idx] = np.cumsum(anatomy/np.sum(anatomy)) \n\n    plt.show()","execution_count":null,"outputs":[]}],"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":4,"nbformat_minor":4}