{"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":"code","source":"!pip install ../input/detectron-05/whls/pycocotools-2.0.2/dist/pycocotools-2.0.2.tar --no-index --find-links ../input/detectron-05/whls \n!pip install ../input/detectron-05/whls/fvcore-0.1.5.post20211019/fvcore-0.1.5.post20211019 --no-index --find-links ../input/detectron-05/whls \n!pip install ../input/detectron-05/whls/antlr4-python3-runtime-4.8/antlr4-python3-runtime-4.8 --no-index --find-links ../input/detectron-05/whls \n!pip install ../input/detectron-05/whls/detectron2-0.5/detectron2 --no-index --find-links ../input/detectron-05/whls ","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"papermill":{"duration":219.954986,"end_time":"2021-11-04T11:14:13.985941","exception":false,"start_time":"2021-11-04T11:10:34.030955","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2021-11-04T23:00:54.568064Z","iopub.execute_input":"2021-11-04T23:00:54.568621Z","iopub.status.idle":"2021-11-04T23:04:17.42363Z","shell.execute_reply.started":"2021-11-04T23:00:54.56853Z","shell.execute_reply":"2021-11-04T23:04:17.422432Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import detectron2\nfrom detectron2 import model_zoo\nfrom detectron2.engine import DefaultPredictor\nfrom detectron2.config import get_cfg\nfrom fastcore.all import *\n\nimport torch\nfrom PIL import Image\nimport cv2\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport os","metadata":{"papermill":{"duration":1.319482,"end_time":"2021-11-04T11:14:15.338677","exception":false,"start_time":"2021-11-04T11:14:14.019195","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2021-11-04T23:04:17.425969Z","iopub.execute_input":"2021-11-04T23:04:17.426245Z","iopub.status.idle":"2021-11-04T23:04:18.6294Z","shell.execute_reply.started":"2021-11-04T23:04:17.426209Z","shell.execute_reply":"2021-11-04T23:04:18.628674Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class CFG:\n    wfold = 0\n    data_folder = '../input/sartorius-cell-instance-segmentation/'\n    anno_folder = '../input/sartorius-annotations/'\n    model_folder = '../input/sartorius-dataset/'\n    model_arch = 'mask_rcnn_R_50_FPN_3x.yaml'\n    nof_iters = 10000\n    THRESHOLDS = [.15, .35, .55]\n    MIN_PIXELS = [75, 150, 75]","metadata":{"papermill":{"duration":0.038138,"end_time":"2021-11-04T11:14:15.407877","exception":false,"start_time":"2021-11-04T11:14:15.369739","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2021-11-04T23:04:18.671334Z","iopub.execute_input":"2021-11-04T23:04:18.671975Z","iopub.status.idle":"2021-11-04T23:04:18.677083Z","shell.execute_reply.started":"2021-11-04T23:04:18.671938Z","shell.execute_reply":"2021-11-04T23:04:18.676352Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Functions","metadata":{"papermill":{"duration":0.031388,"end_time":"2021-11-04T11:14:15.470944","exception":false,"start_time":"2021-11-04T11:14:15.439556","status":"completed"},"tags":[]}},{"cell_type":"code","source":"# From https://www.kaggle.com/stainsby/fast-tested-rle\ndef rle_decode(mask_rle, shape=(520, 704)):\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    '''\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)  # Needed to align to RLE direction\n\ndef 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)\n\ndef get_masks(fn, predictor):\n    im = cv2.imread(str(fn))\n    pred = predictor(im)\n    pred_class = torch.mode(pred['instances'].pred_classes)[0]\n    take = pred['instances'].scores >= CFG.THRESHOLDS[pred_class]\n    pred_masks = pred['instances'].pred_masks[take]\n    pred_masks = pred_masks.cpu().numpy()\n    res = []\n#    mat = []\n    used = np.zeros(im.shape[:2], dtype=int) \n    for mask in pred_masks:\n        mask = mask * (1-used)\n        if mask.sum() >= CFG.MIN_PIXELS[pred_class]: \n            used += mask\n#            mat.append(mask)\n            res.append(rle_encode(mask))\n    return res\n\n# def get_masks(fn, predictor):\n#     im = cv2.imread(str(fn))\n#     outputs = predictor(im)\n#     pred_masks = outputs['instances'].pred_masks.cpu().numpy()\n#     res = []\n#     used = np.zeros(im.shape[:2], dtype=int) # to remove overlaps\n#     for mask in pred_masks:\n#         mask = mask * (1-used)\n#         used += mask\n#         res.append(rle_encode(mask))\n#     return res\n","metadata":{"papermill":{"duration":0.046808,"end_time":"2021-11-04T11:14:15.549188","exception":false,"start_time":"2021-11-04T11:14:15.50238","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2021-11-04T23:12:17.950602Z","iopub.execute_input":"2021-11-04T23:12:17.950886Z","iopub.status.idle":"2021-11-04T23:12:17.961693Z","shell.execute_reply.started":"2021-11-04T23:12:17.950855Z","shell.execute_reply":"2021-11-04T23:12:17.960959Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Taken from\ndef compute_iou(labels, y_pred):\n    \"\"\"\n    Computes the IoU for instance labels and predictions.\n\n    Args:\n        labels (np array): Labels.\n        y_pred (np array): predictions\n\n    Returns:\n        np array: IoU matrix, of size true_objects x pred_objects.\n    \"\"\"\n\n    true_objects = len(np.unique(labels))\n    pred_objects = len(np.unique(y_pred))\n\n    # Compute intersection between all objects\n    intersection = np.histogram2d(\n        labels.flatten(), y_pred.flatten(), bins=(true_objects, pred_objects)\n    )[0]\n\n    # Compute areas (needed for finding the union between all objects)\n    area_true = np.histogram(labels, bins=true_objects)[0]\n    area_pred = np.histogram(y_pred, bins=pred_objects)[0]\n    area_true = np.expand_dims(area_true, -1)\n    area_pred = np.expand_dims(area_pred, 0)\n\n    # Compute union\n    union = area_true + area_pred - intersection\n    iou = intersection / union\n    \n    return iou[1:, 1:]  # exclude background\n\ndef precision_at(threshold, iou):\n    \"\"\"\n    Computes the precision at a given threshold.\n\n    Args:\n        threshold (float): Threshold.\n        iou (np array): IoU matrix.\n\n    Returns:\n        int: Number of true positives,\n        int: Number of false positives,\n        int: Number of false negatives.\n    \"\"\"\n    matches = iou > threshold\n    true_positives = np.sum(matches, axis=1) == 1  # Correct objects\n    false_positives = np.sum(matches, axis=0) == 0  # Missed objects\n    false_negatives = np.sum(matches, axis=1) == 0  # Extra objects\n    tp, fp, fn = (\n        np.sum(true_positives),\n        np.sum(false_positives),\n        np.sum(false_negatives),\n    )\n    return tp, fp, fn\n\n\ndef iou_map(truths, preds, verbose=0):\n    \"\"\"\n    Computes the metric for the competition.\n    Masks contain the segmented pixels where each object has one value associated,\n    and 0 is the background.\n\n    Args:\n        truths (list of masks): Ground truths.\n        preds (list of masks): Predictions.\n        verbose (int, optional): Whether to print infos. Defaults to 0.\n\n    Returns:\n        float: mAP.\n    \"\"\"\n    ious = [compute_iou(truth, pred) for truth, pred in zip(truths, preds)]\n\n    if verbose:\n        print(\"Thresh\\tTP\\tFP\\tFN\\tPrec.\")\n\n    prec = []\n    for t in np.arange(0.5, 1.0, 0.05):\n        tps, fps, fns = 0, 0, 0\n        for iou in ious:\n            tp, fp, fn = precision_at(t, iou)\n            tps += tp\n            fps += fp\n            fns += fn\n\n        p = tps / (tps + fps + fns)\n        prec.append(p)\n\n        if verbose:\n            print(\"{:1.3f}\\t{}\\t{}\\t{}\\t{:1.3f}\".format(t, tps, fps, fns, p))\n\n    if verbose:\n        print(\"AP\\t-\\t-\\t-\\t{:1.3f}\".format(np.mean(prec)))\n\n    return np.mean(prec)","metadata":{"papermill":{"duration":0.045981,"end_time":"2021-11-04T11:14:15.62565","exception":false,"start_time":"2021-11-04T11:14:15.579669","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2021-11-04T23:04:18.700314Z","iopub.execute_input":"2021-11-04T23:04:18.700991Z","iopub.status.idle":"2021-11-04T23:04:18.720098Z","shell.execute_reply.started":"2021-11-04T23:04:18.700956Z","shell.execute_reply":"2021-11-04T23:04:18.719463Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Data\n\nLoad the weights from a previously fitted model - R50 architecture, 10k iterations,  MaP IoU=0.2554","metadata":{"papermill":{"duration":0.031149,"end_time":"2021-11-04T11:14:15.688979","exception":false,"start_time":"2021-11-04T11:14:15.65783","status":"completed"},"tags":[]}},{"cell_type":"code","source":"cfg = get_cfg()\ncfg.merge_from_file(model_zoo.get_config_file('COCO-InstanceSegmentation/' + CFG.model_arch))\ncfg.INPUT.MASK_FORMAT='bitmask'\ncfg.MODEL.ROI_HEADS.NUM_CLASSES = 3 \ncfg.MODEL.WEIGHTS = os.path.join(CFG.model_folder, 'model_f'+str(CFG.wfold)+'.pth')  \ncfg.TEST.DETECTIONS_PER_IMAGE = 1000\npredictor = DefaultPredictor(cfg)\n","metadata":{"papermill":{"duration":7.802493,"end_time":"2021-11-04T11:14:23.52241","exception":false,"start_time":"2021-11-04T11:14:15.719917","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2021-11-04T23:04:18.721795Z","iopub.execute_input":"2021-11-04T23:04:18.722444Z","iopub.status.idle":"2021-11-04T23:04:27.598564Z","shell.execute_reply.started":"2021-11-04T23:04:18.72241Z","shell.execute_reply":"2021-11-04T23:04:27.597593Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Get RLE for validation set, ground truth for validation set and RLE for the test set","metadata":{"papermill":{"duration":0.03258,"end_time":"2021-11-04T11:14:23.589035","exception":false,"start_time":"2021-11-04T11:14:23.556455","status":"completed"},"tags":[]}},{"cell_type":"code","source":"# RLE for ground truth\nxdat = pd.read_csv('../input/sartorius-annotations/gt_fold.csv')\nxdat = xdat.loc[xdat.fold == CFG.wfold][['id', 'annotation']].copy()\n\nrle_gt = xdat['annotation'].copy()\nids_gt = xdat['id'].copy()\n\nprint(len(rle_gt), len(ids_gt))\nvalid_names = ids_gt.unique()\n\n\n# RLE for validation set\nids_valid, rle_valid = [], []\n\nfor fn in valid_names:    \n    rles = get_masks(CFG.data_folder + 'train/' + fn + '.png', predictor)\n    for enc in rles:\n        ids_valid.append(fn)\n        rle_valid.append(enc)\n        \nprint(len(rle_valid), len(ids_valid))\n\n\n# RLE for test set\nids_test, rle_test = [] , []\ntest_names = [f[:-4] for f in os.listdir(CFG.data_folder + 'test')]\n\nfor fn in test_names:\n    rles = get_masks(CFG.data_folder + 'test/' + fn + '.png', predictor)\n    for enc in rles:\n        ids_test.append(fn)\n        rle_test.append(enc)\n\nprint(len(rle_test), len(ids_test))\n  ","metadata":{"papermill":{"duration":47.291367,"end_time":"2021-11-04T11:15:10.912619","exception":false,"start_time":"2021-11-04T11:14:23.621252","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2021-11-04T23:12:26.863407Z","iopub.execute_input":"2021-11-04T23:12:26.863693Z","iopub.status.idle":"2021-11-04T23:13:16.183082Z","shell.execute_reply.started":"2021-11-04T23:12:26.863659Z","shell.execute_reply":"2021-11-04T23:13:16.182275Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Evaluation ","metadata":{"papermill":{"duration":0.035181,"end_time":"2021-11-04T11:15:10.984665","exception":false,"start_time":"2021-11-04T11:15:10.949484","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"Convert RLE for gt / validation into masks","metadata":{"papermill":{"duration":0.03498,"end_time":"2021-11-04T11:15:11.055281","exception":false,"start_time":"2021-11-04T11:15:11.020301","status":"completed"},"tags":[]}},{"cell_type":"code","source":"# translate to masks\nmasks_valid, masks_gt = [], []\n\nfor rl in rle_valid: \n    m = rle_decode(rl)\n    masks_valid.append(m)\n    \nfor rl in rle_gt: \n    m = rle_decode(rl)\n    masks_gt.append(m)\n    ","metadata":{"papermill":{"duration":3.899098,"end_time":"2021-11-04T11:15:14.98941","exception":false,"start_time":"2021-11-04T11:15:11.090312","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2021-11-04T23:13:33.929218Z","iopub.execute_input":"2021-11-04T23:13:33.929472Z","iopub.status.idle":"2021-11-04T23:13:42.515587Z","shell.execute_reply.started":"2021-11-04T23:13:33.929444Z","shell.execute_reply":"2021-11-04T23:13:42.514785Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Combine the masks per file","metadata":{}},{"cell_type":"code","source":"# aggregate \nmasks_valid_agg = pd.DataFrame()\nmasks_valid_agg['id'] = ids_valid\nmasks_valid_agg['masks'] = masks_valid\nmasks_valid_agg = masks_valid_agg.groupby('id').sum().reset_index()\n\nmasks_gt_agg = pd.DataFrame()\nmasks_gt_agg['id'] = ids_gt\nmasks_gt_agg['masks'] = masks_gt\nmasks_gt_agg = masks_gt_agg.groupby('id').sum().reset_index()\n\n# plt.imshow(masks_valid_agg.masks[0])","metadata":{"papermill":{"duration":1.906819,"end_time":"2021-11-04T11:15:16.931606","exception":false,"start_time":"2021-11-04T11:15:15.024787","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2021-11-04T23:13:42.519002Z","iopub.execute_input":"2021-11-04T23:13:42.519299Z","iopub.status.idle":"2021-11-04T23:13:44.558224Z","shell.execute_reply.started":"2021-11-04T23:13:42.519259Z","shell.execute_reply":"2021-11-04T23:13:44.557496Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Calculate the metric:","metadata":{}},{"cell_type":"code","source":"# muh_iou = compute_iou(masks_gt_agg['masks'][0], masks_valid_agg['masks'][0])\n# precision_at(0.5, muh_iou)\n#iou_map(masks_gt_agg['masks'] , masks_gt_agg['masks'], verbose=1)  # This should score 1","metadata":{"papermill":{"duration":0.135349,"end_time":"2021-11-04T11:15:17.100927","exception":false,"start_time":"2021-11-04T11:15:16.965578","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2021-11-04T23:13:54.114579Z","iopub.execute_input":"2021-11-04T23:13:54.114856Z","iopub.status.idle":"2021-11-04T23:13:54.167078Z","shell.execute_reply.started":"2021-11-04T23:13:54.114826Z","shell.execute_reply":"2021-11-04T23:13:54.166235Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"iou_map(masks_gt_agg['masks'] , masks_valid_agg['masks'], verbose=1) ","metadata":{"papermill":{"duration":3.733163,"end_time":"2021-11-04T11:15:21.024442","exception":false,"start_time":"2021-11-04T11:15:17.291279","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2021-11-04T23:13:57.909406Z","iopub.execute_input":"2021-11-04T23:13:57.909676Z","iopub.status.idle":"2021-11-04T23:14:01.719279Z","shell.execute_reply.started":"2021-11-04T23:13:57.909647Z","shell.execute_reply":"2021-11-04T23:14:01.718511Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Submission","metadata":{"papermill":{"duration":0.036853,"end_time":"2021-11-04T11:15:21.09825","exception":false,"start_time":"2021-11-04T11:15:21.061397","status":"completed"},"tags":[]}},{"cell_type":"code","source":"pd.DataFrame({'id': ids_test, 'predicted': rle_test}).to_csv('submission.csv', index=False)","metadata":{"papermill":{"duration":0.11161,"end_time":"2021-11-04T11:15:21.246023","exception":false,"start_time":"2021-11-04T11:15:21.134413","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]}]}