{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Steal and critique my methods as you wish\n\nI just thought I'd let others use any elements of the pre-processing functions I've used.\nThis isn't to say I continue to use all elements of this in my current iteration."},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import numpy  as np \nimport pandas as pd \nimport os\nimport cv2 \nimport matplotlib.pyplot as plt\n\n# Global constants\nIMG_DIM       = 256\nNUM_CLASSES   = 5\n\nprint(os.listdir(\"../\"))\nprint(os.listdir(\"../input/\"))\nprint(os.listdir(\"../input/aptos2019-blindness-detection\"))\n\nINPUT_FOLDER = '../input/aptos2019-blindness-detection/'\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Cropping, Mirroring and Squaring up\n\nTo crop I just assume the eye is centered, and take the image boundaries in to the first pixel that is bright enough. (Green was used because I was also using the green channel for other preprocessing functions at the time...) The percent smaller is a hacky way to deal with the fact that some times the bottom or top of pictures that are cut off are slanted to the actual bottom of the image.\n\nFor mirroring and squaring, I presume the image is a rectangle, wider than taller, so I reflect the image up and down far enough that the final image forms a square."},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"def crop(gray, img, percent_smaller):\n    \n    thresh = 8\n    \n    top    = 0\n    left   = 0\n    bottom = gray.shape[0] - 1\n    right  = gray.shape[1] - 1\n    \n    # work in from the top and bottom along the middle collumn\n    middleCol = gray[:, int(gray.shape[1]/2)] > thresh\n    while middleCol[top] == 0:\n        top += 1\n    while middleCol[bottom] == 0:\n        bottom -= 1\n        \n    # work in from the sides along the middle row\n    middleRow = gray[int(gray.shape[0]/2)] > thresh\n    while middleRow[left] == 0:\n        left += 1\n    while middleRow[right] == 0:\n        right -= 1\n        \n    height = bottom - top\n    width  = right - left\n    \n    bottom -= int(percent_smaller*height)\n    top    += int(percent_smaller*height)\n    right  -= int(percent_smaller*width)\n    left   += int(percent_smaller*width)\n        \n    if height < 100 or width < 100:\n        print(\"Error: squareUp: bottom:\", bottom, \"top:\", top)\n        print(\"Error: squareUp: right:\", right, \"left:\", left)\n        return img\n    \n    return img[top:bottom, left:right]\n\n\n\ndef reflectAndSquareUp(img):\n    \n    height = img.shape[0]\n    width  = img.shape[1]\n    \n    # if its portrait mode, it's probably already kind of square. Make it properly square by cutting\n    # down the height until the dimensions match\n    if (height > width):\n        \n        offset = int((height - width)/2)\n        return img[offset:offset+width]\n    \n    # otherwise, do the whole reflection thingo\n    else:\n        if len(img.shape) == 3:\n            new_img = np.zeros((width, width, img.shape[2]), np.uint8)\n        else:\n            new_img = np.zeros((width, width), np.uint8)\n\n        #  0  |\n        #     |\n        #  h1 |####\n        #     |####\n        #     |####\n        #  h2 |\n        #     |\n\n        h1 = int((width - height)/2)\n        h2 = h1 + height\n\n        # paste the original into the center\n        new_img[h1:h2,:] = img\n\n        # paste in the reflections\n        for i in range(h1):\n            new_img[h1-i] = img[i]\n\n        for i in range(width - h2):\n            new_img[h2+i] = img[height - i - 1]\n\n        return new_img\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Bens Algorithms\n\nI was never quite convinced that using bens algorithm applied directly to all channels independantly made much sense. I like the idea of subtracting the gaussian blur from pixels in a weighted manner as a nifty method of contrast enhancement, but I implemented it by splitting it into the YCC first and just applying it to the Y channel, before stitching it back to RGB (initial attempts to do so on the S channel in HSV space caused headaches).\n\nI haven't made any rigorous checks that this improves performance (the NN training pipeline takes long enough, and I'm just a student chewing through my initial AWS credits atm), but just leave this here for anyone who is interested."},{"metadata":{"trusted":true},"cell_type":"code","source":"\ndef circleMask(img):\n    \n    if (img.shape[0] != img.shape[1]):\n        print(\"Error: circle mask assumes square image\")\n        return img\n    \n    dim = img.shape[0]\n    half = int(dim/2)\n    \n    # crop out circle:\n    circle_mask = np.zeros((dim, dim), np.uint8)\n    circle_mask = cv2.circle(circle_mask, (half, half), half, 1, thickness=-1)\n\n    return cv2.bitwise_and(img, img, mask=circle_mask)\n\ndef clahe_gray(gray, clipLimit=3.5, grid=4):\n\n    #-----Applying CLAHE to L-channel-------------------------------------------\n    clahe = cv2.createCLAHE(clipLimit=clipLimit, tileGridSize=(grid,grid))\n    return clahe.apply(gray)\n\ndef adjust_gamma(image, gamma=1.0):\n    # build a lookup table mapping the pixel values [0, 255] to\n    # their adjusted gamma values\n    invGamma = 1.0 / gamma\n    table = np.array([((i / 255.0) ** invGamma) * 255\n                     for i in np.arange(0, 256)]).astype(\"uint8\")\n\n    # apply gamma correction using the lookup table\n    return cv2.LUT(image, table)\n\ndef benYCC(bgr, weight=4, gamma=12):\n        \n    # convert to y, cr, cb so that we can modify the image based on just the y (brightness)\n    ycc = cv2.cvtColor(bgr, cv2.COLOR_BGR2YCrCb)\n    y, cr, cb = cv2.split(ycc)\n\n    # perform bens algorithm on the y component\n    y = cv2.addWeighted(y, weight, cv2.GaussianBlur(y, (0,0), gamma), -weight, 128)\n\n    # merge the ycc back together, and recolor it\n    ycc_modified = cv2.merge((y, cr, cb))\n    bens = cv2.cvtColor(ycc_modified, cv2.COLOR_YCrCb2BGR)\n    \n    return bens \n\n\ndef benSimple(img, weight=4, gamma=20):\n        \n    bens = cv2.addWeighted(img, weight, cv2.GaussianBlur(img, (0,0), gamma), -weight, 128)\n    \n    return bens \n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Visualisation:"},{"metadata":{"trusted":true},"cell_type":"code","source":"def test_pre_processing():\n    \n    images_dir  = f\"{INPUT_FOLDER}train_images/\"\n    df          = pd.read_csv(f\"{INPUT_FOLDER}train.csv\")\n    df.id_code  = df.id_code.apply(lambda x: x + \".png\")\n\n    for j, filename in enumerate(df.sample(4).id_code):\n        \n        bgr = cv2.imread(images_dir + filename)\n\n        # original\n        ax  = figure.add_subplot(4,4, 4*j+1)\n        plt.imshow(cv2.cvtColor(bgr, cv2.COLOR_BGR2RGB))\n\n        # cropped\n        cropped = crop(bgr[:,:,1], bgr, 0.02)\n        ax      = figure.add_subplot(4,4, 4*j+2)\n        plt.imshow(cv2.cvtColor(cropped, cv2.COLOR_BGR2RGB))\n\n        # mirrored\n        reflected = reflectAndSquareUp(cropped)\n        ax        = figure.add_subplot(4,4, 4*j+3)\n        plt.imshow(cv2.cvtColor(reflected, cv2.COLOR_BGR2RGB))\n\n        # bens\n        circled = circleMask(reflected)\n        resized = cv2.resize(circled, (IMG_DIM, IMG_DIM), interpolation=cv2.INTER_AREA)\n        bens    = benYCC(resized)\n        ax      = figure.add_subplot(4,4, 4*j+4)\n        plt.imshow(cv2.cvtColor(bens, cv2.COLOR_BGR2RGB))\n\n\nfigure=plt.figure(figsize=(22,20))\ntest_pre_processing()\n","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":1}