{"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":"<br>\n\n<a id=\"imports\"></a>\n\n<h1 style=\"font-family: Verdana; font-size: 24px; font-style: normal; font-weight: bold; text-decoration: none; text-transform: none; letter-spacing: 3px; background-color: #ffffff; color: #E55CA0;\" id=\"imports\">0&nbsp;&nbsp;IMPORTS & INSTALLS&nbsp;&nbsp;&nbsp;&nbsp;<a href=\"#toc\">&#10514;</a></h1>\n\n<br>\n\n**PYVIPS INSTALL CODE ONLY WORKS PINNED TO ORIGINAL ENVIRONMENT (2020)**\n- Original: https://www.kaggle.com/hirune924/fast-image-region-loading-using-pyvips\n  - Thanks for @hirune924 !!\n- https://www.kaggle.com/code/yukkyo/using-pyvips-without-internet/comments\n- Install needs about 5 minutes\n\n**I'M NOT SURE WHY BUT THIS ONLY WORKS WHEN A GPU IS ATTACHED...**","metadata":{}},{"cell_type":"code","source":"print(\"\\n... INSTALLING LOCAL VERSION OF PYVIPS! ...\")\n!dpkg -i --force-depends /kaggle/input/pyvips-local/libvips-apt/libvips-apt/*.deb >/dev/null 2>&1\n!pip install /kaggle/input/pyvips-local/cffi-1.14.4-cp37-cp37m-manylinux1_x86_64.whl\n!pip install /kaggle/input/pyvips-local/pycparser-2.20-py2.py3-none-any.whl\n!pip install /kaggle/input/pyvips-local/pyvips-2.1.13-py2.py3-none-any.whl\n\nfrom PIL import Image; Image.MAX_IMAGE_PIXELS = 5_000_000_000;\nimport matplotlib.pyplot as plt\nimport pandas as pd\nimport numpy as np\nimport cv2 # for resize\nimport pyvips\nimport os\n\nprint(\"... INSTALL COMPLETE! ...\\n\")","metadata":{"execution":{"iopub.status.busy":"2022-07-17T01:51:03.07208Z","iopub.execute_input":"2022-07-17T01:51:03.072434Z","iopub.status.idle":"2022-07-17T01:53:22.170365Z","shell.execute_reply.started":"2022-07-17T01:51:03.072395Z","shell.execute_reply":"2022-07-17T01:53:22.169406Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<br>\n\n<a id=\"helper_functions\"></a>\n\n<h1 style=\"font-family: Verdana; font-size: 24px; font-style: normal; font-weight: bold; text-decoration: none; text-transform: none; letter-spacing: 3px; background-color: #ffffff; color: #E55CA0;\" id=\"helper_functions\">1&nbsp;&nbsp;HELPER FUNCTIONS&nbsp;&nbsp;&nbsp;&nbsp;<a href=\"#toc\">&#10514;</a></h1>","metadata":{}},{"cell_type":"code","source":"# vips image to numpy array\ndef vips2numpy(vi):\n    \n    # map vips formats to np dtypes\n    format_to_dtype = {\n        'uchar': np.uint8,       'char': np.int8,\n        'ushort': np.uint16,     'short': np.int16,\n        'uint': np.uint32,       'int': np.int32,\n        'float': np.float32,     'double': np.float64,\n        'complex': np.complex64, 'dpcomplex': np.complex128,\n    }\n    \n    # Return newly written np.ndarray\n    return np.ndarray(buffer=vi.write_to_memory(),\n                      dtype=format_to_dtype[vi.format],\n                      shape=[vi.height, vi.width, vi.bands])\n\ndef pyvips_open_downsampled_slide(img_path, downsample_by=8, as_numpy=True, resize_to=(512,512)):\n    \"\"\"\n    \n    Helper function to convert WSI into smaller downscaled version using pyvips.\n    \n    Timing details for MAYO CLINIC STRIP AI dataset:\n        SMALLEST IMAGE BY AREA (4417, 5314)\n            * Function takes ~1 seconds to run\n        MEDIAN IMAGE BY AREA   (17573, 38743)(~30X LARGER THAN SMALLEST IMAGE)\n            * Function takes ~30 seconds to run\n        LARGEST IMAGE BY AREA  (48282, 101406)(~208X LARGER THAN SMALLEST IMAGE)(~7X LARGER THAN MEDIAN IMAGE)\n            * Function takes ~405 seconds to run\n    \n    Args:\n        img_path (str): Path to .tif file to be downsampled\n        downsample_by (int): How many times smaller should resultant \n            image be. i.e. image_size*(1/downsample_by) = new_size\n            -1 will yield maximum downsample above resized image shape\n        as_numpy (bool, optional): Whether to return image as numpy array (default)\n           or leave as PIL.Image object for further manipulation\n        resize_to (tuple of ints, optional): What to resize the downsampled image to\n    \n    Returns:\n        Downsampled image as a numpy array of type uint8 with only 3 channels\n    \"\"\"\n    \n    # Open the image with PIL\n    tmp_img = pyvips.Image.new_from_file(img_path)    \n    \n    print(\"\\n... APPROXIMATE TIME TO LOAD IMAGE IS AT MOST APPROXIMATELY: \" \\\n          f\"{int((405/(48282*101406))*(tmp_img.width*tmp_img.height))} SECONDS ...\\n\")\n    \n    # if -1 than we downsample by whatever results in the image having dimensions as\n    # close to 512x512 as possible so the image can be resized after\n    \n    if downsample_by==-1:\n        _epsilon = 1e-3\n        downsample_by=min(tmp_img.width, tmp_img.height)/resize_to[0]-_epsilon\n    \n    # Resize the image\n    tmp_img = tmp_img.resize(1/downsample_by)\n    tmp_img = vips2numpy(tmp_img) if as_numpy else tmp_img\n    tmp_img = cv2.resize(tmp_img, resize_to) if resize_to is not None else tmp_img\n    \n    return tmp_img","metadata":{"execution":{"iopub.status.busy":"2022-07-17T01:53:22.172107Z","iopub.execute_input":"2022-07-17T01:53:22.172368Z","iopub.status.idle":"2022-07-17T01:53:22.185317Z","shell.execute_reply.started":"2022-07-17T01:53:22.172343Z","shell.execute_reply":"2022-07-17T01:53:22.184427Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<br>\n\n<a id=\"demo\"></a>\n\n<h1 style=\"font-family: Verdana; font-size: 24px; font-style: normal; font-weight: bold; text-decoration: none; text-transform: none; letter-spacing: 3px; background-color: #ffffff; color: #E55CA0;\" id=\"demo\">2&nbsp;&nbsp;DEMO&nbsp;&nbsp;&nbsp;&nbsp;<a href=\"#toc\">&#10514;</a></h1>\n\n<br>","metadata":{}},{"cell_type":"code","source":"print(\"\\n... BASIC SETUP STARTING ...\\n\\n\")\n\n# Path to competition data\nDATA_DIR = \"/kaggle/input/mayo-clinic-strip-ai\"\nTRAIN_DIR = os.path.join(DATA_DIR, \"train\")\nTRAIN_CSV = os.path.join(DATA_DIR, \"train.csv\")\ntrain_df = pd.read_csv(TRAIN_CSV)\ntrain_df[\"image_path\"] = train_df[\"image_id\"].apply(lambda x: os.path.join(TRAIN_DIR, x+\".tif\"))\n\nprint(\"\\n... TRAINING DATAFRAME... \\n\")\ndisplay(train_df)\n\n# Capture examples that span smallest, median, and large image size examples\nSMALLEST_IMAGE_ID = \"b43ebe_0\"\nSMALLEST_IMAGE_ROW = train_df[train_df.image_id==SMALLEST_IMAGE_ID]\nMEDIAN_IMAGE_ID = \"719165_0\"\nMEDIAN_IMAGE_ROW = train_df[train_df.image_id==MEDIAN_IMAGE_ID]\nLARGEST_IMAGE_ID = \"6baf51_0\"\nLARGEST_IMAGE_ROW = train_df[train_df.image_id==LARGEST_IMAGE_ID]\n\n# Prove that we can infer on all image sizes available in training dataset \n#   --> (smallest, median and largest)\nplt.figure(figsize=(20,15))\n\nprint(\"\\n\\n\\n... DEMO FOR SMALLEST, MEDIAN, & LARGEST (WOULD NORMALLY CRASH PIL) IMAGES IN TRAINING DATA \\n\\n\\n\")\nplt.subplot(1,3,1)\nplt.imshow(pyvips_open_downsampled_slide(SMALLEST_IMAGE_ROW.image_path.values[0], downsample_by=-1, as_numpy=True, resize_to=(512,512)))\nplt.title(\"SMALLEST IMAGE\", fontweight=\"bold\")\n\nplt.subplot(1,3,2)\nplt.imshow(pyvips_open_downsampled_slide(MEDIAN_IMAGE_ROW.image_path.values[0], downsample_by=-1, as_numpy=True, resize_to=(512,512)))\nplt.title(\"MEDIAN IMAGE\", fontweight=\"bold\")\n\nplt.subplot(1,3,3)\nplt.imshow(pyvips_open_downsampled_slide(LARGEST_IMAGE_ROW.image_path.values[0], downsample_by=-1, as_numpy=True, resize_to=(512,512)))\nplt.title(\"LARGEST IMAGE\", fontweight=\"bold\")\n\nplt.tight_layout()\nplt.show()","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2022-07-17T01:53:22.186586Z","iopub.execute_input":"2022-07-17T01:53:22.187103Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}