{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"markdown","source":"[Ref](https://www.kaggle.com/paulorzp/run-length-encode-and-decode)"},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nfrom skimage.data import imread\nimport matplotlib.pyplot as plt","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"48fcb313d5b76bcfabee22ca515c5d3dc851eec7"},"cell_type":"code","source":"def rle_encode(img):\n    '''\n    img: numpy array, 1 - mask, 0 - background\n    Returns run length as string formated\n    '''\n    pixels = img.flatten()\n    pixels = np.concatenate([[0], pixels, [0]])\n    runs = np.where(pixels[1:] != pixels[:-1])[0] + 1\n    runs[1::2] -= runs[::2]\n    return ' '.join(str(x) for x in runs)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"5fd28c1e0e64585b358c014af4d18facfe380003"},"cell_type":"markdown","source":"## Deciphering `rle_encode`"},{"metadata":{"trusted":true,"_uuid":"c6efa5f974987409e6cd7bd516af07c36b75a634"},"cell_type":"code","source":"pixels = np.array((0, 1, 1, 1, 1, 0, 0, 0, 1))\n\n# Concatenating a zero at the start and end of the array is to\n# make sure that the first changing is always from 0 to 1\npixels = np.concatenate([[0], pixels, [0]])\nprint('pixels:', pixels)\n\n# the array except the first element\nprint('pixels[1:]:', pixels[1:])\n# the array except the last element\nprint('pixels[:-1]:', pixels[:-1])\n\n# runs include indices to wherever 0s change to 1s or 1s change to 0s\nprint('where condition:', pixels[1:] != pixels[:-1])\nruns = np.where(pixels[1:] != pixels[:-1])\nprint('runs:', runs)\n\n# the purpose of adding 1 here is to make sure that the indices point to\n# the very first 1s or 0s of the 1s or 0s, this is needed because\n# np.where gets the indices of elements before changing\nruns = runs[0] + 1\nprint('runs = runs[0] + 1:', runs)\n\n# runs[1::2] --> runs[start:stop:step], thus 2 here is the step\n# thus runs[1::2] includes the indices of the changing from 1 to 0\nprint('runs[1::2]:', runs[1::2])\n\n# runs[::2] includes the indices for the changing from 0 to 1\nprint('runs[::2]:', runs[::2])\n\n# the length of 1s\nprint('runs[1::2]-runs[::2]:', runs[1::2] - runs[::2])\n\n# replace runs[1::2] with the lengths of consecutive 1s\nruns[1::2] -= runs[::2]\n\nprint('return:', ' '.join(str(x) for x in runs))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"e5a6ba733e718d413d88ba03d8089311a2f8cf85"},"cell_type":"code","source":"def rle_decode(mask_rle, shape):\n    '''\n    mask_rle: run-length as string formated (start length)\n    shape: (height,width) of array to return \n    Returns numpy array, 1 - mask, 0 - background\n    '''\n    s = mask_rle.split()\n    starts, lengths = [np.asarray(x, dtype=int) for x in (s[0:][::2], s[1:][::2])]\n    starts -= 1\n    ends = starts + lengths\n    img = np.zeros(shape[0] * shape[1], dtype=np.uint8)\n\n    for lo, hi in zip(starts, ends):\n        img[lo:hi] = 1\n    return img.reshape(shape)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"6feadfb4874a06cf4caa4105973bad1c879a7d33"},"cell_type":"markdown","source":"## Deciphering `rle_decode`"},{"metadata":{"trusted":true,"_uuid":"28ca58ab15afb7d5936f69e2d08666889e9e582c"},"cell_type":"code","source":"mask_rle = ' '.join(str(x) for x in runs)\ns = mask_rle.split()\nprint('s:', s)\n\nprint('s[0:][::2]:', s[0:][::2])\nassert(s[0:][::2] == s[::2])\n\nprint('s[1:][::2]:', s[1:][::2])\nassert(s[1:][::2] == s[1::2])\n\nstarts = [np.asarray(x, dtype=int) for x in (s[0:][::2], s[1:][::2])]\nprint('starts:', starts)\n\nrle_decode(mask_rle, (1, 9))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"1c98d8f2daa4035cf3deb6626e4695f16aa293c5"},"cell_type":"markdown","source":"## Testing `rle_encode` and `rle_decode`"},{"metadata":{"trusted":true,"_uuid":"2866644c96231a425948273eab9d32d314959296"},"cell_type":"code","source":"def rle_test():\n    for i in range(100):\n        data = np.random.randint(0, 2, (100,100))\n        data_rle_enc = rle_encode(data)\n        data_rle_dec = rle_decode(data_rle_enc, data.shape)\n        np.testing.assert_allclose(data, data_rle_dec)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"eb36c43ec3ed53e098cb2b4cd023c310835955e1"},"cell_type":"code","source":"rle_test()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"2e2996a381484171eee5691284b94367e68801fc"},"cell_type":"markdown","source":"## Test above code with airbus ship challenge data\n\n[Ref](https://www.kaggle.com/inversion/run-length-decoding-quick-start)"},{"metadata":{"trusted":true,"_uuid":"5e747f9b0cda80f4148d3572dfc9db3ebd3eb25e"},"cell_type":"code","source":"masks = pd.read_csv('../input/train_ship_segmentations.csv')\nnum_masks = masks.shape[0]\nprint('number of training images', num_masks)\nmasks.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"54df2be15173e762a89d6b2f9055a5df6cfd2101"},"cell_type":"code","source":"def display_img_and_masks(ImageId, ImgShape=(768, 768)):\n    img = imread('../input/train/' + ImageId)\n    img_masks = masks.loc[masks['ImageId'] == ImageId, 'EncodedPixels'].tolist()\n\n    # Take the individual ship masks and create a single mask array for all ships\n    all_masks = np.zeros(ImgShape)\n\n    for mask in img_masks:\n        # Note that NaN should compare as not equal to itself\n        if mask == mask:\n            all_masks += rle_decode(mask, ImgShape).T\n\n    fig, axarr = plt.subplots(1, 3, figsize=(15, 40))\n    axarr[0].axis('off')\n    axarr[1].axis('off')\n    axarr[2].axis('off')\n    axarr[0].imshow(img)\n    axarr[1].imshow(all_masks)\n    axarr[2].imshow(img)\n    axarr[2].imshow(all_masks, alpha=0.4)\n    plt.tight_layout(h_pad=0.1, w_pad=0.1)\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"166710f71f370a472b86d6d7abc64650201e8d7b"},"cell_type":"code","source":"# image that has ships\nImageId = '000155de5.jpg'\ndisplay_img_and_masks(ImageId)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"44e56e7ecd1c798416f572fdacec16c070284024"},"cell_type":"code","source":"# image that has no ship\nImageId = '00003e153.jpg'\ndisplay_img_and_masks(ImageId)","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}