{"cells":[{"metadata":{},"cell_type":"markdown","source":"### Attempts to remove pen marks\n\n* [Attempt 1](#Attempt-1)\n* [Attempt 2](#Attempt-2)","execution_count":null},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"# imports\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport cv2 \nimport skimage.io","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"# dataset\nPATH = '../input/prostate-cancer-grade-assessment/'\nIMG_PATH = PATH + 'train_images/'\ndata = pd.read_csv(PATH + 'train.csv')\ndata.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### Implementation\n\nIds of pen marked images taken from this [kernel](https://www.kaggle.com/rohitsingh9990/panda-eda-better-visualization-simple-baseline)\n\nDiscussion [here](https://www.kaggle.com/c/prostate-cancer-grade-assessment/discussion/148060)","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# helper function\ndef read_image(image_path, level=1):\n    image = skimage.io.MultiImage(image_path)\n    image = image[level]\n    return image\n\n\n# credits to Rohit Singh\npen_marked_images = [\n    'fd6fe1a3985b17d067f2cb4d5bc1e6e1',\n    'ebb6a080d72e09f6481721ef9f88c472',\n    'ebb6d5ca45942536f78beb451ee43cc4',\n    'ea9d52d65500acc9b9d89eb6b82cdcdf',\n    'e726a8eac36c3d91c3c4f9edba8ba713',\n    'e90abe191f61b6fed6d6781c8305fe4b',\n    'fd0bb45eba479a7f7d953f41d574bf9f',\n    'ff10f937c3d52eff6ad4dd733f2bc3ac',\n    'feee2e895355a921f2b75b54debad328',\n    'feac91652a1c5accff08217d19116f1c',\n    'fb01a0a69517bb47d7f4699b6217f69d',\n    'f00ec753b5618cfb30519db0947fe724',\n    'e9a4f528b33479412ee019e155e1a197',\n    'f062f6c1128e0e9d51a76747d9018849',\n    'f39bf22d9a2f313425ee201932bac91a',\n]\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Attempt 1\n\nThis method a bit aggressive, where the aim is to remove \\[most of\\] the pen marks along the edges of the tissue as well (quite hard to remove all of it without ruining the tissue)\n","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"def remove_pen_marks(img):\n    \n    # Define elliptic kernel\n    kernel5x5 = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))\n    \n    # Convert image to gray scale and mask out background\n    img_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)\n    img_mask = np.where(img_gray < 210, 1, 0).astype(np.uint8)\n    \n    # Reshape red channel into 1-d array, aims to mask most of the pen marks\n    img_r = np.reshape(img[:, :, 0], (-1,))\n    img_r = img_r[np.where(img_r < 255)[0]]\n    img_r_mask = (img[:, :, 0] < np.median(img_r)-50).astype(np.uint8)\n\n    # When computing the pen mark mask, some tissue gets masked as well,\n    # thus needing to erode the mask to get rid of it. Then some dilatation is \n    # applied to capture the \"edges\" of the \"gradient-like\"/non-uniform pen marks\n    img_r_mask = cv2.erode(img_r_mask, kernel5x5, iterations=3)\n    img_r_mask = cv2.dilate(img_r_mask, kernel5x5, iterations=5)\n    \n    # Combine the two masks\n    img_r_mask = 1 - img_r_mask\n    img_mask = img_mask * img_r_mask\n    \n    # There might still be some gaps/holes in the tissue, here's an attempt to \n    # fill those gaps/holes\n    img_mask = cv2.morphologyEx(img_mask, cv2.MORPH_CLOSE, kernel5x5, iterations=1)\n    img_mask = cv2.dilate(img_mask, kernel5x5, iterations=1)\n    contours, _ = cv2.findContours(img_mask, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)\n    for contour in contours:\n        cv2.drawContours(img_mask, [contour], 0, 1, -1)\n    \n    # Some final touch\n    img_mask = cv2.erode(img_mask, kernel5x5, iterations=3)\n    img_mask = cv2.dilate(img_mask, kernel5x5, iterations=1)\n    img_mask = cv2.erode(img_mask, kernel5x5, iterations=2)\n    \n    # Mask out pen marks from original image\n    img = img * img_mask[:, :, np.newaxis]\n    \n    return img, img_mask\n\n\nfig, axes = plt.subplots(\n    len(pen_marked_images), 3, figsize=(10, 10*len(pen_marked_images))\n)\n\nfor i, ID in enumerate(pen_marked_images):\n    \n    img_path = PATH + 'train_images/' + ID + '.tiff'\n    img = read_image(img_path, level=1)\n    img2, mask = remove_pen_marks(img)\n    \n    axes[i, 0].imshow(img)\n    axes[i, 0].set_title('Original Image', fontsize=16)\n    axes[i, 1].imshow(mask)\n    axes[i, 1].set_title('No-pen Mask', fontsize=16)\n    axes[i, 2].imshow(img2)\n    axes[i, 2].set_title('No-pen Image', fontsize=16)\n    for ax in axes[i]:\n        ax.axis('off')\n    ","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Attempt 2\n\nThe coloring around the edges of the tissue does not indicate a \\[pen\\] marking for cancerous tissue (see [here](https://www.kaggle.com/c/prostate-cancer-grade-assessment/discussion/151323))\n\nThus, in this attempt to remove pen marks, a bit less aggressive method is implemented, only trying to remove relevant pen marks.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"def remove_pen_marks(img):\n    \n    # Define elliptic kernel\n    kernel5x5 = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))\n    \n    # use cv2.inRange to mask pen marks (hardcoded for now)\n    lower = np.array([0, 0, 0])\n    upper = np.array([200, 255, 255])\n    img_mask1 = cv2.inRange(img, lower, upper)\n\n    # Use erosion and findContours to remove masked tissue (side effect of above)\n    img_mask1 = cv2.erode(img_mask1, kernel5x5, iterations=4)\n    img_mask2 = np.zeros(img_mask1.shape, dtype=np.uint8)\n    contours, _ = cv2.findContours(img_mask1, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)\n    for contour in contours:\n        x, y = contour[:, 0, 0], contour[:, 0, 1]\n        w, h = x.max()-x.min(), y.max()-y.min()\n        if w > 100 and h > 100:\n            cv2.drawContours(img_mask2, [contour], 0, 1, -1)\n    # expand the area of the pen marks\n    img_mask2 = cv2.dilate(img_mask2, kernel5x5, iterations=3)\n    img_mask2 = (1 - img_mask2)\n    \n    # Mask out pen marks from original image\n    img = cv2.bitwise_and(img, img, mask=img_mask2)\n    \n    img[img == 0] = 255\n    \n    return img, img_mask1, img_mask2\n\n\nfig, axes = plt.subplots(\n    len(pen_marked_images), 4, figsize=(12, 10*len(pen_marked_images))\n)\n\nfor i, ID in enumerate(pen_marked_images):\n    \n    img_path = PATH + 'train_images/' + ID + '.tiff'\n    img = read_image(img_path, level=1)\n    img2, mask1, mask2 = remove_pen_marks(img)\n    \n    axes[i, 0].imshow(img)\n    axes[i, 0].set_title('Original Image', fontsize=16)\n    axes[i, 1].imshow(mask1)\n    axes[i, 1].set_title('Mask 1', fontsize=16)\n    axes[i, 2].imshow(mask2)\n    axes[i, 2].set_title('Mask 2', fontsize=16)\n    axes[i, 3].imshow(img2)\n    axes[i, 3].set_title('New Image', fontsize=16)\n    for ax in axes[i]:\n        ax.axis('off')\n    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","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}