{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Strange Single Pixel Holes in Masks\n\nAs [Andrej Karpathy would advise](http://karpathy.github.io/2019/04/25/recipe/), Step 1 is \"become one with the data\". As I was doing that, I noticed this strange phenomenon.\n\nAccording to the competition data page:\n> Ground truth was determined by the union of the areas marked by all labelers for that image, after removing any black band area from the areas.\n\nWe should expect the masks to essentially be unions of rectangles. Instead, as I show below, there exist strange, single pixel holes in the ground truth masks. What explains this phenomenon? Is this a flaw in the data? Is this some kind of watermark? Is there a leak here somewhere? This is inconclusive at this point.\n\nSome of the holes that I automatically detect are from tearing at the black stripe boundary, but mostly not."},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport matplotlib.patches\nimport numpy as np\nimport pandas as pd\nimport torch\nimport torch.nn.functional as F","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"def rle_to_mask(rle_string, width, height):\n    '''\n    convert RLE(run length encoding) string to numpy array\n\n    Parameters:\n    rle_string (str): string of rle encoded mask\n    height (int): height of the mask\n    width (int): width of the mask\n\n    Returns:\n    numpy.array: numpy array of the mask\n    '''\n\n    rows, cols = height, width\n\n    if rle_string == -1:\n        return np.zeros((height, width))\n    else:\n        rle_numbers = [int(num_string) for num_string in rle_string.split(' ')]\n        rle_pairs = np.array(rle_numbers).reshape(-1, 2)\n        img = np.zeros(rows * cols, dtype=np.uint8)\n        for index, length in rle_pairs:\n            index -= 1\n            img[index:index + length] = 255\n        img = img.reshape(cols, rows)\n        img = img.T\n        return img","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df = pd.read_csv('../input/understanding_cloud_organization/train.csv')\ndf.set_index('Image_Label', inplace=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"rle = df.loc['0011165.jpg_Flower', 'EncodedPixels']\nholes = [(485, 1030), (654, 1053)]\nmask = rle_to_mask(rle, 2100, 1400)\nmask = np.clip(mask, 0, 1)\n\nplt.figure()\nplt.imshow(mask)\nax = plt.gca()\nfig, axs = plt.subplots(1, len(holes))\n\nfor h_idx, h in enumerate(holes):\n    rect = matplotlib.patches.Rectangle((h[1]-20, h[0]-20), 40, 40, linewidth=1, edgecolor='red', facecolor='none')\n    ax.add_patch(rect)\n    axs[h_idx].imshow(mask[(h[0]-20):(h[0]+20), (h[1]-20):(h[1]+20)])\n    \nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"rle = df.loc['0011165.jpg_Fish', 'EncodedPixels']\nholes = [(485, 1030), (654, 1053), (804, 833)]\nmask = rle_to_mask(rle, 2100, 1400)\nmask = np.clip(mask, 0, 1)\n\nplt.figure()\nplt.imshow(mask)\nax = plt.gca()\nfig, axs = plt.subplots(1, len(holes))\n\nfor h_idx, h in enumerate(holes):\n    rect = matplotlib.patches.Rectangle((h[1]-20, h[0]-20), 40, 40, linewidth=1, edgecolor='red', facecolor='none')\n    ax.add_patch(rect)\n    axs[h_idx].imshow(mask[(h[0]-20):(h[0]+20), (h[1]-20):(h[1]+20)])\n    \nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"kernel = torch.FloatTensor([\n        [\n            [1, 1, 1, 1, 1],\n            [1, 1, 1, 1, 1],\n            [1, 1,-8, 1, 1],\n            [1, 1, 1, 1, 1],\n            [1, 1, 1, 1, 1]\n        ]\n    ]).unsqueeze(1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for i in range(100):\n    row = df.iloc[i]\n    rle = row['EncodedPixels']\n    if not isinstance(rle, float):\n        mask = rle_to_mask(rle, 2100, 1400)\n        mask = np.clip(mask, 0, 1)\n        out = F.conv2d(torch.from_numpy(mask).unsqueeze(0).unsqueeze(0).float(), weight=kernel, padding=2, stride=1)\n        holes = list(zip(*np.where(out[0, 0].numpy() == 24.)))\n        if len(holes) > 0:\n            print(row.name, holes)","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}