{"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_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# **Imports**","metadata":{"papermill":{"duration":0.013747,"end_time":"2021-11-11T08:27:14.919452","exception":false,"start_time":"2021-11-11T08:27:14.905705","status":"completed"},"tags":[]}},{"cell_type":"code","source":"import os\nimport random\nimport time\nimport collections\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport cv2\nfrom PIL import Image, ImageEnhance, ImageFilter\nfrom sklearn.model_selection import train_test_split\nfrom tqdm.notebook import tqdm\n\nimport torch\nimport torchvision\nfrom torchvision.transforms import ToPILImage\nfrom torchvision.transforms import functional as F\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision.models.detection.faster_rcnn import FastRCNNPredictor\nfrom torchvision.models.detection.mask_rcnn import MaskRCNNPredictor\n\nfrom skimage import exposure\nimport torchvision.transforms as T","metadata":{"papermill":{"duration":3.840547,"end_time":"2021-11-11T08:27:18.774549","exception":false,"start_time":"2021-11-11T08:27:14.934002","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2021-11-11T21:55:27.131084Z","iopub.execute_input":"2021-11-11T21:55:27.131431Z","iopub.status.idle":"2021-11-11T21:55:30.181812Z","shell.execute_reply.started":"2021-11-11T21:55:27.131331Z","shell.execute_reply":"2021-11-11T21:55:30.181006Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"TEST = False\n\ndata_directory = '../input/sartorius-cell-instance-segmentation'\nDEVICE = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')\nBATCH_SIZE = 2\nNUM_EPOCHS = 20\n\nTRAIN_CSV = f\"{data_directory}/train.csv\"\nTRAIN_PATH = f\"{data_directory}/train\"\nTEST_PATH = f\"{data_directory}/test\"\n\nWIDTH = 704\nHEIGHT = 520\n\nRESNET_MEAN = (0.485, 0.456, 0.406)\nRESNET_STD = (0.229, 0.224, 0.225)","metadata":{"papermill":{"duration":0.023035,"end_time":"2021-11-11T08:27:18.809743","exception":false,"start_time":"2021-11-11T08:27:18.786708","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2021-11-11T21:55:30.183919Z","iopub.execute_input":"2021-11-11T21:55:30.184216Z","iopub.status.idle":"2021-11-11T21:55:30.192118Z","shell.execute_reply.started":"2021-11-11T21:55:30.184173Z","shell.execute_reply":"2021-11-11T21:55:30.191153Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Utils**","metadata":{"papermill":{"duration":0.011828,"end_time":"2021-11-11T08:27:18.833736","exception":false,"start_time":"2021-11-11T08:27:18.821908","status":"completed"},"tags":[]}},{"cell_type":"code","source":"# ref: https://www.kaggle.com/inversion/run-length-decoding-quick-start\ndef rle_decode(mask_rle, shape, color=1):\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.float32)\n    for lo, hi in zip(starts, ends):\n        img[lo : hi] = color\n    return img.reshape(shape)\n\n\ndef visualize(**images):\n    n = len(images)\n    plt.figure(figsize=(16, 12))\n    for i, (name, image) in enumerate(images.items()):\n        plt.subplot(1, n, i + 1)\n        plt.xticks([])\n        plt.yticks([])\n        plt.title(' '.join(name.split('_')).title())\n        plt.imshow(image)\n    plt.show()","metadata":{"papermill":{"duration":0.026445,"end_time":"2021-11-11T08:27:18.872292","exception":false,"start_time":"2021-11-11T08:27:18.845847","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2021-11-11T22:16:55.507661Z","iopub.execute_input":"2021-11-11T22:16:55.507952Z","iopub.status.idle":"2021-11-11T22:16:55.517371Z","shell.execute_reply.started":"2021-11-11T22:16:55.507920Z","shell.execute_reply":"2021-11-11T22:16:55.516547Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Robust Augmentation Utils**","metadata":{"papermill":{"duration":0.012052,"end_time":"2021-11-11T08:27:18.896680","exception":false,"start_time":"2021-11-11T08:27:18.884628","status":"completed"},"tags":[]}},{"cell_type":"code","source":"class Compose:\n    def __init__(self, transforms):\n        self.transforms = transforms\n\n    def __call__(self, image, target):\n        for t in self.transforms:\n            image, target = t(image, target)\n        return image, target\n\n\nclass VerticalFlip:\n    def __init__(self, prob):\n        self.prob = prob\n\n    def __call__(self, image, target):\n        if random.random() < self.prob:\n            height, width = image.shape[-2:]\n            image = image.flip(-2)\n            bbox = target[\"boxes\"]\n            bbox[:, [1, 3]] = height - bbox[:, [3, 1]]\n            target[\"boxes\"] = bbox\n            target[\"masks\"] = target[\"masks\"].flip(-2)\n        return image, target\n\n\nclass HorizontalFlip:\n    def __init__(self, prob):\n        self.prob = prob\n\n    def __call__(self, image, target):\n        if random.random() < self.prob:\n            height, width = image.shape[-2:]\n            image = image.flip(-1)\n            bbox = target[\"boxes\"]\n            bbox[:, [0, 2]] = width - bbox[:, [2, 0]]\n            target[\"boxes\"] = bbox\n            target[\"masks\"] = target[\"masks\"].flip(-1)\n        return image, target\n\n\nclass RandomRatation:\n    def __init__(self, prob):\n        self.prob = prob\n\n    def __call__(self, image, masks):\n        if random.random() < self.prob:\n\n            transformT = T.Compose([\n                T.RandomHorizontalFlip(),\n                T.RandomVerticalFlip(),\n                T.RandomChoice([\n                    T.RandomAffine(degrees=45, scale=(.9, 2.), translate=(0.1, 0.5), fill=0), # random transformations\n                    T.RandomPerspective(distortion_scale=0.32, fill=0),                        # random perspective\n                    T.RandomResizedCrop(size = (HEIGHT, WIDTH), scale = (.9, 1.4))             # random resized cropp\n                    # ... ( feel free to add yout own augmentation :) )\n                ]),\n            ])\n\n            transformImg = T.Compose([\n                T.RandomAdjustSharpness(sharpness_factor=0.1),\n            ])\n\n            # Set seed for same augmentations in one run\n            seed = np.random.randint(2147483647)  # make a seed with numpy generator\n            random.seed(seed)  # apply this seed to img transforms\n            torch.manual_seed(seed)\n\n\n            # Transform Image\n            image = transformT(image)\n\n            # Transform Masks\n            masks = np.array(masks)\n            new_masks = np.zeros((masks.shape[0], \n                                  HEIGHT, WIDTH\n                                  ), dtype=np.uint8)\n            for i, mask in enumerate(masks):\n                mask = Image.fromarray((mask).astype(np.uint8))\n                random.seed(seed)  # apply this seed to img tranfsorms\n                torch.manual_seed(seed)\n                mask = transformT(mask)\n                new_masks[i, :, :] = mask\n                \n            return image, new_masks\n        return image, masks\n\n\nclass Normalize:\n    def __call__(self, image, target):\n        image = F.normalize(image, RESNET_MEAN, RESNET_STD)\n        return image, target\n\n\nclass ToTensor:\n    def __call__(self, image, target):\n        image = F.to_tensor(image)\n        return image, target\n\n\ndef get_transform(train):\n    transforms = [ToTensor(), Normalize()]\n    if train:\n        transforms.append(RandomRatation(1.0))\n\n    return Compose(transforms)\n","metadata":{"papermill":{"duration":0.019474,"end_time":"2021-11-11T08:27:18.928567","exception":false,"start_time":"2021-11-11T08:27:18.909093","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2021-11-11T22:19:39.886115Z","iopub.execute_input":"2021-11-11T22:19:39.886574Z","iopub.status.idle":"2021-11-11T22:19:39.909743Z","shell.execute_reply.started":"2021-11-11T22:19:39.886525Z","shell.execute_reply":"2021-11-11T22:19:39.908699Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Dataset + Augmentation**","metadata":{"papermill":{"duration":0.012057,"end_time":"2021-11-11T08:27:18.952832","exception":false,"start_time":"2021-11-11T08:27:18.940775","status":"completed"},"tags":[]}},{"cell_type":"code","source":"class CellDataset(Dataset):\n    def __init__(self, image_dir, df, transforms=None, resize=False):\n        self.transforms = transforms\n        self.image_dir = image_dir\n        self.df = df\n        self.height = HEIGHT\n        self.width = WIDTH\n\n        self.image_info = collections.defaultdict(dict)\n        temp_df = self.df.groupby('id')['annotation'].agg(lambda x: list(x)).reset_index()\n        for index, row in temp_df.iterrows():\n            self.image_info[index] = {\n                'image_id': row['id'],\n                'image_path': os.path.join(self.image_dir, row['id'] + '.png'),\n                'annotations': row[\"annotation\"]\n            }\n\n    def get_box(self, a_mask):\n        ''' Get the bounding box of a given mask '''\n        pos = np.where(a_mask)\n        xmin = np.min(pos[1])\n        xmax = np.max(pos[1])\n        ymin = np.min(pos[0])\n        ymax = np.max(pos[0])\n        return [xmin, ymin, xmax, ymax]\n\n    def __getitem__(self, idx):\n        ''' Get the image and the target'''\n        img_path = self.image_info[idx][\"image_path\"]\n        img = Image.open(img_path).convert(\"RGB\")\n\n        info = self.image_info[idx]\n\n        n_objects = len(info['annotations'])\n        masks = np.zeros((len(info['annotations']), self.height, self.width), dtype=np.uint8)\n        boxes = []\n\n        for i, annotation in enumerate(info['annotations']):\n            a_mask = rle_decode(annotation, (HEIGHT, WIDTH))\n            a_mask = Image.fromarray(a_mask)\n            a_mask = np.array(a_mask) > 0\n            masks[i, :, :] = a_mask\n\n        ################################ AUGMENTATION PART ################################\n\n        if self.transforms is not None:\n            img, masks = self.transforms(img, masks)\n\n        new_masks = []\n        for i, mask in enumerate(masks):\n            if np.any((mask != 0)):\n                box = self.get_box(mask)\n                if box[0] != box[2] and box[1] != box[3]:\n                    new_masks.append(mask)\n                    boxes.append(box)\n        masks = np.array(new_masks)\n\n        ###################################################################################\n\n        labels = [1 for _ in range(n_objects)]\n\n        boxes = torch.as_tensor(boxes, dtype=torch.float32)\n        labels = torch.as_tensor(labels, dtype=torch.int64)\n        masks = torch.as_tensor(masks, dtype=torch.uint8)\n\n        image_id = torch.tensor([idx])\n        area = (boxes[:, 3] - boxes[:, 1]) * (boxes[:, 2] - boxes[:, 0])\n        iscrowd = torch.zeros((n_objects,), dtype=torch.int64)\n\n        target = {\n            'boxes': boxes,\n            'labels': labels,\n            'masks': masks,\n            'image_id': image_id,\n            'area': area,\n            'iscrowd': iscrowd\n        }\n\n        return img, target\n    \n    def __len__(self):\n        return len(self.image_info)","metadata":{"papermill":{"duration":0.034091,"end_time":"2021-11-11T08:27:18.999226","exception":false,"start_time":"2021-11-11T08:27:18.965135","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2021-11-11T22:19:40.143079Z","iopub.execute_input":"2021-11-11T22:19:40.143527Z","iopub.status.idle":"2021-11-11T22:19:40.163871Z","shell.execute_reply.started":"2021-11-11T22:19:40.143493Z","shell.execute_reply":"2021-11-11T22:19:40.163042Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"ds_train = CellDataset(TRAIN_PATH, pd.read_csv(TRAIN_CSV), transforms=get_transform(train=True))","metadata":{"papermill":{"duration":0.690529,"end_time":"2021-11-11T08:27:19.702468","exception":false,"start_time":"2021-11-11T08:27:19.011939","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2021-11-11T22:19:40.263856Z","iopub.execute_input":"2021-11-11T22:19:40.264275Z","iopub.status.idle":"2021-11-11T22:19:40.674687Z","shell.execute_reply.started":"2021-11-11T22:19:40.264244Z","shell.execute_reply":"2021-11-11T22:19:40.673755Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Results**","metadata":{"papermill":{"duration":0.014263,"end_time":"2021-11-11T08:27:20.188940","exception":false,"start_time":"2021-11-11T08:27:20.174677","status":"completed"},"tags":[]}},{"cell_type":"code","source":"a, b = ds_train[0]\nmasks = np.array(b[\"masks\"])\nmask = masks[0, :, :]\nfor i in range(len(masks)):\n    mask += masks[i, :, :]\nimage = a[0, :, :]\n\nprint(a.max(), a.min())\nvisualize(\n    image=image,\n    mask=mask,\n    mask2=masks[2, :, :],\n)\n\nprint(mask.max())\nprint(mask.shape)","metadata":{"papermill":{"duration":0.420717,"end_time":"2021-11-11T08:27:20.159244","exception":false,"start_time":"2021-11-11T08:27:19.738527","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2021-11-11T22:19:40.863670Z","iopub.execute_input":"2021-11-11T22:19:40.864200Z","iopub.status.idle":"2021-11-11T22:19:43.481186Z","shell.execute_reply.started":"2021-11-11T22:19:40.864159Z","shell.execute_reply":"2021-11-11T22:19:43.480314Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"a, b = ds_train[20]\nmasks = np.array(b[\"masks\"])\nmask = masks[0, :, :]\nfor i in range(len(masks)):\n    mask += masks[i, :, :]\nimage = a[0, :, :]\n\nprint(a.max(), a.min())\nvisualize(\n    image=image,\n    mask=mask,\n    mask2=masks[2, :, :],\n)\n\nprint(mask.max())\nprint(mask.shape)","metadata":{"execution":{"iopub.status.busy":"2021-11-11T22:19:43.482604Z","iopub.execute_input":"2021-11-11T22:19:43.482907Z","iopub.status.idle":"2021-11-11T22:19:43.981591Z","shell.execute_reply.started":"2021-11-11T22:19:43.482876Z","shell.execute_reply":"2021-11-11T22:19:43.980964Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"a, b = ds_train[20]\nmasks = np.array(b[\"masks\"])\nmask = masks[0, :, :]\nfor i in range(len(masks)):\n    mask += masks[i, :, :]\nimage = a[0, :, :]\n\nprint(a.max(), a.min())\nvisualize(\n    image=image,\n    mask=mask,\n    mask2=masks[2, :, :],\n)\n\nprint(mask.max())\nprint(mask.shape)","metadata":{"execution":{"iopub.status.busy":"2021-11-11T22:20:28.728758Z","iopub.execute_input":"2021-11-11T22:20:28.729304Z","iopub.status.idle":"2021-11-11T22:20:29.582670Z","shell.execute_reply.started":"2021-11-11T22:20:28.729267Z","shell.execute_reply":"2021-11-11T22:20:29.581883Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"a, b = ds_train[20]\nmasks = np.array(b[\"masks\"])\nmask = masks[0, :, :]\nfor i in range(len(masks)):\n    mask += masks[i, :, :]\nimage = a[0, :, :]\n\nprint(a.max(), a.min())\nvisualize(\n    image=image,\n    mask=mask,\n    mask2=masks[2, :, :],\n)\n\nprint(mask.max())\nprint(mask.shape)","metadata":{"execution":{"iopub.status.busy":"2021-11-11T22:20:30.451670Z","iopub.execute_input":"2021-11-11T22:20:30.452433Z","iopub.status.idle":"2021-11-11T22:20:30.994643Z","shell.execute_reply.started":"2021-11-11T22:20:30.452389Z","shell.execute_reply":"2021-11-11T22:20:30.993867Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Enjoy! :)**","metadata":{}},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}