{"cells":[{"metadata":{"_uuid":"8d84f5d2fe3e7ed64cc7c6bffde94115a117e373"},"cell_type":"markdown","source":"Current competition metric implies segmenation task. However one valid approach could incorporate object detection. In this direcrion and borrowing stuff from Kevin's excellent kernel [https://www.kaggle.com/kmader/baseline-u-net-model-part-1](http://), we attempt to extract bounding boxes information from binary rle-encoded masks.\nAnd produce correspoding CSV file for tensorflow training \nThis kernal is a small derivative from Costas Voglis kernal [https://www.kaggle.com/voglinio/from-masks-to-bounding-boxes](http://,)"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"collapsed":true},"cell_type":"code","source":"import os\nimport cv2\nimport csv\nfrom tqdm import tqdm\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nfrom skimage.io import imread\nimport matplotlib.pyplot as plt\nfrom skimage.segmentation import mark_boundaries\nfrom skimage.measure import label, regionprops\nfrom skimage.util.montage import montage2d as montage\nmontage_rgb = lambda x: np.stack([montage(x[:, :, :, i]) for i in range(x.shape[3])], -1)\nship_dir = '../input'\ntrain_image_dir = os.path.join(ship_dir, 'train')\ntest_image_dir = os.path.join(ship_dir, 'test')\n\nfrom skimage.morphology import label\ndef multi_rle_encode(img):\n    labels = label(img[:, :, 0])\n    return [rle_encode(labels==k) for k in np.unique(labels[labels>0])]\n\n# ref: https://www.kaggle.com/paulorzp/run-length-encode-and-decode\ndef rle_encode(img):\n    '''\n    img: numpy array, 1 - mask, 0 - background\n    Returns run length as string formated\n    '''\n    pixels = img.T.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)\n\ndef rle_decode(mask_rle, shape=(768, 768)):\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    for lo, hi in zip(starts, ends):\n        img[lo:hi] = 1\n    return img.reshape(shape).T  # Needed to align to RLE direction\n\ndef masks_as_image(in_mask_list, all_masks=None):\n    # Take the individual ship masks and create a single mask array for all ships\n    if all_masks is None:\n        all_masks = np.zeros((768, 768), dtype = np.int16)\n    #if isinstance(in_mask_list, list):\n    for mask in in_mask_list:\n        if isinstance(mask, str):\n            all_masks += rle_decode(mask)\n    return np.expand_dims(all_masks, -1)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"482b8891d20ac2b8052d77ee58d0f766aba7d674"},"cell_type":"markdown","source":"Let us read the masks:"},{"metadata":{"trusted":true,"_uuid":"24bcb040514e697fd80f03291d322b73146bceda","collapsed":true},"cell_type":"code","source":"masks = pd.read_csv(os.path.join('../input',\n                                 'train_ship_segmentations.csv'))\nprint(masks.shape[0], 'masks found')\nprint(masks['ImageId'].value_counts().shape[0])\nmasks.head()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"15feac3041c7f644fa1afc39478abfbab380583d"},"cell_type":"markdown","source":"and keep only those that contain ships. Keep in mind that image files can be repeated many times in the csv file. So a unique operator will give us the unique filenames that contain ships."},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true,"collapsed":true},"cell_type":"code","source":"images_with_ship = masks.ImageId[masks.EncodedPixels.isnull()==False]\nimages_with_ship = np.unique(images_with_ship.values)\nprint('There are ' +str(len(images_with_ship)) + ' image files with masks')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"3385f11ac14a1b32559133e23498984f147a89ef"},"cell_type":"markdown","source":"In order to extract the bounding box we:\n1. Load mask as binary numpy array using Kevin's `masks_as_image`)\n\n2. Label  connected regions of this mask using `skimage.measure.label`\n\n3. Measure morphological properties of these connected regions and keep the bounding box (`skimage.measure.regionprops`). For each connected region a bounding box of the form  (min_row, min_col, max_row, max_col) is returned.  \n"},{"metadata":{"trusted":true,"scrolled":false,"_uuid":"9b1ee6524f6eba8bb21921a609dfcfd2fabbf114","collapsed":true},"cell_type":"code","source":"for i in range(10):\n    image = images_with_ship[i]\n\n    fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize = (15, 5))\n    img_0 = cv2.imread(train_image_dir+'/' + image)\n    rle_0 = masks.query('ImageId==\"'+image+'\"')['EncodedPixels']\n    mask_0 = masks_as_image(rle_0)\n    #\n    # \n    lbl_0 = label(mask_0) \n    props = regionprops(lbl_0)\n    img_1 = img_0.copy()\n    print ('Image', image)\n    for prop in props:\n        print('Found bbox', prop.bbox)\n        cv2.rectangle(img_1, (prop.bbox[1], prop.bbox[0]), (prop.bbox[3], prop.bbox[2]), (255, 0, 0), 2)\n\n\n    ax1.imshow(img_0)\n    ax1.set_title('Image')\n    ax2.set_title('Mask')\n    ax3.set_title('Image with derived bounding box')\n    ax2.imshow(mask_0[...,0], cmap='gray')\n    ax3.imshow(img_1)\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"8b1c568de89f266ab84eaeecb972e644688ff017"},"cell_type":"markdown","source":"Here we calculate the bounding boxes for all `29070` images and save then into a dictionary. "},{"metadata":{"trusted":true,"_uuid":"8b7005e02786cd76b180151927b997d3b7fa62fd","collapsed":true},"cell_type":"code","source":"import gc \nbboxes_dict = {}\ni = 0\ncount_ships = 0\nfor image in tqdm(images_with_ship):\n    img_0 = cv2.imread(train_image_dir+'/' + image)\n    rle_0 = masks.query('ImageId==\"'+image+'\"')['EncodedPixels']\n    mask_0 = masks_as_image(rle_0)\n\n    lbl_0 = label(mask_0) \n    props = regionprops(lbl_0)\n    bboxes = []\n    count_ships = count_ships + len(props)\n    for prop in props:\n        bboxes.append(prop.bbox)\n        \n        \n    i = i + 1\n    if i % 500 == 0:\n        gc.collect()    \n\n    bboxes_dict[image] = bboxes.copy()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a58ca4a95fef572afa96ddf9f2f798ee4f7a8f87","collapsed":true},"cell_type":"markdown","source":"Let us save extracted bounding boxes in CSV file "},{"metadata":{"trusted":true,"_uuid":"e282e2a52d11fbceae34b8ea6166cf49323b29b3","collapsed":true},"cell_type":"code","source":"dict_images = list(bboxes_dict.keys())\nmyData = [['image_name','width','height','class','xmin','ymin','xmax','ymax']]\nmyFile = open('train.csv', 'w')\nwith myFile:\n            writer = csv.writer(myFile)\n            writer.writerows(myData)\nfor i in range(29070):\n    image = dict_images[i]\n    img_0 = cv2.imread(train_image_dir+'/' + image)\n    rle_0 = masks.query('ImageId==\"'+image+'\"')['EncodedPixels']\n    mask_0 = masks_as_image(rle_0)\n    img_1 = img_0.copy()\n    bboxs = bboxes_dict[image]\n    width, height = img_1.shape[:2]\n    for bbox in bboxs:\n        cv2.rectangle(img_1, (bbox[1], bbox[0]), (bbox[3], bbox[2]), (255, 0, 0), 2)\n        myData = [[image,width,height,'ship',bbox[1], bbox[0], bbox[3], bbox[2]]]\n        with open('train.csv','a',newline='') as myFile:\n            writer = csv.writer(myFile)\n            writer.writerows(myData)","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}