{"cells":[{"metadata":{"_uuid":"3b0a88e8350d56f49e759507d3ec72b5380d8d53"},"cell_type":"markdown","source":"I tried to use [@martinpiotte's](https://www.kaggle.com/martinpiotte)  kernel referenced from, <br>\n        \n[bounding_box affine transform_1](https://www.kaggle.com/martinpiotte/bounding-box-data-for-the-whale-flukes) <br>\n[bounding_box affine transform_2](http://www.kaggle.com/martinpiotte/whale-recognition-model-with-score-0-78563) <br>\n\n- affine transform RGB, Grey level preprocessing"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load in \n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the \"../input/\" directory.\n# For example, running this (by clicking run or pressing Shift+Enter) will list the files in the input directory\n\nimport os\nprint(os.listdir(\"../input\"))\n\n# Any results you write to the current directory are saved as output.","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"31e98d32c6fa386024a3eb26089b85d37a81450f"},"cell_type":"code","source":"from tqdm import tqdm_notebook as tqdm\nfrom PIL import Image as pil_image\nfrom PIL.ImageDraw import Draw\nimport pandas as pd\nfrom os.path import isfile\nimport numpy as np\nimport matplotlib.pyplot as plt\nfrom PIL.ImageDraw import Draw\n\nTRAIN_DF = '../input/humpback-whale-identification/train.csv'\nSUB_Df = '../input/humpback-whale-identification/sample_submission.csv'\nTRAIN = '../input/humpback-whale-identification/train/'\nTEST = '../input/humpback-whale-identification/test/'\nBB_DF = \"../input/metadata/bounding_boxes.csv\"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"47a041bb9f1a7976d0f107eabf06ab56a83ca56a"},"cell_type":"code","source":"tagged = dict([(p, w) for _, p, w in pd.read_csv(TRAIN_DF).to_records()])\nsubmit = [p for _, p, _ in pd.read_csv(SUB_Df).to_records()]\njoin = list(tagged.keys()) + submit","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"25f31209d74d5052a1c2ffd1e7a12423c74f040c"},"cell_type":"code","source":"def expand_path(p):\n    if isfile(TRAIN + p):\n        return TRAIN + p\n    if isfile(TEST + p):\n        return TEST + p\n    return p","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"cf761dbdf0263541a880c78bd9042d6ede8948fd"},"cell_type":"code","source":"# Raw data image read, if data in rotate list, 180 deg rotate\ndef read_raw_image(p):\n    img = pil_image.open(expand_path(p))\n    #if p in rotate: img = img.rotate(180)  # if rotation is required,\n    return img","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"7ffc96a1f137f8148091829e9cc3a5898251a3cd"},"cell_type":"code","source":"def show_whale(imgs, per_row=2):\n    n         = len(imgs)\n    rows      = (n + per_row - 1)//per_row\n    cols      = min(per_row, n)\n    fig, axes = plt.subplots(rows,cols, figsize=(24//per_row*cols,24//per_row*rows))\n    for ax in axes.flatten(): ax.axis('off')\n    for i,(img,ax) in enumerate(zip(imgs, axes.flatten())): ax.imshow(img.convert('RGB'))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c099497cc3da46ad077a6f099c492adac8a0cec9"},"cell_type":"code","source":"# image size data generation\n\np2size = {}\nfor p in tqdm(join):\n    size = pil_image.open(expand_path(p)).size\n    p2size[p] = size","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"1f09e085043dd06b8566a316e0d5dc66f6f48ede"},"cell_type":"code","source":"# anisotropy; The horizontal compression ratio, ~ 2\n\ntotal_width = 0\ntotal_height = 0\n\nfor val in p2size.values():\n    total_width  += val[0]\n    total_height += val[1]\n    \navg_width = total_width/len(p2size)\navg_height = total_height/len(p2size)\nratio = avg_width/avg_height\nratio","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"91cd4b843813b29757281c7d01b5c663e9e60e7e"},"cell_type":"code","source":"# Bounding box data load\n\np2bb = pd.read_csv(BB_DF).set_index(\"Image\")\np2bb.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"2293e3d1d8befa7bed23976e1373d3442519cb55"},"cell_type":"code","source":"# example\nfilename = list(tagged.keys())[100]\nfilename","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"af91c31912dcfe0159f3a0d90ce59d91442ef95a"},"cell_type":"code","source":"def draw_dot(draw, x, y):\n    draw.ellipse(((x-5,y-5),(x+5,y+5)), fill='red', outline='red')\n\ndef draw_dots(draw, coordinates):\n    for x,y in coordinates: draw_dot(draw, x, y)\n\nsize_x,size_y = p2size[filename]\nx0, y0, x1, y1 = p2bb.loc[filename]\n\n#if rotation is required,\n#if filename in rotate:\n#    x0, y0, x1, y1 = size_x - x1, size_y - y1, size_x - x0, size_y - y0\n\ncoordinates = [(x0, y0), (x1, y1)]\nimg = read_raw_image(filename)\ndraw = Draw(img)\ndraw_dots(draw, coordinates)\nimg","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"15d2f3d27c316c144eb70984ffc276e4ac5e59f9"},"cell_type":"code","source":"def bounding_rectangle(list):\n    x0, y0 = list[0]\n    x1, y1 = x0, y0\n    for x,y in list[1:]:\n        x0 = min(x0, x)\n        y0 = min(y0, y)\n        x1 = max(x1, x)\n        y1 = max(y1, y)\n    return x0,y0,x1,y1\n\nbox = bounding_rectangle(coordinates)\nbox","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"scrolled":true,"_uuid":"249f1701ff81a72e69134a42ebfadef891b736cc"},"cell_type":"code","source":"draw.rectangle(box, outline='red')\nimg","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"da117168055cc4653c8f3daaa4dbaea77f1b002f"},"cell_type":"markdown","source":"# Affine transform_RGB\n- You can use this code for traning siamese network (martinpiotte's ver.)\n- margin added to this kernel, as mentioned from previous kernel\n- Margin cripping is prefered because edge information could be damaged during data augmentation at exact clipping"},{"metadata":{"trusted":true,"_uuid":"650fb10a7a3bf88123046319b76eeef7c2c423c4"},"cell_type":"code","source":"import sys\nimport platform\nold_stderr = sys.stderr\nsys.stderr = open('/dev/null' if platform.system() != 'Windows' else 'nul', 'w')\nsys.stderr = old_stderr\n\nimport random\nfrom keras import backend as K\nfrom keras.preprocessing.image import img_to_array,array_to_img\nfrom scipy.ndimage import affine_transform\n\nimg_shape    = (384,384,3) # The image shape used by the model\nanisotropy   = 2.0 # The horizontal compression ratio\n#crop_margin  = 0.05 # The margin added around the bounding box to compensate for bounding box inaccuracy\n\ndef build_transform(rotation, shear, height_zoom, width_zoom, height_shift, width_shift):\n    \"\"\"\n    Build a transformation matrix with the specified characteristics.\n    \"\"\"\n    rotation        = np.deg2rad(rotation)\n    shear           = np.deg2rad(shear)\n    rotation_matrix = np.array([[np.cos(rotation), np.sin(rotation), 0], [-np.sin(rotation), np.cos(rotation), 0], [0, 0, 1]])\n    shift_matrix    = np.array([[1, 0, height_shift], [0, 1, width_shift], [0, 0, 1]])\n    shear_matrix    = np.array([[1, np.sin(shear), 0], [0, np.cos(shear), 0], [0, 0, 1]])\n    zoom_matrix     = np.array([[1.0/height_zoom, 0, 0], [0, 1.0/width_zoom, 0], [0, 0, 1]])\n    shift_matrix    = np.array([[1, 0, -height_shift], [0, 1, -width_shift], [0, 0, 1]])\n    return np.dot(np.dot(rotation_matrix, shear_matrix), np.dot(zoom_matrix, shift_matrix))\n\ndef read_cropped_image(p, augment, crop_margin=0.05):\n    \"\"\"\n    @param p : the name of the picture to read\n    @param augment: True/False if data augmentation should be performed\n    @return a numpy array with the transformed image\n    \"\"\"\n    size_x,size_y = p2size[p]\n    \n    # Determine the region of the original image we want to capture based on the bounding box.\n    x0,y0,x1,y1   = p2bb.loc[p]\n    # if rotation is required,\n    #if p in rotate: x0, y0, x1, y1 = size_x - x1, size_y - y1, size_x - x0, size_y - y0\n\n    dx            = x1 - x0\n    dy            = y1 - y0\n    x0           -= dx*crop_margin\n    x1           += dx*crop_margin + 1\n    y0           -= dy*crop_margin\n    y1           += dy*crop_margin + 1\n    if (x0 < 0     ): x0 = 0\n    if (x1 > size_x): x1 = size_x\n    if (y0 < 0     ): y0 = 0\n    if (y1 > size_y): y1 = size_y\n    dx            = x1 - x0\n    dy            = y1 - y0\n    if dx > dy*anisotropy:\n        dy  = 0.5*(dx/anisotropy - dy)\n        y0 -= dy\n        y1 += dy\n    else:\n        dx  = 0.5*(dy*anisotropy - dx)\n        x0 -= dx\n        x1 += dx\n    \n    # Generate the transformation matrix\n    trans = np.array([[1, 0, -0.5*img_shape[0]], [0, 1, -0.5*img_shape[1]], [0, 0, 1]])\n    trans = np.dot(np.array([[(y1 - y0)/img_shape[0], 0, 0], [0, (x1 - x0)/img_shape[1], 0], [0, 0, 1]]), trans)\n    \n    if augment:\n        trans = np.dot(build_transform(\n            random.uniform(-5, 5),\n            random.uniform(-5, 5),\n            random.uniform(0.8, 1.0),\n            random.uniform(0.8, 1.0),\n            random.uniform(-0.05*(y1 - y0), 0.05*(y1 - y0)),\n            random.uniform(-0.05*(x1 - x0), 0.05*(x1 - x0))\n            ), trans) \n    trans = np.dot(np.array([[1, 0, 0.5*(y1 + y0)], [0, 1, 0.5*(x1 + x0)], [0, 0, 1]]), trans)\n\n    # Read the image, Comvert to numpy array\n    img   = read_raw_image(p)\n    img   = img_to_array(img)\n    \n    # Apply affine transformation\n    matrix = trans[:2,:2]\n    offset = trans[:2,2]\n    x = np.moveaxis(img, -1, 0) # Change to channel first\n    \n    img    = [affine_transform(img, matrix, offset, order=1, output_shape=img_shape[:-1], mode='constant', cval=np.average(img)) for img in x]\n    img    = np.moveaxis(np.stack(img, axis=0), 0, -1)\n\n    # Normalize to zero mean and unit variance\n    img  -= np.mean(img, keepdims=True)\n    img  /= np.std(img, keepdims=True) + K.epsilon()\n    \n    return img\n\ndef read_for_training(p, crop_margin=0.05):\n    \"\"\"\n    Read and preprocess an image with data augmentation (random transform).\n    \"\"\"\n    print(\"Training crop_margin: \", crop_margin)\n    return read_cropped_image(p, True, crop_margin)\n\ndef read_for_validation(p, crop_margin=0.05):\n    \"\"\"\n    Read and preprocess an image without data augmentation (use for testing).\n    \"\"\"\n    print(\"Validation crop_margin: \", crop_margin)\n    return read_cropped_image(p, False, crop_margin)\n\nimgs = [\n    read_raw_image(filename),                                      # raw image plot\n    array_to_img(read_for_validation(filename)),                   # Affine transform (resize with bbox) without augmentation\n    array_to_img(read_for_validation(filename, crop_margin=0)),    # Affine transform (resize with bbox) without augmentation, margin = 0\n    array_to_img(read_for_training(filename)),                     # Affine transform (resize with bbox) with augmentation\n    array_to_img(read_for_training(filename, crop_margin=0))       # Affine transform (resize with bbox) with augmentation, margin = 0\n]\nshow_whale(imgs, per_row=5)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"29bcf9a300c521fe24c679f553495eca3730d773"},"cell_type":"markdown","source":"# Affine transform_Grey level"},{"metadata":{"trusted":true,"_uuid":"fce5bd31f2af2f6e1a3444f8777f5e26743e98df"},"cell_type":"code","source":"img_shape    = (384,384,1)\n\ndef read_cropped_image(p, augment, crop_margin=0.05):\n    \"\"\"\n    @param p : the name of the picture to read\n    @param augment: True/False if data augmentation should be performed\n    @return a numpy array with the transformed image\n    \"\"\"\n    size_x,size_y = p2size[p]\n    \n    # Determine the region of the original image we want to capture based on the bounding box.\n    x0,y0,x1,y1   = p2bb.loc[p]\n    dx            = x1 - x0\n    dy            = y1 - y0\n    x0           -= dx*crop_margin\n    x1           += dx*crop_margin + 1\n    y0           -= dy*crop_margin\n    y1           += dy*crop_margin + 1\n    if (x0 < 0     ): x0 = 0\n    if (x1 > size_x): x1 = size_x\n    if (y0 < 0     ): y0 = 0\n    if (y1 > size_y): y1 = size_y\n    dx            = x1 - x0\n    dy            = y1 - y0\n    if dx > dy*anisotropy:\n        dy  = 0.5*(dx/anisotropy - dy)\n        y0 -= dy\n        y1 += dy\n    else:\n        dx  = 0.5*(dy*anisotropy - dx)\n        x0 -= dx\n        x1 += dx\n\n    # Generate the transformation matrix\n    trans = np.array([[1, 0, -0.5*img_shape[0]], [0, 1, -0.5*img_shape[1]], [0, 0, 1]])\n    trans = np.dot(np.array([[(y1 - y0)/img_shape[0], 0, 0], [0, (x1 - x0)/img_shape[1], 0], [0, 0, 1]]), trans)\n    if augment:\n        trans = np.dot(build_transform(\n            random.uniform(-5, 5),\n            random.uniform(-5, 5),\n            random.uniform(0.8, 1.0),\n            random.uniform(0.8, 1.0),\n            random.uniform(-0.05*(y1 - y0), 0.05*(y1 - y0)),\n            random.uniform(-0.05*(x1 - x0), 0.05*(x1 - x0))\n            ), trans)\n    trans = np.dot(np.array([[1, 0, 0.5*(y1 + y0)], [0, 1, 0.5*(x1 + x0)], [0, 0, 1]]), trans)\n\n    # Read the image, transform to black and white and comvert to numpy array\n    img   = read_raw_image(p).convert('L')\n    img   = img_to_array(img)\n    \n    # Apply affine transformation\n    matrix = trans[:2,:2]\n    offset = trans[:2,2]\n    img    = img.reshape(img.shape[:-1])\n    img    = affine_transform(img, matrix, offset, output_shape=img_shape[:-1], order=1, mode='constant', cval=np.average(img))\n    img    = img.reshape(img_shape)\n    \n    # Normalize to zero mean and unit variance\n    img  -= np.mean(img, keepdims=True)\n    img  /= np.std(img, keepdims=True) + K.epsilon()\n    return img\n\ndef read_for_training(p):\n    \"\"\"\n    Read and preprocess an image with data augmentation (random transform).\n    \"\"\"\n    return read_cropped_image(p, True)\n\ndef read_for_validation(p):\n    \"\"\"\n    Read and preprocess an image without data augmentation (use for testing).\n    \"\"\"\n    return read_cropped_image(p, False)\n\nimgs = [\n    read_raw_image(filename),                      # raw image plot\n    array_to_img(read_for_validation(filename)),   # Affine transform (resize with bbox) without augmentation\n    array_to_img(read_for_training(filename))      # Affine transform (resize with bbox) with augmentation\n]\nshow_whale(imgs, per_row=3)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"8c1d6d1b781efde312df422480f1b7838d3491eb"},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}