{"nbformat_minor": 1, "nbformat": 4, "cells": [{"outputs": [], "execution_count": null, "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", "\n", "import os\n", "import numpy as np # linear algebra\n", "import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n", "import matplotlib.pyplot as plt\n", "\n", "from skimage.io import imread, imshow\n", "from skimage.transform import resize\n", "from skimage.morphology import label\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", "\n", "from subprocess import check_output\n", "print(check_output([\"ls\", \"../input\"]).decode(\"utf8\"))\n", "\n", "# Any results you write to the current directory are saved as output."], "cell_type": "code", "metadata": {"_uuid": "7cc364f51f77683079c058ed1728b0176c445dfe", "_cell_guid": "63800151-d233-4054-aeb4-d5839b85d1d6"}}, {"source": ["This kernel is inspired by [this one](https://www.kaggle.com/keegil/keras-u-net-starter-lb-0-277)\n", "\n", "# Understanding problem, data and simple exploration\n", "1. Particular cases\n", "    * First training image\n", "    * Second training image\n", "2. Preprocessing all data\n", "3. Run-length encoding"], "cell_type": "markdown", "metadata": {"_uuid": "cb7d5123aac4203314fbffed3010e766b9acf64f", "_cell_guid": "a0f33838-265d-402d-affd-46d94018d293"}}, {"source": ["## 1. Particular cases"], "cell_type": "markdown", "metadata": {"_uuid": "b72f64055e7f0e57d3077a867e513e2623493ebb", "_cell_guid": "fa350a56-a3db-4784-8329-b5fb3dfdf59f"}}, {"outputs": [], "execution_count": null, "source": ["train_dir = '../input/stage1_train/'\n", "test_dir = '../input/stage1_test/'\n", "first_image_id = '00ae65c1c6631ae6f2be1a449902976e6eb8483bf6b0740d00530220832c6d3e'\n", "second_image_id = '0a7d30b252359a10fd298b638b90cb9ada3acced4e0c0e5a3692013f432ee4e9'\n", "first_path = train_dir + first_image_id\n", "second_path = train_dir + second_image_id"], "cell_type": "code", "metadata": {"collapsed": true, "_uuid": "fa608727b83ac55c6e67717f2d676b925ad53343", "_cell_guid": "c49a687b-8332-4a40-a02f-ac9a74ee1903"}}, {"outputs": [], "execution_count": null, "source": ["first_img = imread(first_path + '/images/' + first_image_id + '.png')\n", "second_img = imread(second_path + '/images/' + second_image_id + '.png')\n", "\n", "print('first_img => (height, width, channels)=', first_img.shape)\n", "print('second_img => (height, width, channels)=', second_img.shape)"], "cell_type": "code", "metadata": {"_uuid": "761ff61fbb75545debb3acef132fe1c60dfb656a", "_cell_guid": "cb4bca5a-cc89-4717-845f-52c0eaeffb63"}}, {"source": ["Grayscale images are encoded from 0 (black) to 255 (white) and between then we have intermediate colors ranging from totally black to totally white. In numpy, there are a type to hold this range of integers.\n", "\n", "[np.unit8](https://docs.scipy.org/doc/numpy-1.13.0/user/basics.types.html) => Unsigned integer (0 to 255)"], "cell_type": "markdown", "metadata": {"_uuid": "78ef7954b2babc57c306be65f38ae6063739fdcb", "_cell_guid": "f64e7c3e-0f66-46f3-8377-7e7149d20a03"}}, {"source": ["---\n", "Beacuse there are **4** channels in these **RGB** images, let's explore the last channel in these particular cases\n"], "cell_type": "markdown", "metadata": {"_uuid": "c75cfb27dd11d25ba5466a4938ff591806aa6c48", "_cell_guid": "99261eae-44a7-4276-909b-9afe4a376003"}}, {"outputs": [], "execution_count": null, "source": ["# show last channel of the two images\n", "imshow(first_img[:, :, 3])\n", "plt.show()\n", "imshow(second_img[:, :, 3])\n", "plt.show()"], "cell_type": "code", "metadata": {"_uuid": "efc527f2ae0b1e98460a66c57533e9d8fbbd74a6", "_cell_guid": "04695799-1442-4934-9652-9ad8c367fa0c"}}, {"outputs": [], "execution_count": null, "source": ["np.all(first_img[:, :, 3] / 255)"], "cell_type": "code", "metadata": {"_uuid": "71f52050d06b9ab601ec5ec5e321080512ceb24e", "_cell_guid": "bd79c9d4-ad85-4ee4-95f4-64d096768d0b"}}, {"source": ["The last channel is empty (totally white = 255), therefore we can ignore it.\n", "\n", "Latter in this notebook, we check if last channel in all training set images are empty\n", "___"], "cell_type": "markdown", "metadata": {"_uuid": "ae1df233d6e7b8dc5409cd2c0d2233601d72e367", "_cell_guid": "1117c64f-6600-433a-977e-158ac753bc86"}}, {"source": ["Let's define two type of mask, one (**mask_sum**) superimpose each individual mask to form one master mask and another (**mask_max**) picking the maximun element between the partial master mask and the individual mask"], "cell_type": "markdown", "metadata": {"_uuid": "d10136807d5e2844d1bd228cee248800b7c57dd6", "_cell_guid": "a8ba2135-79b8-4b95-8516-7cd84e340dee"}}, {"outputs": [], "execution_count": null, "source": ["first_mask_sum = np.zeros((256, 320, 1), dtype=np.uint8)\n", "first_mask_max = np.zeros((256, 320, 1), dtype=np.uint8)\n", "second_mask_sum = np.zeros((256, 256, 1), dtype=np.uint8)\n", "second_mask_max = np.zeros((256, 256, 1), dtype=np.uint8)\n", "\n", "# mask for first image\n", "for mask_file in next(os.walk(first_path + '/masks/'))[2]:\n", "    mask = imread(first_path + '/masks/' + mask_file)\n", "    first_mask_max = np.maximum(first_mask_max, mask[:, :, np.newaxis])\n", "    first_mask_sum += mask[:, :, np.newaxis] # because there are no overlapping\n", "    \n", "# mask for second image\n", "for mask_file in next(os.walk(second_path + '/masks/'))[2]:\n", "    mask = imread(second_path + '/masks/' + mask_file)\n", "    second_mask_max = np.maximum(second_mask_max, mask[:, :, np.newaxis])\n", "    second_mask_sum += mask[:, :, np.newaxis] # because there are no overlapping"], "cell_type": "code", "metadata": {"collapsed": true, "_uuid": "2c88dfdfbe03fc74c3b334dc8809b9dc8b867ca3", "_cell_guid": "25807a73-6365-4b33-a2f0-dd75d7da6711"}}, {"outputs": [], "execution_count": null, "source": ["print('first_mask => (height, width, channels)=', first_mask_sum.shape)\n", "print('second_mask => (height, width, channels)=', second_mask_sum.shape)"], "cell_type": "code", "metadata": {"_uuid": "a77a8768952c0b037a2c32d63dfcdcabd6c2d9f5", "_cell_guid": "ee099486-d04e-44a7-90ce-b49e5bda6351"}}, {"source": [], "cell_type": "markdown", "metadata": {"_uuid": "13993bd8aa820f8f95490158395e3ef465faf952", "_cell_guid": "d7d8d195-f352-4df5-9765-2b16d2fc0fe1"}}, {"outputs": [], "execution_count": null, "source": ["# showing first image and masks\n", "imshow(first_img)\n", "plt.show()\n", "imshow(first_mask_sum[:, :, 0])\n", "plt.show()\n", "imshow(first_mask_max[:, :, 0])\n", "plt.show()"], "cell_type": "code", "metadata": {"_uuid": "c3b1a4e47b0362b3758d296b4be5ec6cc4bfe3b2", "_cell_guid": "888215a2-691b-4427-a9ad-5617f98b6962"}}, {"outputs": [], "execution_count": null, "source": ["# showing second image and masks\n", "imshow(second_img)\n", "plt.show()\n", "imshow(second_mask_sum[:, :, 0])\n", "plt.show()\n", "imshow(second_mask_max[:, :, 0])\n", "plt.show()"], "cell_type": "code", "metadata": {"_uuid": "bf91e2d552f0758e1dfa972093f0bd78eabd6209", "_cell_guid": "1c331e49-0213-4bc5-8a5d-6fb119e766a4"}}, {"outputs": [], "execution_count": null, "source": ["# sanity check for first_mask_sum\n", "first_mask_normalized = first_mask_sum / 255\n", "zeros = (first_mask_normalized[first_mask_normalized == 0] + 1).sum()\n", "ones = first_mask_normalized[first_mask_normalized == 1].sum()\n", "zeros + ones == 256 * 320 # height x width\n", "# i.e. there are only zeros and ones, no overlapping"], "cell_type": "code", "metadata": {"_uuid": "381dd966bc9d3f6f3c6a97b2f0daac7b88ec28d5", "_cell_guid": "e1f640e5-4c86-49d0-ab4d-d85346a1eb50"}}, {"outputs": [], "execution_count": null, "source": ["# sanity check for second_mask_sum\n", "second_mask_normalized = second_mask_sum / 255\n", "zeros = (second_mask_normalized[second_mask_normalized == 0] + 1).sum()\n", "ones = second_mask_normalized[second_mask_normalized == 1].sum()\n", "zeros + ones == 256 * 256 # height x width\n", "# i.e. there are only zeros and ones, no overlapping"], "cell_type": "code", "metadata": {"_uuid": "d6060a6bd128c8f9e8b83a5a5f2c27aa6ef2d31c", "_cell_guid": "81a45ef9-f225-4ec0-8f6d-6fea58ae57da"}}, {"source": ["Latter in this notebook, we can check if this property is true for all training set masks\n", "___"], "cell_type": "markdown", "metadata": {"_uuid": "ff305c0a62143264f0af13ab3b8dceb8a925a285", "_cell_guid": "2e92a859-0782-47e1-8d4d-c34c3b587ab2"}}, {"source": ["Resizing 256x320 image to 256x256"], "cell_type": "markdown", "metadata": {"_uuid": "2130776395a570e44b41b4803851f3540ffef106", "_cell_guid": "f317b231-ef4e-446a-98fd-c3b469ab4ad0"}}, {"outputs": [], "execution_count": null, "source": ["first_img_resized = resize(first_img, (256, 256, 4), preserve_range=True, mode='constant')\n", "first_img_resized = first_img_resized.astype(dtype=np.uint8)\n", "imshow(first_img_resized)\n", "plt.show()\n", "imshow(first_img)\n", "plt.show()"], "cell_type": "code", "metadata": {"_uuid": "6a0b94ae5c4c4aecf5185cabdfccf4e642b77444", "_cell_guid": "42f8dd76-20ee-40af-8370-d95a8cccb636"}}, {"source": ["The resized image looks good\n", "___"], "cell_type": "markdown", "metadata": {"_uuid": "f618acb09c61c27d62a47fda180fbb2ee7a29589", "_cell_guid": "d6626300-5314-4af3-8943-e1b3c7084743"}}, {"source": ["## 2. Preprocessing all data"], "cell_type": "markdown", "metadata": {"_uuid": "237b78619fb4393305c45d961fc78ad124382d37", "_cell_guid": "92651638-71b1-4fea-b161-a477bcbb06c0"}}, {"outputs": [], "execution_count": null, "source": ["train_images_ids = os.listdir(train_dir)\n", "train_m = len(train_images_ids) # number of training examples\n", "test_images_ids = os.listdir(test_dir)\n", "test_m = len(test_images_ids)\n", "print('(Training examples, Test examples):', '(', train_m, ',', test_m, ')')"], "cell_type": "code", "metadata": {"_uuid": "ea1ce89bda902a5062b4236dbd84954878ff7d44", "_cell_guid": "8d9f6d48-a3dc-40d0-94bc-b96aafc46910"}}, {"source": ["In this part of the notebook, we'll do some sanity check to proof is all training set images have the same properties: shape, last channel, masks..."], "cell_type": "markdown", "metadata": {"_kg_hide-output": true, "_uuid": "32c1b7aac6f599c3c9709ed1ebc7ae36264f2aa1", "_cell_guid": "5bdb348d-c4a5-42f7-9abb-1a89c51d6c1d"}}, {"outputs": [], "execution_count": null, "source": ["d = dict()\n", "last_channel_empty = []\n", "for i, ids in enumerate(train_images_ids):\n", "    path = train_dir + ids\n", "    img = imread(path + '/images/' + ids + '.png')\n", "    last_channel_empty.append( np.all(img[:, :, 3] / 255) )\n", "    shape = img.shape\n", "    if (shape in d.keys()):\n", "        d[shape] += 1\n", "    else:\n", "        d[shape] = 1\n", "\n", "# print all images shape\n", "for shape in d.keys():\n", "    print(shape, ':', d[shape])\n", "if np.all(last_channel_empty):\n", "    print('Last channel empty in all images')\n", "else:\n", "    print('Last channel not empty in some images')"], "cell_type": "code", "metadata": {"_uuid": "db49a8db68a0ecc4a2a2fd9d3854971ebb749e14", "_cell_guid": "51c96a6a-de2e-4b01-9045-9d793916adb4"}}, {"source": ["Beacuse there are several shapes, we need to resize all images into one common shape.\n", "\n", "All images have 4 channels but the last channel is empty, therefore, we can delete it."], "cell_type": "markdown", "metadata": {"_uuid": "fa356376c7dc1a5f7c88cf7eb6fd221b07f459f5", "_cell_guid": "8b36dd25-655a-414c-949b-74bcb89e516a"}}, {"outputs": [], "execution_count": null, "source": ["# Let's define the common shape to resize all images\n", "height, width, channels = 256, 256, 3\n", "print('height, width, channels:', height, width, channels)"], "cell_type": "code", "metadata": {"_uuid": "933ef2a9311b9289a4b25578d0e616c82d3375bc", "_cell_guid": "96c48609-fa5e-46e1-b5af-cffc95859d8e"}}, {"outputs": [], "execution_count": null, "source": ["X_train = np.zeros((train_m, height, width, channels), dtype=np.uint8)\n", "Y_train = np.zeros((train_m, height, width, 1), dtype=np.uint8)\n", "\n", "print(train_m, 'examples =>', end=' ')\n", "for i, ids in enumerate(train_images_ids):\n", "    if (i%10==0):\n", "        print(i, end=',')\n", "    path = train_dir + ids\n", "    img = imread(path + '/images/' + ids + '.png')[:, :, :channels]\n", "    if (img.shape != (height, width, channels)): # resize it\n", "        img = resize(img, (height, width, channels), mode='constant', preserve_range=True)\n", "        img = img.astype(np.uint8)\n", "    X_train[i] = img\n", "    mask = np.zeros((height, width, 1), dtype=np.uint8)\n", "    for mask_file in os.listdir(path + '/masks/'):\n", "        mask_ = imread(path + '/masks/' + mask_file)\n", "        mask_ = mask_[:, :, np.newaxis]\n", "        if (mask_.shape != (height, width, 1)):\n", "            mask_ = resize(mask_, (height, width, 1), mode='constant', preserve_range=True)\n", "            mask_ = mask_.astype(np.uint8)\n", "        mask += mask_\n", "    Y_train[i] = mask\n", "print('Done')"], "cell_type": "code", "metadata": {"_uuid": "b9704ba0e1bcd7ed5d9c35d4c4c1e6c72e1021f8", "_cell_guid": "70a6a250-6e84-44a7-8a9d-4fc4bd8bf884"}}, {"outputs": [], "execution_count": null, "source": ["X_test = np.zeros((test_m, height, width, channels), dtype=np.uint8)\n", "sizes_test = [] # latter, for submit results, we need the original shapes\n", "\n", "print(test_m, 'examples =>', end=' ')\n", "for i, ids in enumerate(test_images_ids):\n", "    if (i%5==0):\n", "        print(i, end=',')\n", "    path = test_dir + ids\n", "    img = imread(path + '/images/' + ids + '.png')[:, :, :channels]\n", "    sizes_test.append(img.shape)\n", "    if (img.shape != (height, width, channels)):\n", "        img = resize(img, (height, width, channels), mode='constant', preserve_range=True)\n", "        img = img.astype(np.uint8)\n", "    X_test[i] = img\n", "print('Done')"], "cell_type": "code", "metadata": {"_uuid": "1c3503d1f13ded167a4a6426a999bf378e8cb94f", "_cell_guid": "c2a15071-7f26-402f-86fb-a4ecd1a12809"}}, {"outputs": [], "execution_count": null, "source": ["print('Shape X_train:', X_train.shape)\n", "print('Shape Y_train:', Y_train.shape)\n", "print('Shape X_test:', X_test.shape)"], "cell_type": "code", "metadata": {"_uuid": "baec696442cac362d954858e0bfb6e347e5d5988", "_cell_guid": "36bd696c-0353-466c-8418-9ef827375174"}}, {"outputs": [], "execution_count": null, "source": ["# Normalice inputs\n", "X_train = X_train / 255 # values ranging form 0 to 1\n", "Y_train = Y_train / 255 # only contains 0 or 1\n", "X_test = X_test / 255    # values ranging form 0 to 1"], "cell_type": "code", "metadata": {"collapsed": true, "_uuid": "3432a4a86a78f56f7d6befdec8a186c26b958fa6", "_cell_guid": "5344b70d-365d-4c3e-8dff-1525a6dfbea2"}}, {"source": ["Now we can train our [U-net](https://arxiv.org/pdf/1505.04597.pdf) model over X_train and test it over X_test to submit results in LB."], "cell_type": "markdown", "metadata": {"_uuid": "370f92be3629957550efa77fece63924e286798b", "_cell_guid": "3df27b38-2958-4ee1-ad3f-14097dc1e75f"}}, {"source": ["## 3. Run-length encoding\n", "I've used the implementation done in https://www.kaggle.com/rakhlin/fast-run-length-encoding-python"], "cell_type": "markdown", "metadata": {}}, {"outputs": [], "execution_count": null, "source": ["# Run-length encoding\n", "def rle_encoding(x):\n", "    dots = np.where(x.T.flatten() == 1)[0]\n", "    run_lengths = []\n", "    prev = -2\n", "    for b in dots:\n", "        if (b > prev+1): run_lengths.extend((b+1, 0))\n", "        run_lengths[-1] += 1\n", "        prev = b\n", "    return run_lengths\n", "\n", "def prob_to_rles(x, cutoff=0.5):\n", "    lab_img = label(x > cutoff)\n", "    for i in range(1, lab_img.max() + 1):\n", "        yield rle_encoding(lab_img == i)"], "cell_type": "code", "metadata": {"collapsed": true}}, {"outputs": [], "execution_count": null, "source": ["#threshold = 0.5\n", "#y_pred = model.predict(X_test)\n", "# resize all y_pred images to its original shape.\n", "#y_pred_resize = []\n", "#for i in range(len(y_pred)):\n", "#    y_pred_resize.append(resize(y_pred[i], (sizes_test[i][0], sizes_test[i][1]), \n", "#                                mode='constant', preserve_range=True))\n", "#y_pred_t = y_pred_resize > threshold # only 0's and 1's"], "cell_type": "code", "metadata": {}}, {"outputs": [], "execution_count": null, "source": ["# over y_pred_t, apply run length encoding to submit results\n", "#new_test_ids = []\n", "#rles = []\n", "#for n, id_ in enumerate(test_images_ids):\n", "#    rle = list(prob_to_rles(y_pred_resize[n]))\n", "#    rles.extend(rle)\n", "#    new_test_ids.extend([id_] * len(rle))"], "cell_type": "code", "metadata": {}}, {"outputs": [], "execution_count": null, "source": ["# create submission DataFrame\n", "#sub = pd.DataFrame()\n", "#sub['ImageId'] = new_test_ids\n", "#sub['EncodedPixels'] = pd.Series(rles).apply(lambda x: ' '.join(str(y) for y in x))\n", "#sub.to_csv('predictions.csv', index=False)"], "cell_type": "code", "metadata": {"collapsed": true}}], "metadata": {"kernelspec": {"display_name": "Python 3", "name": "python3", "language": "python"}, "language_info": {"file_extension": ".py", "pygments_lexer": "ipython3", "name": "python", "version": "3.6.4", "nbconvert_exporter": "python", "mimetype": "text/x-python", "codemirror_mode": {"name": "ipython", "version": 3}}}}