{"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":"## **Removing white space from images**","metadata":{}},{"cell_type":"markdown","source":"### **Import Usefull Libraries.**","metadata":{}},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport seaborn as sns\nfrom PIL import Image\nimport openslide\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport os\nimport cv2\nimport PIL\nimport random\nimport openslide\nimport skimage.io\nimport matplotlib\nfrom IPython.display import Image, display","metadata":{"execution":{"iopub.status.busy":"2022-05-16T09:27:54.958851Z","iopub.execute_input":"2022-05-16T09:27:54.959697Z","iopub.status.idle":"2022-05-16T09:27:54.966485Z","shell.execute_reply.started":"2022-05-16T09:27:54.959639Z","shell.execute_reply":"2022-05-16T09:27:54.965608Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **Base Folder Path of Dataset.**","metadata":{}},{"cell_type":"code","source":"BASE_FOLDER = \"/kaggle/input/prostate-cancer-grade-assessment/\"\n!ls {BASE_FOLDER}","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-05-16T09:27:55.109365Z","iopub.execute_input":"2022-05-16T09:27:55.109664Z","iopub.status.idle":"2022-05-16T09:27:55.879297Z","shell.execute_reply.started":"2022-05-16T09:27:55.109634Z","shell.execute_reply":"2022-05-16T09:27:55.878366Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **Read all CSV file & train Images of Dataset.**","metadata":{}},{"cell_type":"code","source":"IMG_FOLDER = BASE_FOLDER + 'train_images/'\nMASK_FOLDER = BASE_FOLDER + 'train_label_masks/'\ntrain = pd.read_csv(BASE_FOLDER+\"train.csv\")\ntest = pd.read_csv(BASE_FOLDER+\"test.csv\")\nsub = pd.read_csv(BASE_FOLDER+\"sample_submission.csv\")","metadata":{"execution":{"iopub.status.busy":"2022-05-16T09:27:55.881398Z","iopub.execute_input":"2022-05-16T09:27:55.881641Z","iopub.status.idle":"2022-05-16T09:27:55.914762Z","shell.execute_reply.started":"2022-05-16T09:27:55.881611Z","shell.execute_reply":"2022-05-16T09:27:55.913823Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **Drop the Mislabelled row from training dataset.**","metadata":{}},{"cell_type":"code","source":"train.drop([7273],inplace=True)","metadata":{"execution":{"iopub.status.busy":"2022-05-16T09:27:55.916155Z","iopub.execute_input":"2022-05-16T09:27:55.91686Z","iopub.status.idle":"2022-05-16T09:27:55.924623Z","shell.execute_reply.started":"2022-05-16T09:27:55.916806Z","shell.execute_reply":"2022-05-16T09:27:55.923667Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **Compute Statistics Function**\n\nThis function help us to find the ratio of white pixels, green concentration & red concentration in the image.","metadata":{}},{"cell_type":"code","source":"def compute_statistics(image):\n    \"\"\"\n    Args:\n        image                  numpy.array   multi-dimensional array of the form WxHxC\n    \n    Returns:\n        ratio_white_pixels     float         ratio of white pixels over total pixels in the image \n    \"\"\"\n    width, height = image.shape[0], image.shape[1]\n    num_pixels = width * height\n    \n    num_white_pixels = 0\n    \n    summed_matrix = np.sum(image, axis=-1)\n    # Note: A 3-channel white pixel has RGB (255, 255, 255)\n    num_white_pixels = np.count_nonzero(summed_matrix > 620)\n    ratio_white_pixels = num_white_pixels / num_pixels\n    \n    green_concentration = np.mean(image[1])\n    blue_concentration = np.mean(image[2])\n    \n    return ratio_white_pixels, green_concentration, blue_concentration","metadata":{"execution":{"iopub.status.busy":"2022-05-16T09:27:55.926706Z","iopub.execute_input":"2022-05-16T09:27:55.927534Z","iopub.status.idle":"2022-05-16T09:27:55.936373Z","shell.execute_reply.started":"2022-05-16T09:27:55.927486Z","shell.execute_reply":"2022-05-16T09:27:55.935527Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **Select K best regions Function**","metadata":{}},{"cell_type":"code","source":"def select_k_best_regions(regions, k=20):\n    \"\"\"\n    Args:\n        regions = list of 2-component tuples first component the region, \n                  second component the ratio of white pixels                          \n        k = number of regions to select\n    \"\"\"\n    \n    # x[3]=green_concentration, x[4]=blue_concentration\n    regions = [x for x in regions if x[3] > 180 and x[4] > 180]\n    \n    # sorted the regions according to white pixel ratio & select the k best regions from that\n    k_best_regions = sorted(regions, key=lambda tup: tup[2])[:k]\n    return k_best_regions","metadata":{"execution":{"iopub.status.busy":"2022-05-16T09:27:55.93748Z","iopub.execute_input":"2022-05-16T09:27:55.939326Z","iopub.status.idle":"2022-05-16T09:27:55.952802Z","shell.execute_reply.started":"2022-05-16T09:27:55.939277Z","shell.execute_reply":"2022-05-16T09:27:55.951776Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **Function to get K best regions.**","metadata":{}},{"cell_type":"code","source":"def get_k_best_regions(coordinates, image, window_size=512):\n    regions = {}\n    for i, tup in enumerate(coordinates):\n        x, y = tup[0], tup[1]\n        regions[i] = image[x : x+window_size, y : y+window_size, :]\n    \n    return regions","metadata":{"execution":{"iopub.status.busy":"2022-05-16T09:27:55.981115Z","iopub.execute_input":"2022-05-16T09:27:55.981963Z","iopub.status.idle":"2022-05-16T09:27:55.988553Z","shell.execute_reply.started":"2022-05-16T09:27:55.981918Z","shell.execute_reply":"2022-05-16T09:27:55.987756Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **Generate patches from Images**\n\nThe main function: the two while loops slide over the image (the first one from top to bottom, the second from left to right). The order does not matter actually. Then we select the region, compute the statistics of that region, sort the array and select the k-best regions.","metadata":{}},{"cell_type":"code","source":"def generate_patches(slide_path, window_size=200, stride=128, k=20):\n    \n    image = skimage.io.MultiImage(slide_path)[0]\n    image = np.array(image)\n    \n    max_width, max_height = image.shape[0], image.shape[1]\n    regions_container = []\n    i = 0\n    \n    while window_size + stride*i <= max_height:\n        j = 0\n        \n        while window_size + stride*j <= max_width:            \n            x_top_left_pixel = j * stride\n            y_top_left_pixel = i * stride\n            \n            patch = image[\n                x_top_left_pixel : x_top_left_pixel + window_size,\n                y_top_left_pixel : y_top_left_pixel + window_size,\n                :\n            ]\n            \n            ratio_white_pixels, green_concentration, blue_concentration = compute_statistics(patch)\n            \n            region_tuple = (x_top_left_pixel, y_top_left_pixel, ratio_white_pixels, green_concentration, blue_concentration)\n            regions_container.append(region_tuple)\n            \n            j += 1\n        \n        i += 1\n    \n    k_best_region_coordinates = select_k_best_regions(regions_container, k=k)\n    k_best_regions = get_k_best_regions(k_best_region_coordinates, image, window_size)\n    \n    return image, k_best_region_coordinates, k_best_regions","metadata":{"execution":{"iopub.status.busy":"2022-05-16T09:27:56.1495Z","iopub.execute_input":"2022-05-16T09:27:56.150059Z","iopub.status.idle":"2022-05-16T09:27:56.159186Z","shell.execute_reply.started":"2022-05-16T09:27:56.150024Z","shell.execute_reply":"2022-05-16T09:27:56.158442Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **Function to display regions of Images**","metadata":{}},{"cell_type":"code","source":"def display_images(regions, title):\n    fig, ax = plt.subplots(5, 4, figsize=(15, 15))\n    \n    for i, region in regions.items():\n        ax[i//4, i%4].imshow(region)\n    \n    fig.suptitle(title)","metadata":{"execution":{"iopub.status.busy":"2022-05-16T09:27:56.425379Z","iopub.execute_input":"2022-05-16T09:27:56.425842Z","iopub.status.idle":"2022-05-16T09:27:56.430904Z","shell.execute_reply.started":"2022-05-16T09:27:56.42581Z","shell.execute_reply":"2022-05-16T09:27:56.430206Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**List of all Image Id's & Labels.**","metadata":{}},{"cell_type":"code","source":"images = list(train['image_id'])\nlabels = list(train['isup_grade'])","metadata":{"execution":{"iopub.status.busy":"2022-05-16T09:32:44.294084Z","iopub.execute_input":"2022-05-16T09:32:44.294476Z","iopub.status.idle":"2022-05-16T09:32:44.302658Z","shell.execute_reply.started":"2022-05-16T09:32:44.294441Z","shell.execute_reply":"2022-05-16T09:32:44.301689Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%time\n\nex_url = IMG_FOLDER + images[0] + '.tiff'\n_, best_coordinates, best_regions = generate_patches(ex_url)","metadata":{"execution":{"iopub.status.busy":"2022-05-16T09:53:49.16707Z","iopub.execute_input":"2022-05-16T09:53:49.167527Z","iopub.status.idle":"2022-05-16T09:54:47.011375Z","shell.execute_reply.started":"2022-05-16T09:53:49.167482Z","shell.execute_reply":"2022-05-16T09:54:47.010297Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"display_images(best_regions, 'Window size: 200, stride: 128')","metadata":{"execution":{"iopub.status.busy":"2022-05-16T09:55:05.071749Z","iopub.execute_input":"2022-05-16T09:55:05.072068Z","iopub.status.idle":"2022-05-16T09:55:07.439883Z","shell.execute_reply.started":"2022-05-16T09:55:05.072036Z","shell.execute_reply":"2022-05-16T09:55:07.438998Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%time\n\nex_url = IMG_FOLDER + images[0] + '.tiff'\n_, best_coordinates, best_regions = generate_patches(ex_url, window_size=128, stride=64)\ndisplay_images(best_regions, 'Window size: 128, stride: 64')","metadata":{"execution":{"iopub.status.busy":"2022-05-16T09:56:09.176883Z","iopub.execute_input":"2022-05-16T09:56:09.177211Z","iopub.status.idle":"2022-05-16T09:57:47.301888Z","shell.execute_reply.started":"2022-05-16T09:56:09.177178Z","shell.execute_reply":"2022-05-16T09:57:47.300768Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **Function to Glue all patches into one Image.**","metadata":{}},{"cell_type":"code","source":"def glue_to_one_picture(image_patches, window_size=200, k=16):\n    side = int(np.sqrt(k))\n    image = np.zeros((side*window_size, side*window_size, 3), dtype=np.int16)\n        \n    for i, patch in image_patches.items():\n        x = i // side\n        y = i % side\n        image[\n            x * window_size : (x+1) * window_size,\n            y * window_size : (y+1) * window_size,\n            :\n        ] = patch\n    \n    return image","metadata":{"execution":{"iopub.status.busy":"2022-05-16T09:28:55.762257Z","iopub.execute_input":"2022-05-16T09:28:55.762524Z","iopub.status.idle":"2022-05-16T09:28:55.770307Z","shell.execute_reply.started":"2022-05-16T09:28:55.762494Z","shell.execute_reply":"2022-05-16T09:28:55.769205Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **Define Parameters**","metadata":{}},{"cell_type":"code","source":"WINDOW_SIZE = 128\nSTRIDE = 64\nK = 16               # no of best regions to select","metadata":{"execution":{"iopub.status.busy":"2022-05-16T09:28:55.771982Z","iopub.execute_input":"2022-05-16T09:28:55.772482Z","iopub.status.idle":"2022-05-16T09:28:55.785743Z","shell.execute_reply.started":"2022-05-16T09:28:55.772431Z","shell.execute_reply":"2022-05-16T09:28:55.785096Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, ax = plt.subplots(2, 2, figsize=(20, 25))\n\nfor i, img in enumerate(images[:2]):\n    url = IMG_FOLDER + img + '.tiff'\n    image, best_coordinates, best_regions = generate_patches(url, window_size=WINDOW_SIZE, stride=STRIDE, k=K)\n    glued_image = glue_to_one_picture(best_regions, window_size=WINDOW_SIZE, k=K)\n    \n    ax[i][0].imshow(image)\n    ax[i][0].set_title(f'{img} - Original - Label: {labels[i]}')\n    \n    ax[i][1].imshow(glued_image)\n    ax[i][1].set_title(f'{img} - Glued - Label: {labels[i]}')\n\nfig.suptitle('From biopsy to glued patches')","metadata":{"execution":{"iopub.status.busy":"2022-05-16T09:40:09.582758Z","iopub.execute_input":"2022-05-16T09:40:09.583194Z","iopub.status.idle":"2022-05-16T09:43:58.25224Z","shell.execute_reply.started":"2022-05-16T09:40:09.58315Z","shell.execute_reply":"2022-05-16T09:43:58.251051Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Conclusion for Image Tiles:-\n\nTo Small window size can create loss of information which will affect the model performance, so the window size around 200 is a good choice having enough biopsy detail & structured capture.\n\nAlthough, we can tune more this in modelling part after seeing the performance of the model.\n","metadata":{}},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}