{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "_cell_guid": "afe35633-327b-b45d-a328-b9d17d60e0f3"
      },
      "source": [
        "# Type 1 clustering\n",
        "\n",
        "I want to understand what kind of images we have acording to the standard procedure, for example described [here](http://www.gfmer.ch/ccdc/pdf/module5.pdf). Namely,\n",
        "do we have images :\n",
        "\n",
        "- native cervix\n",
        "- acetic acid\n",
        "- lugol iodine\n",
        "\n",
        "of the same patient ?\n",
        " \n",
        "**Edit**: Clustering method updated\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "d4af76fc-b031-a85a-6603-ed04208c6e45"
      },
      "outputs": [],
      "source": [
        "import os\n",
        "from glob import glob\n",
        "\n",
        "import numpy as np\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",
        "print(\"Train data\")\n",
        "print(len(type_1_files), len(type_2_files), len(type_3_files))\n",
        "print(\"Type 1\", type_1_ids[:10])\n",
        "print(\"Type 2\", type_2_ids[:10])\n",
        "print(\"Type 3\", type_3_ids[:10])\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",
        "print(\"Additional data\")\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",
        "\n",
        "\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[1:])\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",
        "\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",
        "\n",
        "import matplotlib.pylab as plt\n",
        "\n",
        "def plt_st(l1,l2):\n",
        "    plt.figure(figsize=(l1,l2))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "_cell_guid": "c84634bd-f844-4296-7885-eb8b5169ea1e"
      },
      "source": [
        "Idea is to use clustering on images of one type to group data"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "3e89c9fc-7176-c259-a7d7-e3dd237f8001"
      },
      "outputs": [],
      "source": [
        "def compute_histogram(img, hist_size=100):\n",
        "    hist = cv2.calcHist([img], [0], mask=None, histSize=[hist_size], ranges=(0, 255))\n",
        "    hist = cv2.normalize(hist, dst=hist)\n",
        "    return hist"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "e58c2105-db81-e86e-c19f-830478e57729"
      },
      "outputs": [],
      "source": [
        "type_ids=(type_1_ids, additional_type_1_ids)\n",
        "image_types = [\"Type_1\", \"AType_1\"]\n",
        "ll = [int(len(ids)) for ids in type_ids]\n",
        "\n",
        "id_type_list = []\n",
        "for ids, image_type in zip(type_ids, image_types):\n",
        "    for image_id in ids:\n",
        "        id_type_list.append((image_id, image_type))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "56f78a4b-1ca9-8ce1-7a60-6b6be9849bb3"
      },
      "outputs": [],
      "source": [
        "print(\"Total number of images: \", len(id_type_list))\n",
        "# Find empty images:\n",
        "empty_images = []\n",
        "for image_id, image_type in id_type_list:\n",
        "    size = os.path.getsize(get_filename(image_id, image_type))\n",
        "    if size == 0:\n",
        "        empty_images.append((image_id, image_type))\n",
        "print(\"Number of empty images: \", len(empty_images))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "38db7d67-a114-4950-ebb8-fca8385b4f7d"
      },
      "outputs": [],
      "source": [
        "# Remove empty images from id_type_list\n",
        "for image_id, image_type in empty_images:\n",
        "    id_type_list.remove((image_id, image_type))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "5dc1800d-c4b2-37a2-751f-bae0b70dc568"
      },
      "outputs": [],
      "source": [
        "import cv2"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "916970d2-90bf-a740-8734-cf62940a61c8"
      },
      "outputs": [],
      "source": [
        "RESIZED_IMAGES = {}"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "8cfed6a2-6de0-52c3-ce34-75d6fe815696"
      },
      "outputs": [],
      "source": [
        "image_size = (256, 256)\n",
        "center = (image_size[0]//2, image_size[1]//2)\n",
        "hist_size = 30\n",
        "\n",
        "crop_size = 30\n",
        "\n",
        "n_features = 3 * hist_size\n",
        "X = np.zeros((len(id_type_list), n_features), dtype=np.float32)\n",
        "for i, (image_id, image_type) in enumerate(id_type_list):\n",
        "    \n",
        "    key = (image_id, image_type)\n",
        "    if key in RESIZED_IMAGES:\n",
        "        img = RESIZED_IMAGES[key]\n",
        "    else:\n",
        "        img = get_image_data(image_id, image_type)\n",
        "        img = cv2.resize(img, dsize=image_size[::-1])    \n",
        "        RESIZED_IMAGES[key] = img\n",
        "    \n",
        "    # crop \n",
        "    proc = img[center[1]-crop_size:center[1]+crop_size,center[0]-crop_size:center[0]+crop_size,:]\n",
        "    # Blur \n",
        "    proc = cv2.GaussianBlur(proc, (7, 7), 0)\n",
        "    hsv = cv2.cvtColor(proc, cv2.COLOR_RGB2HSV)\n",
        "    hue = hsv[:,:,0]\n",
        "    sat = hsv[:,:,1]\n",
        "    val = hsv[:,:,2]\n",
        "    hist_hue = compute_histogram(hue, hist_size)\n",
        "    hist_sat = compute_histogram(sat, hist_size)    \n",
        "    hist_val = compute_histogram(val, hist_size)    \n",
        "    X[i, 0:hist_size] = hist_hue[:,0]\n",
        "    X[i, hist_size:2*hist_size] = hist_sat[:,0]\n",
        "    X[i, 2*hist_size:] = hist_val[:,0]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "3fbd6b27-67dc-6ef0-b007-422b18ee65f9"
      },
      "outputs": [],
      "source": [
        "n_classes = 10\n",
        "\n",
        "from sklearn.cluster import KMeans\n",
        "kmeans = KMeans(n_clusters=n_classes)\n",
        "kmeans.fit(X)\n",
        "y_classes = kmeans.predict(X)\n",
        "_ = plt.hist(y_classes)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "b10a1017-f6ed-97fc-7de8-96dd604beacc"
      },
      "outputs": [],
      "source": [
        "all_classes_images = []\n",
        "\n",
        "for class_index in range(n_classes):    \n",
        "    class_indices = np.where(y_classes == class_index)[0]\n",
        "    n = 10    \n",
        "    m = int(np.ceil(len(class_indices) / n)) \n",
        "    one_class_image = np.zeros((m*(image_size[0]+2), n*(image_size[1]+2), 3), dtype=np.uint8)    \n",
        "    \n",
        "    counter = 0\n",
        "    for i in range(m):\n",
        "        ys = i*(image_size[1] + 2)\n",
        "        ye = ys + image_size[1]\n",
        "        for j in range(n):\n",
        "            xs = j*(image_size[0] + 2)\n",
        "            xe = xs + image_size[0]\n",
        "            if counter == len(class_indices):\n",
        "                break\n",
        "            image_id, image_type = id_type_list[class_indices[counter]]; counter+=1\n",
        "            key = (image_id, image_type)\n",
        "            assert key in RESIZED_IMAGES, \"WTF\"\n",
        "            img = RESIZED_IMAGES[key]                \n",
        "            img = cv2.putText(img, image_id + ' | ' + str(image_type) + ' | ' + str(class_index), (5,img.shape[0] - 5), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (255, 255, 255), thickness=2)\n",
        "            one_class_image[ys:ye, xs:xe, :] = img[:,:,:]\n",
        "\n",
        "        if counter == len(class_indices):\n",
        "            break\n",
        "    \n",
        "    all_classes_images.append(one_class_image)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "ecea4b4c-4f1a-edac-702c-632e8d70888b"
      },
      "outputs": [],
      "source": [
        "class_index = 0\n",
        "\n",
        "m = all_classes_images[class_index].shape[0] / (image_size[0] + 2)\n",
        "n = int(np.ceil(m / 15.0))\n",
        "for i in range(n):\n",
        "    plt_st(20, 20)\n",
        "    ys = i*(image_size[0] + 2)*15\n",
        "    ye = min((i+1)*(image_size[0] + 2)*15, all_classes_images[class_index].shape[0])\n",
        "    plt.imshow(all_classes_images[class_index][ys:ye,:,:])\n",
        "    plt.title(\"Class %i, part %i\" % (class_index, i))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "48a62847-5cd2-1df9-988e-b7e007b8e5a4"
      },
      "outputs": [],
      "source": [
        "class_index = 1\n",
        "\n",
        "m = all_classes_images[class_index].shape[0] / (image_size[0] + 2)\n",
        "n = int(np.ceil(m / 15.0))\n",
        "for i in range(n):\n",
        "    plt_st(20, 20)\n",
        "    ys = i*(image_size[0] + 2)*15\n",
        "    ye = min((i+1)*(image_size[0] + 2)*15, all_classes_images[class_index].shape[0])\n",
        "    plt.imshow(all_classes_images[class_index][ys:ye,:,:])\n",
        "    plt.title(\"Class %i, part %i\" % (class_index, i))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "d65be573-0e4d-428f-c69d-d76ac099a061"
      },
      "outputs": [],
      "source": [
        "class_index = 2\n",
        "\n",
        "m = all_classes_images[class_index].shape[0] / (image_size[0] + 2)\n",
        "n = int(np.ceil(m / 15.0))\n",
        "for i in range(n):\n",
        "    plt_st(20, 20)\n",
        "    ys = i*(image_size[0] + 2)*15\n",
        "    ye = min((i+1)*(image_size[0] + 2)*15, all_classes_images[class_index].shape[0])\n",
        "    plt.imshow(all_classes_images[class_index][ys:ye,:,:])\n",
        "    plt.title(\"Class %i, part %i\" % (class_index, i))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "291c138b-4a68-1e0e-e2c9-dbceadde3783"
      },
      "outputs": [],
      "source": [
        "class_index = 3\n",
        "\n",
        "m = all_classes_images[class_index].shape[0] / (image_size[0] + 2)\n",
        "n = int(np.ceil(m / 15.0))\n",
        "for i in range(n):\n",
        "    plt_st(20, 20)\n",
        "    ys = i*(image_size[0] + 2)*15\n",
        "    ye = min((i+1)*(image_size[0] + 2)*15, all_classes_images[class_index].shape[0])\n",
        "    plt.imshow(all_classes_images[class_index][ys:ye,:,:])\n",
        "    plt.title(\"Class %i, part %i\" % (class_index, i))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "8d1b9526-48f6-4181-7c58-a6b841e5d4f2"
      },
      "outputs": [],
      "source": [
        "class_index = 4\n",
        "\n",
        "m = all_classes_images[class_index].shape[0] / (image_size[0] + 2)\n",
        "n = int(np.ceil(m / 15.0))\n",
        "for i in range(n):\n",
        "    plt_st(20, 20)\n",
        "    ys = i*(image_size[0] + 2)*15\n",
        "    ye = min((i+1)*(image_size[0] + 2)*15, all_classes_images[class_index].shape[0])\n",
        "    plt.imshow(all_classes_images[class_index][ys:ye,:,:])\n",
        "    plt.title(\"Class %i, part %i\" % (class_index, i))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "7b9a61de-67e6-9cb4-6440-7238d44976fd"
      },
      "outputs": [],
      "source": [
        "class_index = 5\n",
        "\n",
        "m = all_classes_images[class_index].shape[0] / (image_size[0] + 2)\n",
        "n = int(np.ceil(m / 15.0))\n",
        "for i in range(n):\n",
        "    plt_st(20, 20)\n",
        "    ys = i*(image_size[0] + 2)*15\n",
        "    ye = min((i+1)*(image_size[0] + 2)*15, all_classes_images[class_index].shape[0])\n",
        "    plt.imshow(all_classes_images[class_index][ys:ye,:,:])\n",
        "    plt.title(\"Class %i, part %i\" % (class_index, i))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "104efcd7-6de5-66b0-4af2-b64ff78ce5d3"
      },
      "outputs": [],
      "source": [
        "class_index = 6\n",
        "\n",
        "m = all_classes_images[class_index].shape[0] / (image_size[0] + 2)\n",
        "n = int(np.ceil(m / 15.0))\n",
        "for i in range(n):\n",
        "    plt_st(20, 20)\n",
        "    ys = i*(image_size[0] + 2)*15\n",
        "    ye = min((i+1)*(image_size[0] + 2)*15, all_classes_images[class_index].shape[0])\n",
        "    plt.imshow(all_classes_images[class_index][ys:ye,:,:])\n",
        "    plt.title(\"Class %i, part %i\" % (class_index, i))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "801b1415-20be-7660-4e21-f7d99e2ef9f2"
      },
      "outputs": [],
      "source": [
        "class_index = 7\n",
        "\n",
        "m = all_classes_images[class_index].shape[0] / (image_size[0] + 2)\n",
        "n = int(np.ceil(m / 15.0))\n",
        "for i in range(n):\n",
        "    plt_st(20, 20)\n",
        "    ys = i*(image_size[0] + 2)*15\n",
        "    ye = min((i+1)*(image_size[0] + 2)*15, all_classes_images[class_index].shape[0])\n",
        "    plt.imshow(all_classes_images[class_index][ys:ye,:,:])\n",
        "    plt.title(\"Class %i, part %i\" % (class_index, i))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "c11f78b0-bc0b-8d41-fdba-38f0e097a22a"
      },
      "outputs": [],
      "source": [
        "class_index = 8\n",
        "\n",
        "m = all_classes_images[class_index].shape[0] / (image_size[0] + 2)\n",
        "n = int(np.ceil(m / 15.0))\n",
        "for i in range(n):\n",
        "    plt_st(20, 20)\n",
        "    ys = i*(image_size[0] + 2)*15\n",
        "    ye = min((i+1)*(image_size[0] + 2)*15, all_classes_images[class_index].shape[0])\n",
        "    plt.imshow(all_classes_images[class_index][ys:ye,:,:])\n",
        "    plt.title(\"Class %i, part %i\" % (class_index, i))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "bc969529-1209-5c7e-4bfc-1625a2eb6530"
      },
      "outputs": [],
      "source": [
        "class_index = 9\n",
        "\n",
        "m = all_classes_images[class_index].shape[0] / (image_size[0] + 2)\n",
        "n = int(np.ceil(m / 15.0))\n",
        "for i in range(n):\n",
        "    plt_st(20, 20)\n",
        "    ys = i*(image_size[0] + 2)*15\n",
        "    ye = min((i+1)*(image_size[0] + 2)*15, all_classes_images[class_index].shape[0])\n",
        "    plt.imshow(all_classes_images[class_index][ys:ye,:,:])\n",
        "    plt.title(\"Class %i, part %i\" % (class_index, i))"
      ]
    }
  ],
  "metadata": {
    "_change_revision": 0,
    "_is_fork": false,
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.6.0"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}