{"nbformat": 4, "nbformat_minor": 1, "metadata": {"_is_fork": false, "language_info": {"mimetype": "text/x-python", "codemirror_mode": {"version": 3, "name": "ipython"}, "pygments_lexer": "ipython3", "nbconvert_exporter": "python", "file_extension": ".py", "version": "3.6.1", "name": "python"}, "kernelspec": {"display_name": "Python 3", "name": "python3", "language": "python"}, "_change_revision": 0}, "cells": [{"source": ["# Cervix Image Segmentation\n", "\n", "I'd first like to say thank you to \n", "\n", "1. https://www.kaggle.com/philschmidt/intel-mobileodt-cervical-cancer-screening/cervix-eda/notebook\n", "2. Those competing in the Lung Cancer detection competition for the masking idea\n", "3. All those I have learned from in the Kaggle community and outside \n", "\n", "I hope you learn from this script and is improved upon. This is my first Kaggle kernel so please give feedback where you see appropriate :D\n", "\n", "**IF YOU KNOW A BETTER WAY TO DO A CLUSTER CROP, PLEASE LET ME KNOW :)**\n", "\n", "One of the first things I noticed about the images is that there are borders of a \"random\" width/height that contain no \"information\". We really want to reduce the data to just the necessary components, ie. the cervix in this instance. AFAIK, all other parts of the picture provide no information that will help our classifier.\n", "\n", "From here I looked into medical imaging but saw k-means clustering with cv2 seemed to handle the task pretty well."], "cell_type": "markdown", "metadata": {"_cell_guid": "877fe53b-92f3-c470-c7ec-cd6d4a48cebb", "_uuid": "84e863fb3c6071dec841efee096747e4d56edc11"}}, {"execution_count": null, "outputs": [], "cell_type": "code", "source": ["%matplotlib inline\n", "import numpy as np\n", "import pandas as pd\n", "import matplotlib.pyplot as plt\n", "import seaborn as sns\n", "from skimage.io import imread, imshow\n", "import cv2\n", "import os\n", "from glob import glob\n", "from subprocess import check_output\n", "\n", "\n", "TRAIN_DATA = \"../input/train\"\n", "type_1_files = glob(os.path.join(TRAIN_DATA, \"Type_1\", \"*.jpg\"))\n", "type_1_ids = np.array([s[len(os.path.join(TRAIN_DATA, \"Type_1\"))+1:-4] for s in type_1_files])\n", "type_2_files = glob(os.path.join(TRAIN_DATA, \"Type_2\", \"*.jpg\"))\n", "type_2_ids = np.array([s[len(os.path.join(TRAIN_DATA, \"Type_2\"))+1:-4] for s in type_2_files])\n", "type_3_files = glob(os.path.join(TRAIN_DATA, \"Type_3\", \"*.jpg\"))\n", "type_3_ids = np.array([s[len(os.path.join(TRAIN_DATA, \"Type_3\"))+1:-4] for s in type_3_files])\n", "\n", "\n", "\n", "TEST_DATA = \"../input/test\"\n", "test_files = glob(os.path.join(TEST_DATA, \"*.jpg\"))\n", "test_ids = np.array([s[len(TEST_DATA)+1:-4] for s in test_files])\n", "\n", "\n", "ADDITIONAL_DATA = \"../input/additional\"\n", "additional_type_1_files = glob(os.path.join(ADDITIONAL_DATA, \"Type_1\", \"*.jpg\"))\n", "additional_type_1_ids = np.array([s[len(os.path.join(ADDITIONAL_DATA, \"Type_1\"))+1:-4] for s in additional_type_1_files])\n", "additional_type_2_files = glob(os.path.join(ADDITIONAL_DATA, \"Type_2\", \"*.jpg\"))\n", "additional_type_2_ids = np.array([s[len(os.path.join(ADDITIONAL_DATA, \"Type_2\"))+1:-4] for s in additional_type_2_files])\n", "additional_type_3_files = glob(os.path.join(ADDITIONAL_DATA, \"Type_3\", \"*.jpg\"))\n", "additional_type_3_ids = np.array([s[len(os.path.join(ADDITIONAL_DATA, \"Type_3\"))+1:-4] for s in additional_type_3_files])\n", "\"\"\"\n", "CROP_DATA = \"../input/to_crop\"\n", "crop_type_1_files = glob(os.path.join(CROP_DATA, \"Type_1\", \"*.jpg\"))\n", "crop_type_1_ids = np.array([s[len(os.path.join(CROP_DATA, \"Type_1\"))+1:-4] for s in crop_type_1_files])\n", "crop_type_2_files = glob(os.path.join(CROP_DATA, \"Type_2\", \"*.jpg\"))\n", "crop_type_2_ids = np.array([s[len(os.path.join(CROP_DATA, \"Type_2\"))+1:-4] for s in crop_type_2_files])\n", "crop_type_3_files = glob(os.path.join(CROP_DATA, \"Type_3\", \"*.jpg\"))\n", "crop_type_3_ids = np.array([s[len(os.path.join(CROP_DATA, \"Type_3\"))+1:-4] for s in crop_type_3_files])\n", "\n", "CROP_EDGE_DATA = \"../input/to_crop_edge\"\n", "crop_edge_type_1_files = glob(os.path.join(CROP_EDGE_DATA, \"Type_1\", \"*.jpg\"))\n", "crop_edge_type_1_ids = np.array([s[len(os.path.join(CROP_EDGE_DATA, \"Type_1\"))+1:-4] for s in crop_edge_type_1_files])\n", "crop_edge_type_2_files = glob(os.path.join(CROP_EDGE_DATA, \"Type_2\", \"*.jpg\"))\n", "crop_edge_type_2_ids = np.array([s[len(os.path.join(CROP_EDGE_DATA, \"Type_2\"))+1:-4] for s in crop_edge_type_2_files])\n", "crop_edge_type_3_files = glob(os.path.join(CROP_EDGE_DATA, \"Type_3\", \"*.jpg\"))\n", "crop_edge_type_3_ids = np.array([s[len(os.path.join(CROP_EDGE_DATA, \"Type_3\"))+1:-4] for s in crop_edge_type_3_files])\n", "\n", "\n", "Only do the first 20 for computational constraint reasons\n", "\"\"\"\n", "type_1_ids = type_1_ids[:20]\n", "#crop_type_1_ids = crop_type_1_ids[:30]\n", "\n", "def get_filename(image_id, image_type):\n", "    \"\"\"\n", "    Method to get image file path from its id and type   \n", "    \"\"\"\n", "    if image_type == \"Type_1\" or \\\n", "        image_type == \"Type_2\" or \\\n", "        image_type == \"Type_3\":\n", "        data_path = os.path.join(TRAIN_DATA, image_type)\n", "    elif image_type == \"Test\":\n", "        data_path = TEST_DATA\n", "    elif image_type == \"AType_1\" or \\\n", "          image_type == \"AType_2\" or \\\n", "          image_type == \"AType_3\":\n", "        data_path = os.path.join(ADDITIONAL_DATA, image_type)\n", "    else:\n", "        raise Exception(\"Image type '%s' is not recognized\" % image_type)\n", "\n", "    ext = 'jpg'\n", "    return os.path.join(data_path, \"{}.{}\".format(image_id, ext))\n", "\n", "def get_image_data(image_id, image_type):\n", "    \"\"\"\n", "    Method to get image data as np.array specifying image id and type\n", "    \"\"\"\n", "    fname = get_filename(image_id, image_type)\n", "    img = cv2.imread(fname)\n", "    assert img is not None, \"Failed to read image : %s, %s\" % (image_id, image_type)\n", "    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n", "    return img\n", "\n", "def plt_st(l1,l2):\n", "    plt.figure(figsize=(l1,l2))\n", "\n", "#tile_size = (256, 256)\n", "tile_size=(54, 54) # last_good\n", "#tile_size=(34,34)\n", "n = 15\n", "\n", "print(check_output([\"ls\", \"../input/train\"]).decode(\"utf8\"))\n", "print(len(additional_type_1_files), len(additional_type_2_files), len(additional_type_2_files))\n", "print(\"Type 1\", additional_type_1_ids[:10])\n", "print(\"Type 2\", additional_type_2_ids[:10])\n", "print(\"Type 3\", additional_type_3_ids[:10])\n", "#print(crop_type_1_ids) # from manually selecting images that are not solely the cervix"], "metadata": {"_cell_guid": "5460b9bb-9fc9-a3d7-b141-7fd4cd34f244", "_uuid": "9cf9c11a3620e7c4c38462814dd14275b18a846d"}}, {"execution_count": null, "outputs": [], "cell_type": "code", "source": ["def mask_black_bkgd(img):\n", "    #Invert the image to be white on black for compatibility with findContours function.\n", "\n", "    imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n", "    #Binarize the image and call it thresh.\n", "    ret, thresh = cv2.threshold(imgray, 127, 255, cv2.THRESH_BINARY)\n", "\n", "    #Find all the contours in thresh. In your case the 3 and the additional strike\n", "    im2, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)\n", "    #Calculate bounding rectangles for each contour.\n", "    rects = [cv2.boundingRect(cnt) for cnt in contours]\n", "\n", "    #Calculate the combined bounding rectangle points.\n", "    top_x = min([x for (x, y, w, h) in rects])\n", "    top_y = min([y for (x, y, w, h) in rects])\n", "    bottom_x = max([x+w for (x, y, w, h) in rects])\n", "    bottom_y = max([y+h for (x, y, w, h) in rects])\n", "\n", "    #Draw the rectangle on the image\n", "    #out = cv2.rectangle(img, (top_x, top_y), (bottom_x, bottom_y), (0, 255, 0), 2)\n", "    crop = img[top_y:bottom_y,top_x:bottom_x]\n", "    return crop #thresh\n", "    \n", "complete_images = []\n", "for k, type_ids in enumerate([type_1_ids]): #, type_2_ids, type_3_ids]):\n", "    m = int(np.floor(len(type_ids) / n))\n", "    complete_image = np.zeros((m*(tile_size[0]+2), n*(tile_size[1]+2), 3), dtype=np.uint8)\n", "    train_ids = sorted(type_ids)\n", "    counter = 0\n", "    for i in range(m):\n", "        ys = i*(tile_size[1] + 2)\n", "        ye = ys + tile_size[1]\n", "        for j in range(n):\n", "            xs = j*(tile_size[0] + 2)\n", "            xe = xs + tile_size[0]\n", "            image_id = train_ids[counter]; counter+=1\n", "            img = get_image_data(image_id, 'Type_%i' % (k+1))\n", "            img = cv2.resize(img, dsize=tile_size)\n", "            #img = cv2.putText(img, image_id, (5,img.shape[0] - 5), cv2.FONT_HERSHEY_SIMPLEX, 2.0, (255, 255, 255), thickness=3)\n", "            complete_image[ys:ye, xs:xe] = img[:,:,:]\n", "    complete_images.append(complete_image)\n", "\n", "plt_st(20, 20)\n", "plt.imshow(complete_images[0])\n", "plt.title(\"Training dataset of type %i\" % (1))\n", "\n", "complete_images = []\n", "for k, type_ids in enumerate([type_1_ids]): #, type_2_ids, type_3_ids]):\n", "    m = int(np.floor(len(type_ids) / n))\n", "    complete_image = np.zeros((m*(tile_size[0]+2), n*(tile_size[1]+2), 3), dtype=np.uint8)\n", "    train_ids = sorted(type_ids)\n", "    counter = 0\n", "    for i in range(m):\n", "        ys = i*(tile_size[1] + 2)\n", "        ye = ys + tile_size[1]\n", "        for j in range(n):\n", "            xs = j*(tile_size[0] + 2)\n", "            xe = xs + tile_size[0]\n", "            image_id = train_ids[counter]; counter+=1\n", "            img = get_image_data(image_id, 'Type_%i' % (k+1))\n", "            img = cv2.resize(img, dsize=tile_size)\n", "            #img = cv2.putText(img, image_id, (5,img.shape[0] - 5), cv2.FONT_HERSHEY_SIMPLEX, 2.0, (255, 255, 255), thickness=3)\n", "            complete_image[ys:ye, xs:xe] = cv2.resize(mask_black_bkgd(img[:,:,:]), dsize=tile_size)\n", "    complete_images.append(complete_image)\n", "\n", "\n", "plt_st(20, 20)\n", "plt.imshow(complete_images[0])\n", "plt.title(\"Training dataset of type %i\" % (1))"], "metadata": {"_cell_guid": "ca2c168a-6f7f-b1d1-145a-c2f153bb2bef", "_uuid": "2a87f1a729084b2be47569ddca3a2a61af648600"}}, {"source": [" Images dont seem to be appearing now... anyway this just cuts out the black borders, which will be the first step\n", "\n", "Thanks Allunia. Looking into gaussian mixtures now."], "cell_type": "markdown", "metadata": {"_cell_guid": "ab46557f-1417-c24c-ef5c-877fd0ad7b91", "_uuid": "ce9ada89cbbe172f34f447d189c140f0f74a9bd7"}}, {"execution_count": null, "outputs": [], "cell_type": "code", "source": ["Thanks @Allunia. Looking into gaussian mixtures now"], "metadata": {"_cell_guid": "c98f9f85-87e5-0aa1-7bff-8c075eb21f31", "collapsed": true, "_uuid": "bf15f78fdcfd953cbb35190b2cce73b177f2268f"}}, {"execution_count": null, "outputs": [], "cell_type": "code", "source": ["def mask_black_bkgd(img):\n", "    #Invert the image to be white on black for compatibility with findContours function.\n", "\n", "    imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n", "    #Binarize the image and call it thresh.\n", "    ret, thresh = cv2.threshold(imgray, 127, 255, cv2.THRESH_BINARY)\n", "\n", "    #Find all the contours in thresh. In your case the 3 and the additional strike\n", "    im2, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)\n", "    #Calculate bounding rectangles for each contour.\n", "    rects = [cv2.boundingRect(cnt) for cnt in contours]\n", "\n", "    #Calculate the combined bounding rectangle points.\n", "    top_x = min([x for (x, y, w, h) in rects])\n", "    top_y = min([y for (x, y, w, h) in rects])\n", "    bottom_x = max([x+w for (x, y, w, h) in rects])\n", "    bottom_y = max([y+h for (x, y, w, h) in rects])\n", "\n", "    #Draw the rectangle on the image\n", "    out = cv2.rectangle(img, (top_x, top_y), (bottom_x, bottom_y), (0, 255, 0), 2)\n", "    crop = img[top_y:bottom_y,top_x:bottom_x]\n", "    return crop #thresh\n", "    \n", "complete_images = []\n", "for k, type_ids in enumerate([type_1_ids]): #, type_2_ids, type_3_ids]):\n", "    m = int(np.floor(len(type_ids) / n))\n", "    complete_image = np.zeros((m*(tile_size[0]+2), n*(tile_size[1]+2), 3), dtype=np.uint8)\n", "    train_ids = sorted(type_ids)\n", "    counter = 0\n", "    for i in range(m):\n", "        ys = i*(tile_size[1] + 2)\n", "        ye = ys + tile_size[1]\n", "        for j in range(n):\n", "            xs = j*(tile_size[0] + 2)\n", "            xe = xs + tile_size[0]\n", "            image_id = train_ids[counter]; counter+=1\n", "            img = get_image_data(image_id, 'Type_%i' % (k+1))\n", "            img = cv2.resize(img, dsize=tile_size)\n", "            #img = cv2.putText(img, image_id, (5,img.shape[0] - 5), cv2.FONT_HERSHEY_SIMPLEX, 2.0, (255, 255, 255), thickness=3)\n", "            complete_image[ys:ye, xs:xe] = cv2.resize(mask_black_bkgd(img[:,:,:]), dsize=tile_size)\n", "    complete_images.append(complete_image)\n", "\n", "plt_st(20, 20)\n", "plt.imshow(complete_images[0])\n", "plt.title(\"Training dataset of type %i\" % (1))\n", "\n", "complete_images = []\n", "for k, type_ids in enumerate([type_1_ids]): #, type_2_ids, type_3_ids]):\n", "    m = int(np.floor(len(type_ids) / n))\n", "    complete_image = np.zeros((m*(tile_size[0]+2), n*(tile_size[1]+2), 3), dtype=np.uint8)\n", "    train_ids = sorted(type_ids)\n", "    counter = 0\n", "    for i in range(m):\n", "        ys = i*(tile_size[1] + 2)\n", "        ye = ys + tile_size[1]\n", "        for j in range(n):\n", "            xs = j*(tile_size[0] + 2)\n", "            xe = xs + tile_size[0]\n", "            image_id = train_ids[counter]; counter+=1\n", "            img = get_image_data(image_id, 'Type_%i' % (k+1))\n", "            img = cv2.resize(img, dsize=tile_size)\n", "            #img = cv2.putText(img, image_id, (5,img.shape[0] - 5), cv2.FONT_HERSHEY_SIMPLEX, 2.0, (255, 255, 255), thickness=3)\n", "            complete_image[ys:ye, xs:xe] = img[:,:,:]\n", "    complete_images.append(complete_image)\n", "\n", "plt_st(20, 20)\n", "plt.imshow(complete_images[0])\n", "plt.title(\"Training dataset of type %i\" % (1))"], "metadata": {"_cell_guid": "3115f95a-89ad-470d-dde2-e17f8b1cec48", "_uuid": "acf509b9794eb508633b44c19fe5123c090bb2c7"}}]}