{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "_cell_guid": "7777d9a4-3741-606b-af50-12cadc4c5717"
      },
      "source": [
        "Using pattern matching to find the red dotted sea lions."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "_cell_guid": "9b8cbb31-b7a2-929c-3ff5-e0bd808f28f0"
      },
      "source": [
        "This version works a lot better by filtering out the red pixels first, then finding circles in the resulting image. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "1140cf35-22c3-43fa-8de9-f5c4fcd7b121"
      },
      "outputs": [],
      "source": [
        "import numpy as np\n",
        "import cv2\n",
        "import matplotlib.pyplot as plt\n",
        "\n",
        "img = cv2.cvtColor(cv2.imread(\"../input/TrainDotted/5.jpg\"), cv2.COLOR_BGR2RGB)\n",
        "plt.imshow(img, cmap='gray')"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "50e7b13a-af58-9e2e-edab-cec89fa5875e"
      },
      "outputs": [],
      "source": [
        "# Mask everything but the red dots.\n",
        "cmsk = cv2.inRange(img, np.array([160, 0, 0]), np.array([255, 50, 50])) # Get the red -ish stuff.\n",
        "# Find the circles in the masked image.\n",
        "circles = cv2.HoughCircles(cmsk,cv2.HOUGH_GRADIENT,1,50, param1=40,param2=1,minRadius=0,maxRadius=25)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "5a725813-303e-aeb6-44fb-1656ed362b2e"
      },
      "outputs": [],
      "source": [
        "#Draw rectangles around the dots. Print the total.\n",
        "'''\n",
        "if circles is not None:\n",
        "    circles = np.uint16(np.around(circles))\n",
        "    print('%d circles found.' % (len(circles[0]) ))\n",
        "    for i in circles[0,:]:\n",
        "        cv2.rectangle(img, (i[0] - 50, i[1] - 50), (i[0] + 50, i[1] + 50), (255, 0, 0), 3)\n",
        "\n",
        "plt.imshow(img, cmap = 'gray', interpolation = 'bicubic')\n",
        "'''"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "a3f32d23-ed8c-b755-57fe-947eeb1ea4f4"
      },
      "outputs": [],
      "source": [
        "#Extract one sealion\n",
        "i=0 #Sealion number\n",
        "print(circles[0,i,:])\n",
        "imgCrop= img[int(circles[0,i,1]-50):int(circles[0,i,1]+50),int(circles[0,i,0]-50):int(circles[0,i,0]+50)]\n",
        "plt.imshow(imgCrop, cmap = 'gray', interpolation = 'bicubic')\n",
        "\n",
        "#Convert to grayscal and normalize\n",
        "imgCrop=cv2.cvtColor(imgCrop, cv2.COLOR_RGB2GRAY)\n",
        "cv2.normalize(imgCrop, imgCrop, 0, 255, cv2.NORM_MINMAX)\n",
        "plt.imshow(imgCrop, cmap = 'gray', interpolation = 'bicubic')"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "d0eb3fb8-b388-b97c-9e3d-d773375d08af"
      },
      "outputs": [],
      "source": [
        "#Apply a canny filter to extract the edges\n",
        "edges = cv2.Canny(imgCrop,50,50)\n",
        "plt.imshow(edges,cmap = 'gray')"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "e4883437-476a-c335-fe0a-bcb32c1e08c5"
      },
      "outputs": [],
      "source": [
        "kernel = np.ones((5,5),np.uint8)\n",
        "#dilation = cv2.dilate(edges,kernel,iterations = 1)\n",
        "dilation = cv2.morphologyEx(edges, cv2.MORPH_CLOSE, kernel)\n",
        "plt.imshow(dilation,cmap = 'gray')"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "915b04db-6b49-284c-5a25-44e77a910618"
      },
      "outputs": [],
      "source": [
        "#Fill function\n",
        "def fillEdgeImage(img):\n",
        "    edgesNeg = img.copy();\n",
        "    # Mask used to flood filling.\n",
        "    # Notice the size needs to be 2 pixels than the image.\n",
        "    h, w = img.shape[:2]\n",
        "    mask = np.zeros((h+2, w+2), np.uint8)\n",
        " \n",
        "    # Floodfill from point (0, 0)\n",
        "    cv2.floodFill(edgesNeg, mask, (0,0), 255);\n",
        "    cv2.bitwise_not(edgesNeg, edgesNeg);\n",
        "    filledImg = (edgesNeg | img);\n",
        "    return filledImg"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "6892e946-3fd8-b0c6-5363-f82eb1801e6c"
      },
      "outputs": [],
      "source": [
        "filledImg = fillEdgeImage(dilation)\n",
        "plt.imshow(filledImg,cmap = 'gray')"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "6339018a-e8c0-1694-1f5a-ff5ff0491505"
      },
      "outputs": [],
      "source": [
        "\n",
        "# Setup SimpleBlobDetector parameters.\n",
        "params = cv2.SimpleBlobDetector_Params()\n",
        "\n",
        "# To extract white blobs\n",
        "params.blobColor = 255;\n",
        "# Change thresholds\n",
        "params.minThreshold = 10\n",
        "params.maxThreshold = 200\n",
        "# Filter by Area.\n",
        "params.filterByArea = True\n",
        "params.minArea = 0\n",
        "# Filter by Circularity\n",
        "params.filterByCircularity = False\n",
        "params.minCircularity = 0.1\n",
        "# Filter by Convexity\n",
        "params.filterByConvexity = False\n",
        "params.minConvexity = 0.87\n",
        "# Filter by Inertia\n",
        "params.filterByInertia = False\n",
        "params.minInertiaRatio = 0.01\n",
        "# Create a detector with the parameters\n",
        "detector = cv2.SimpleBlobDetector_create(params)\n",
        "\n",
        "# Detect blobs.\n",
        "keypoints = detector.detect(filledImg)\n",
        "print(keypoints)\n",
        "# Draw detected blobs as red circles.\n",
        "# cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS ensures\n",
        "# the size of the circle corresponds to the size of blob\n",
        "\n",
        "point1=keypoints[0].pt\n",
        "print(point1)\n",
        "print(keypoints[0].size)\n",
        "'''\n",
        "# Draw detected blobs as red circles.\n",
        "# cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS ensures the size of the circle corresponds to the size of blob\n",
        "im_with_keypoints = cv2.drawKeypoints(im, keypoints, np.array([]), (0,0,255), cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)\n",
        "\n",
        "# Show keypoints\n",
        "cv2.imshow(\"Keypoints\", im_with_keypoints)\n",
        "'''"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "f79e8b36-880f-9437-4877-587f12aaa1b5"
      },
      "outputs": [],
      "source": [
        "#Find the blob that is closer to the center of the image\n",
        "h, w = filledImg.shape\n",
        "count=0;\n",
        "euclDistPre=h**2+w**2;\n",
        "for i in keypoints:\n",
        "    hdiff=h/2-i.pt[0]\n",
        "    wdiff=w/2-i.pt[1]\n",
        "    euclDist = hdiff**2 + wdiff**2\n",
        "    if euclDist<euclDistPre:\n",
        "        euclDistPre = euclDist;\n",
        "        blobNb=count;\n",
        "    count+=1;   \n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "5a8b12a9-62b6-4cce-57fa-334fa5f7c7b0"
      },
      "outputs": [],
      "source": [
        "#Define the area arround the sealion\n",
        "print(keypoints[blobNb].size)\n",
        "size=keypoints[blobNb].size*1.5\n",
        "cv2.rectangle(filledImg, (round(h/2 - size/2),round(w/2 -  size/2)), (round(h/2 +  size/2), round(w/2 +  size/2)), (255, 0, 0), 3)\n",
        "plt.imshow(filledImg,cmap = 'gray')"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "a06ed485-1f1a-a4ff-04c9-cae87e8130cd"
      },
      "outputs": [],
      "source": [
        "#crop the sealion\n",
        "imgCropped=filledImg[round(h/2 - size/2):round(h/2 + size/2),round(w/2 -  size/2):round(w/2 +  size/2)]\n",
        "plt.imshow(imgCropped,cmap = 'gray')"
      ]
    }
  ],
  "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
}