{"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":"# **[HuBMAP 2023] MMDetection 3.1 Inference**","metadata":{}},{"cell_type":"markdown","source":"#### [HuBMAP 2023] K-fold CV COCO Dataset Generator [here](https://www.kaggle.com/code/ammarnassanalhajali/hubmap-2023-k-fold-cv-coco-dataset-generator)\n#### [HuBMAP 2023] MMDetectron 3.1 Wheel [here](https://www.kaggle.com/code/ammarnassanalhajali/hubmap-2023-mmdetectron-3-1-wheel)\n#### [HuBMAP 2023] MMDetection 3.1 Training [here](https://www.kaggle.com/code/ammarnassanalhajali/hubmap-2023-mmdetection-3-1-training)\n#### [HuBMAP 2023] Detectron2-Training [here](https://www.kaggle.com/code/ammarnassanalhajali/hubmap-2023-detectron2-training)\n#### [HuBMAP 2023] Detectron2-Inference [here](https://www.kaggle.com/code/ammarnassanalhajali/hubmap-2023-detectron2-inference)\n#### [HuBMAP 2023] Torch Mask R-CNN [here](https://www.kaggle.com/code/ammarnassanalhajali/hubmap-2023-torch-mask-r-cnn)\n\n","metadata":{}},{"cell_type":"markdown","source":"### Install MMdetectron 3.1 offline","metadata":{}},{"cell_type":"code","source":"!pip install --no-index --no-deps /kaggle/input/mmdetectron-31-wheel/pycocotools-2.0.6-cp310-cp310-linux_x86_64.whl\n!pip install --no-index --no-deps /kaggle/input/mmdetectron-31-wheel/torch-1.12.1+cu116-cp310-cp310-linux_x86_64.whl\n!pip install --no-index --no-deps /kaggle/input/mmdetectron-31-wheel/torchvision-0.13.1+cu116-cp310-cp310-linux_x86_64.whl\n!pip install --no-index --no-deps /kaggle/input/mmdetectron-31-wheel/mmcv-2.0.1-cp310-cp310-manylinux1_x86_64.whl \n!pip install --no-index --no-deps /kaggle/input/mmdetectron-31-wheel/openmim-0.3.9-py2.py3-none-any.whl\n!pip install --no-index --no-deps /kaggle/input/mmdetectron-31-wheel/mmengine-0.7.4-py3-none-any.whl\n!pip install --no-index --no-deps /kaggle/input/mmdetectron-31-wheel/addict-2.4.0-py3-none-any.whl\n!pip install --no-index --no-deps /kaggle/input/mmdetectron-31-wheel/mmdet-3.1.0-py3-none-any.whl\n!pip install --no-index --no-deps /kaggle/input/mmdetectron-31-wheel/terminaltables-3.1.10-py2.py3-none-any.whl","metadata":{"execution":{"iopub.status.busy":"2023-07-05T17:39:45.550473Z","iopub.execute_input":"2023-07-05T17:39:45.550799Z","iopub.status.idle":"2023-07-05T17:41:51.229990Z","shell.execute_reply.started":"2023-07-05T17:39:45.550772Z","shell.execute_reply":"2023-07-05T17:41:51.228807Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Importing Libraries","metadata":{}},{"cell_type":"code","source":"from itertools import groupby\nfrom pycocotools import mask as mutils\nfrom pycocotools.coco import COCO\nimport numpy as np\nfrom tqdm.notebook import tqdm\nimport pandas as pd\nimport os\nimport cv2,glob\nimport matplotlib.pyplot as plt\nimport wandb\nfrom PIL import Image\nimport gc\nsample = None\nimport mmcv\nfrom glob import glob\nimport matplotlib.pyplot as plt\nfrom mmdet.apis import init_detector, inference_detector","metadata":{"execution":{"iopub.status.busy":"2023-07-05T17:41:51.233828Z","iopub.execute_input":"2023-07-05T17:41:51.234165Z","iopub.status.idle":"2023-07-05T17:41:58.659930Z","shell.execute_reply.started":"2023-07-05T17:41:51.234133Z","shell.execute_reply":"2023-07-05T17:41:58.658968Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch, torchvision\nprint(torch.__version__, torch.cuda.is_available())\n\nimport mmdet as mmdet\nprint(mmdet.__version__)\n\nfrom mmcv.ops import get_compiling_cuda_version, get_compiler_version\nprint(get_compiling_cuda_version())\nprint(get_compiler_version())\ndevice = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')","metadata":{"execution":{"iopub.status.busy":"2023-07-05T17:41:58.661770Z","iopub.execute_input":"2023-07-05T17:41:58.662139Z","iopub.status.idle":"2023-07-05T17:41:58.787126Z","shell.execute_reply.started":"2023-07-05T17:41:58.662101Z","shell.execute_reply":"2023-07-05T17:41:58.786058Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Function","metadata":{}},{"cell_type":"code","source":"import base64\nimport numpy as np\nfrom pycocotools import _mask as coco_mask\nimport typing as t\nimport zlib\n\ndef encode_binary_mask(mask: np.ndarray) -> t.Text:\n  \"\"\"Converts a binary mask into OID challenge encoding ascii text.\"\"\"\n\n  # check input mask --\n  if mask.dtype != np.bool:\n    raise ValueError(\n        \"encode_binary_mask expects a binary mask, received dtype == %s\" %\n        mask.dtype)\n\n  mask = np.squeeze(mask)\n  if len(mask.shape) != 2:\n    raise ValueError(\n        \"encode_binary_mask expects a 2d mask, received shape == %s\" %\n        mask.shape)\n\n  # convert input mask to expected COCO API input --\n  mask_to_encode = mask.reshape(mask.shape[0], mask.shape[1], 1)\n  mask_to_encode = mask_to_encode.astype(np.uint8)\n  mask_to_encode = np.asfortranarray(mask_to_encode)\n\n  # RLE encode mask --\n  encoded_mask = coco_mask.encode(mask_to_encode)[0][\"counts\"]\n\n  # compress and base64 encoding --\n  binary_str = zlib.compress(encoded_mask, zlib.Z_BEST_COMPRESSION)\n  base64_str = base64.b64encode(binary_str)\n  return base64_str\n\ndef remove_overlapping_pixels(mask, other_masks):\n    for other_mask in other_masks:\n        if np.sum(np.logical_and(mask, other_mask)) > 0:\n            mask[np.logical_and(mask, other_mask)] = 0\n    return mask\n\ndef combine_masks(masks, mask_threshold):\n    \"\"\"\n    combine masks into one image\n    \"\"\"\n    maskimg = np.zeros((HEIGHT, WIDTH))\n    # print(len(masks.shape), masks.shape)\n    for m, mask in enumerate(masks,1):\n        maskimg[mask>mask_threshold] = m\n    return maskimg\n\n\ndef get_filtered_masks(pred):\n    \"\"\"\n    filter masks using MIN_SCORE for mask and MAX_THRESHOLD for pixels\n    \"\"\"\n    use_masks = []\n    use_labels = []\n    for i, mask in enumerate(pred[\"masks\"]):\n        # Filter-out low-scoring results. Not tried yet.\n        scr = pred[\"scores\"][i].cpu().item()\n        label = pred[\"labels\"][i].cpu().item()\n        if scr > min_score_dict[label]:\n            mask = mask.cpu().numpy().squeeze()\n            # Keep only highly likely pixels\n            binary_mask = mask > mask_threshold_dict[label]\n            binary_mask = remove_overlapping_pixels(binary_mask, use_masks)\n            use_masks.append(binary_mask)\n            use_labels.append(label)\n\n    return use_masks,use_labels\n","metadata":{"execution":{"iopub.status.busy":"2023-07-05T17:41:58.789905Z","iopub.execute_input":"2023-07-05T17:41:58.790258Z","iopub.status.idle":"2023-07-05T17:41:58.803919Z","shell.execute_reply.started":"2023-07-05T17:41:58.790223Z","shell.execute_reply":"2023-07-05T17:41:58.802691Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Test Dataset and DataLoader","metadata":{}},{"cell_type":"code","source":"import os\nimport numpy as np\nimport torch\nfrom PIL import Image\n\n\nclass HuBMAPDataset(torch.utils.data.Dataset):\n    def __init__(self, imgs):\n        self.imgs = imgs\n        self.name_indices = [os.path.splitext(os.path.basename(i))[0] for i in imgs]\n    def __getitem__(self, idx):\n        # load images and masks\n        img_path = self.imgs[idx]\n        name = self.name_indices[idx]\n        array = tiff.imread(img_path)\n        img = Image.fromarray(array)\n        return img, name\n    def __len__(self):\n        return len(self.imgs)\n    \nall_imgs = glob('/kaggle/input/hubmap-hacking-the-human-vasculature/test/*.tif')\ndataset_test = HuBMAPDataset(all_imgs)\ntest_dl = torch.utils.data.DataLoader(dataset_test, batch_size=1, shuffle=False, num_workers=os.cpu_count(), pin_memory=True)","metadata":{"execution":{"iopub.status.busy":"2023-07-05T17:41:58.805120Z","iopub.execute_input":"2023-07-05T17:41:58.805996Z","iopub.status.idle":"2023-07-05T17:41:58.826033Z","shell.execute_reply.started":"2023-07-05T17:41:58.805962Z","shell.execute_reply":"2023-07-05T17:41:58.825078Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Model","metadata":{}},{"cell_type":"code","source":"from mmdet.apis import init_detector, inference_detector\nfrom mmengine.config import Config\nconfig_file = '/kaggle/input/hubmap-2023-detectron2-colab-models/1024/MMdet/custom_config_cascade-mask-rcnn_x101-64x4d_fpn_20e_coco_1024_1024.py'\ncheckpoint_file = '/kaggle/input/hubmap-2023-detectron2-colab-models/1024/MMdet/best_coco_segm_mAP_epoch_17.pth'\n\ncfg = Config.fromfile(config_file )\ncfg.test_dataloader.dataset.pipeline[1]['scale']=(1024, 1024)\nmodel = init_detector(cfg, checkpoint_file, device=device)\n\n# cell type specific thresholds\ncell_type_dict = {'blood_vessel': 1, 'glomerulus': 2, 'unsure': 3}\n\nmask_threshold_dict = {0: 0.2, 1: 0.80, 2:  0.80}\nmin_score_dict = {0: 0.25, 1: 0.80, 2: 0.80}","metadata":{"execution":{"iopub.status.busy":"2023-07-05T17:45:15.387251Z","iopub.execute_input":"2023-07-05T17:45:15.387611Z","iopub.status.idle":"2023-07-05T17:45:17.695631Z","shell.execute_reply.started":"2023-07-05T17:45:15.387573Z","shell.execute_reply":"2023-07-05T17:45:17.694667Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Predicting","metadata":{}},{"cell_type":"code","source":"from skimage.morphology import binary_dilation\nids = []\nheights = []\nwidths = []\nprediction_strings = []\n\nfor img in all_imgs:\n    img_array = mmcv.imread(img,channel_order='rgb')\n    [h, w, c] = img_array.shape \n    pred = inference_detector(model,img)\n    masks_use = []\n    labels_use = []\n    scores_use=[]\n    pred_string=\"\"\n    for i, mask in enumerate(pred.pred_instances[\"masks\"]):\n        # Filter-out low-scoring results.\n        score = pred.pred_instances[\"scores\"][i].cpu().item()\n        label = pred.pred_instances[\"labels\"][i].cpu().item()\n        if score > min_score_dict[label]:\n            mask = mask.cpu().numpy()\n            binary_mask = mask > mask_threshold_dict[label]\n            \n            #dilation\n            binary_mask = binary_mask.astype(np.uint8)\n            kernel = np.ones(shape=(5, 5), dtype=np.uint8)\n            binary_mask = cv2.dilate(binary_mask, kernel, iterations=1)\n            kernel = np.ones(shape=(3, 3), dtype=np.uint8)\n            binary_mask = cv2.erode(binary_mask, kernel, iterations=1)\n            binary_mask = binary_mask.astype(bool)  \n            #end dilation\n           # binary_mask = binary_dilation(binary_mask)\n            \n            masks_use.append(binary_mask)\n            labels_use.append(label)\n            scores_use.append(score)\n            encoded = encode_binary_mask(binary_mask)\n            if label != 0: continue\n            if i == 0:\n                pred_string += f\"{int(label)} {score} {encoded.decode('utf-8')}\"\n            else:\n                pred_string += f\" {int(label)} {score} {encoded.decode('utf-8')}\"      \n            #print(pred_classes[i])\n    ids.append(str(img).split('.')[0].split('/')[-1])\n    heights.append(h)\n    widths.append(w)\n    prediction_strings.append(pred_string)","metadata":{"execution":{"iopub.status.busy":"2023-07-05T17:45:17.697472Z","iopub.execute_input":"2023-07-05T17:45:17.697915Z","iopub.status.idle":"2023-07-05T17:45:18.147494Z","shell.execute_reply.started":"2023-07-05T17:45:17.697881Z","shell.execute_reply":"2023-07-05T17:45:18.146222Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\ncolors = [ 'Set1', 'Set3'] \nlegend = {0: 'blood_vessel',1: 'glomerulus'} \nfrom skimage import io\nimport matplotlib.patches as mpatches\nfig, axs = plt.subplots(1, 2, figsize=(10, 5))\nI = io.imread(str(all_imgs[0]))\naxs[0].imshow(I)\naxs[0].set_title('Image')\naxs[1].imshow(I)\n\nfor i, (mk,label,score) in enumerate(zip(masks_use,labels_use,scores_use)):\n    if score > min_score_dict[label]:\n        color = colors[label]\n        mask = np.ma.masked_where(mk == 0, mk)\n        axs[1].imshow(mask, cmap=color, alpha=0.8)\n        axs[1].set_title('Predicted Masks')\n        # Add score text on each segment\n        y, x = np.where(mk > 0)\n        text_x, text_y = np.min(x), np.min(y)\n        axs[1].text(text_x, text_y, f\"{score:.2f}\", color='white', fontsize=8)\n        handles = []\n        for cl in legend:\n            color = colors[cl]\n            handles.append(mpatches.Patch(color=plt.colormaps.get_cmap(color)(0)))\n        axs[1].legend(handles, legend.values(), bbox_to_anchor=(1.05, 1), loc='upper left')","metadata":{"execution":{"iopub.status.busy":"2023-07-05T17:45:18.149150Z","iopub.execute_input":"2023-07-05T17:45:18.149801Z","iopub.status.idle":"2023-07-05T17:45:19.829197Z","shell.execute_reply.started":"2023-07-05T17:45:18.149764Z","shell.execute_reply":"2023-07-05T17:45:19.828078Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### submission","metadata":{}},{"cell_type":"code","source":"submission = pd.DataFrame()\nsubmission['id'] = ids\nsubmission['height'] = heights\nsubmission['width'] = widths\nsubmission['prediction_string'] = prediction_strings\nsubmission = submission.set_index('id')\nsubmission.to_csv(\"submission.csv\")\nsubmission.head()","metadata":{"execution":{"iopub.status.busy":"2023-07-05T17:45:19.831385Z","iopub.execute_input":"2023-07-05T17:45:19.831813Z","iopub.status.idle":"2023-07-05T17:45:19.852784Z","shell.execute_reply.started":"2023-07-05T17:45:19.831777Z","shell.execute_reply":"2023-07-05T17:45:19.851043Z"},"trusted":true},"execution_count":null,"outputs":[]}]}