{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Visualization: PANDA 16x128x128 tiles"},{"metadata":{},"cell_type":"markdown","source":"### This notebook:\n\n- is based on [PANDA 16x128x128 tiles][original]. Thank you [@iafoss][iafoss] for sharing it with us.\n- visualizes which tiles are selected in iafoss's approach.\n\n[iafoss]: https://www.kaggle.com/iafoss\n[original]: https://www.kaggle.com/iafoss/panda-16x128x128-tiles"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import os\nfrom functools import reduce\n\nimport pandas as pd\nimport skimage.io\nimport numpy as np\nimport matplotlib.pyplot as plt","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"INPUT_DIR = \"../input/prostate-cancer-grade-assessment\"\nTRAIN_DIR = f\"{INPUT_DIR}/train_images\"\nMASK_DIR = f\"{INPUT_DIR}/train_label_masks\"\n\nBLACK = (0,) * 3\nGRAY = (200,) * 3\nWHITE = (255,) * 3\nRED = (255, 0, 0)\n\nSIZE = 128\nN = 16","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train = pd.read_csv(f\"{INPUT_DIR}/train.csv\")\ntrain.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Load image"},{"metadata":{"trusted":true},"cell_type":"code","source":"def imread(path):\n    if not os.path.exists(path):\n        raise FileNotFoundError(f\"No such file or directory: '{path}'\")\n\n    return skimage.io.MultiImage(path)\n\n\ndef imshow(\n    img,\n    title=None,\n    show_shape=True,\n    figsize=(8, 8)\n):\n    fig, ax = plt.subplots(figsize=figsize)\n    ax.imshow(img)\n    ax.grid(\"off\")\n    ax.set_xticks([])\n    ax.set_yticks([])\n\n    if show_shape:\n        ax.set_xlabel(f\"Shape: {img.shape}\", fontsize=16)\n        \n    if title:\n        ax.set_title(title, fontsize=16)\n\n    return ax","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"img_id = \"000920ad0b612851f8e01bcc880d9b3d\"\nimg_org = imread(os.path.join(TRAIN_DIR, f\"{img_id}.tiff\"))[-1]\nimshow(img_org, \"Original image\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Padding\n\nhttps://docs.scipy.org/doc/numpy/reference/generated/numpy.pad.html"},{"metadata":{"trusted":true},"cell_type":"code","source":"H, W = img_org.shape[:2]\npad_h = (SIZE - H % SIZE) % SIZE\npad_w = (SIZE - W % SIZE) % SIZE\n\nprint(\"pad_h:\", pad_h)\nprint(\"pad_w\", pad_w)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"padded_vis = np.pad(\n    img_org,\n    [[pad_h // 2, pad_h - pad_h // 2],\n     [pad_w // 2, pad_w - pad_w // 2],\n     [0, 0]],\n    constant_values=GRAY[0],  # use GRAY for visualization.\n)\n\nimshow(padded_vis, \"Padded image\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"padded = np.pad(\n    img_org,\n    [[pad_h // 2, pad_h - pad_h // 2],\n     [pad_w // 2, pad_w - pad_w // 2],\n     [0, 0]],\n    constant_values=WHITE[0],\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"N_ROWS = padded.shape[0] // SIZE\nN_COLS = padded.shape[1] // SIZE\n\nprint(\"N_ROWS :\", N_ROWS)\nprint(\"N_COLS :\", N_COLS)\nprint(\"N_TILES:\", N_ROWS * N_COLS)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Create tiles\n\n- https://docs.scipy.org/doc/numpy/reference/generated/numpy.reshape.html\n- https://docs.scipy.org/doc/numpy/reference/generated/numpy.transpose.html"},{"metadata":{"trusted":true},"cell_type":"code","source":"reshaped = padded.reshape(\n    padded.shape[0] // SIZE,\n    SIZE,\n    padded.shape[1] // SIZE,\n    SIZE,\n    3,\n)\ntransposed = reshaped.transpose(0, 2, 1, 3, 4)\ntiles = transposed.reshape(-1, SIZE, SIZE, 3)\n\nprint(\"reshaped.shape  :\", reshaped.shape)\nprint(\"transposed.shape:\", transposed.shape)\nprint(\"tiles.shape     :\", tiles.shape)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Visualize tiles"},{"metadata":{"trusted":true},"cell_type":"code","source":"def merge_tiles(tiles, funcs=None):\n    \"\"\"\n    If `funcs` specified, apply them to each tile before merging.\n    \"\"\"\n    return np.vstack([\n        np.hstack([\n            reduce(lambda acc, f: f(acc), funcs, x) if funcs else x\n            for x in row\n        ])\n        for row in tiles\n    ])\n\n\ndef draw_borders(img):\n    \"\"\"\n    Put borders around an image.\n    \"\"\"\n    ret = img.copy()\n    ret[0, :] = GRAY   # top\n    ret[-1, :] = GRAY  # bottom\n    ret[:, 0] = GRAY   # left\n    ret[:, -1] = GRAY  # right\n    return ret\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"imshow(merge_tiles(transposed, [draw_borders]), \"Tiles\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Select tiles"},{"metadata":{"trusted":true},"cell_type":"code","source":"sums = tiles.reshape(tiles.shape[0], -1).sum(axis=-1)\n\nhighlight = lambda x: \"color: {}\".format(\"red\" if x != sums.max() else \"black\")\npd.DataFrame(sums.reshape(N_ROWS, N_COLS)).style.applymap(highlight)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"idxs_selected = np.argsort(sums)[:N]\nidxs_selected","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Visuzalize selected tiles"},{"metadata":{"trusted":true},"cell_type":"code","source":"def fill_tiles(tiles, fill_func):\n    \"\"\"\n    Fill each tile with another array created by `fill_func`.\n    \"\"\"\n    return np.array([[fill_func(x) for x in row] for row in tiles])\n\n\ndef make_patch_func(true_color, false_color):\n    def ret(x):\n        \"\"\"\n        Retunrs a color patch. The color will be `true_color` if `x` is True otherwise `false_color`.\n        \"\"\"\n        color = true_color if x else false_color\n        return np.tile(color, (SIZE, SIZE, 1)).astype(np.uint8)\n\n    return ret","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"mask = np.isin(np.arange(len(sums)), idxs_selected).reshape(N_ROWS, N_COLS)\nmask = fill_tiles(mask, make_patch_func(WHITE, BLACK))\nmask = merge_tiles(mask, [draw_borders])\n\nimshow(mask, \"Selected tiles\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"mask = np.isin(np.arange(len(sums)), idxs_selected).reshape(N_ROWS, N_COLS)\nmask = fill_tiles(mask, make_patch_func(RED, WHITE))\nmask = merge_tiles(mask, [draw_borders])\n\nwith_mask = np.ubyte(0.7 * padded + 0.3 * mask)\n\nimshow(with_mask, \"Selected tiles\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","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}