{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Updates\n\n28/07/2019: Added circle_crop_v2. Here we resize the image after the first crop before drawing the circle. The result is that a larger portion of the zoomed in images is retained, though it will be somewhat stretched. I think a slightly stretch is better than losing so much information."},{"metadata":{},"cell_type":"markdown","source":"# Summary\n\nBased on findings in this kernel:\n\nhttps://www.kaggle.com/taindow/be-careful-what-you-train-on\n\nI wanted to ensure that train and test images were preprocessed effectively so that the network was not able to learn the idiosyncrasies of how different target groups had been pre-processed before the competition. Image processing is not something I'm super familiar with, so suggestions on improving the code to run more effeciently are much appreciated.\n\n# References\n\nCropping black areas: https://www.kaggle.com/ratthachat/aptos-updated-preprocessing-ben-s-cropping"},{"metadata":{},"cell_type":"markdown","source":"# Function"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import os\nimport glob\nimport cv2\nimport numpy as np\n\ndef crop_image_from_gray(img,tol=7):\n    \"\"\"\n    Crop out black borders\n    https://www.kaggle.com/ratthachat/aptos-updated-preprocessing-ben-s-cropping\n    \"\"\"  \n    \n    if img.ndim ==2:\n        mask = img>tol\n        return img[np.ix_(mask.any(1),mask.any(0))]\n    elif img.ndim==3:\n        gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n        mask = gray_img>tol        \n        check_shape = img[:,:,0][np.ix_(mask.any(1),mask.any(0))].shape[0]\n        if (check_shape == 0):\n            return img\n        else:\n            img1=img[:,:,0][np.ix_(mask.any(1),mask.any(0))]\n            img2=img[:,:,1][np.ix_(mask.any(1),mask.any(0))]\n            img3=img[:,:,2][np.ix_(mask.any(1),mask.any(0))]\n            img = np.stack([img1,img2,img3],axis=-1)\n        return img\n\n\ndef circle_crop(img):   \n    \"\"\"\n    Create circular crop around image centre    \n    \"\"\"    \n    \n    img = cv2.imread(img)\n    img = crop_image_from_gray(img)    \n    \n    height, width, depth = img.shape    \n    \n    x = int(width/2)\n    y = int(height/2)\n    r = np.amin((x,y))\n    \n    circle_img = np.zeros((height, width), np.uint8)\n    cv2.circle(circle_img, (x,y), int(r), 1, thickness=-1)\n    img = cv2.bitwise_and(img, img, mask=circle_img)\n    img = crop_image_from_gray(img)\n    \n    return img \n\ndef circle_crop_v2(img):\n    \"\"\"\n    Create circular crop around image centre\n    \"\"\"\n    img = cv2.imread(img)\n    img = crop_image_from_gray(img)\n\n    height, width, depth = img.shape\n    largest_side = np.max((height, width))\n    img = cv2.resize(img, (largest_side, largest_side))\n\n    height, width, depth = img.shape\n\n    x = int(width / 2)\n    y = int(height / 2)\n    r = np.amin((x, y))\n\n    circle_img = np.zeros((height, width), np.uint8)\n    cv2.circle(circle_img, (x, y), int(r), 1, thickness=-1)\n    img = cv2.bitwise_and(img, img, mask=circle_img)\n    img = crop_image_from_gray(img)\n\n    return img","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Image Types\n\nThe basic idea is that I want to ensure all images are presented to the network in the right way. In generally I think there are 4 different \"types\" of images in the dataset.\n\n1. Spaceboy: rectangular image, no cropping\n2. Cropboy: rectangular, lossy vertical cropping\n3. Squareboy: square image, tight cropping\n4. Supercropboy: rectangular, lossy vertical and horizontal cropping\n\nInterestingly, most of the test data is 4, while most of the training data is 1 or 3. Some examples are below."},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"from matplotlib import pyplot as plt\nfig, ax = plt.subplots(nrows=1, ncols=4, figsize=(20,4))\n\nspaceboy = cv2.imread('../input/train_images/1df0a4c23c95.png')\nax[0].imshow(cv2.cvtColor(spaceboy, cv2.COLOR_BGR2RGB))\nax[0].axis('off')\n\ncropboy = cv2.imread('../input/train_images/0a1076183736.png')\nax[1].imshow(cv2.cvtColor(cropboy, cv2.COLOR_BGR2RGB))\nax[1].axis('off')\n\nsquareboy = cv2.imread('../input/train_images/0e3572b5884a.png')\nax[2].imshow(cv2.cvtColor(squareboy, cv2.COLOR_BGR2RGB))\nax[2].axis('off')\n\nsupercropboy = cv2.imread('../input/train_images/698d6e422a80.png')\nax[3].imshow(cv2.cvtColor(supercropboy, cv2.COLOR_BGR2RGB))\nax[3].axis('off')","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","collapsed":true,"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":false},"cell_type":"markdown","source":"Applying the janky function from above:"},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"fig, ax = plt.subplots(nrows=1, ncols=4, figsize=(20,4))\n\nspaceboy = circle_crop('../input/train_images/1df0a4c23c95.png')\nax[0].imshow(cv2.cvtColor(spaceboy, cv2.COLOR_BGR2RGB))\nax[0].axis('off')\n\ncropboy = circle_crop('../input/train_images/0a1076183736.png')\nax[1].imshow(cv2.cvtColor(cropboy, cv2.COLOR_BGR2RGB))\nax[1].axis('off')\n\nsquareboy = circle_crop('../input/train_images/0e3572b5884a.png')\nax[2].imshow(cv2.cvtColor(squareboy, cv2.COLOR_BGR2RGB))\nax[2].axis('off')\n\nsupercropboy = circle_crop('../input/train_images/698d6e422a80.png')\nax[3].imshow(cv2.cvtColor(supercropboy, cv2.COLOR_BGR2RGB))\nax[3].axis('off')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Not sure if information loss is worth it, but will experiment."},{"metadata":{"trusted":true},"cell_type":"code","source":"fig, ax = plt.subplots(nrows=1, ncols=4, figsize=(20,4))\n\nspaceboy = circle_crop_v2('../input/train_images/1df0a4c23c95.png')\nax[0].imshow(cv2.cvtColor(spaceboy, cv2.COLOR_BGR2RGB))\nax[0].axis('off')\n\ncropboy = circle_crop_v2('../input/train_images/0a1076183736.png')\nax[1].imshow(cv2.cvtColor(cropboy, cv2.COLOR_BGR2RGB))\nax[1].axis('off')\n\nsquareboy = circle_crop_v2('../input/train_images/0e3572b5884a.png')\nax[2].imshow(cv2.cvtColor(squareboy, cv2.COLOR_BGR2RGB))\nax[2].axis('off')\n\nsupercropboy = circle_crop_v2('../input/train_images/698d6e422a80.png')\nax[3].imshow(cv2.cvtColor(supercropboy, cv2.COLOR_BGR2RGB))\nax[3].axis('off')","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.4","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}