{"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":"# A Quick YOLOv7 Baseline [Inference Edition]\n\nThis is the inference notebook for this YOLOv7 [training notebook](https://www.kaggle.com/code/fnands/a-quick-yolov7-baseline).  \n\nThe inference code in the main repo [doesn't seem to actually export segmentation masks](https://github.com/WongKinYiu/yolov7/issues/1483), so I modified the inference loop.   \n","metadata":{}},{"cell_type":"code","source":"!cp -r /kaggle/input/pycocotools/ /kaggle/working/pycocotools\n!pip install /kaggle/working/pycocotools/pycocotools-2.0.6  --no-index --find-links=/kaggle/working/pycocotools/ ","metadata":{"execution":{"iopub.status.busy":"2023-06-15T06:34:21.511177Z","iopub.execute_input":"2023-06-15T06:34:21.511839Z","iopub.status.idle":"2023-06-15T06:34:59.327598Z","shell.execute_reply.started":"2023-06-15T06:34:21.511801Z","shell.execute_reply":"2023-06-15T06:34:59.326396Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import base64\nimport numpy as np\nfrom pycocotools import _mask as coco_mask\nfrom typing import Text, Dict, Tuple\nimport zlib","metadata":{"execution":{"iopub.status.busy":"2023-06-15T06:34:59.331111Z","iopub.execute_input":"2023-06-15T06:34:59.331997Z","iopub.status.idle":"2023-06-15T06:34:59.348422Z","shell.execute_reply.started":"2023-06-15T06:34:59.331964Z","shell.execute_reply":"2023-06-15T06:34:59.346793Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install /kaggle/input/yolov7-weights-and-wheels/yolo_wheel/yolov7-0.0.1-py37.py38.py39-none-any.whl --no-index --find-links=/kaggle/input/yolov7-weights-and-wheels/yolo_wheel","metadata":{"execution":{"iopub.status.busy":"2023-06-15T06:34:59.350022Z","iopub.execute_input":"2023-06-15T06:34:59.351205Z","iopub.status.idle":"2023-06-15T06:35:35.189443Z","shell.execute_reply.started":"2023-06-15T06:34:59.35117Z","shell.execute_reply":"2023-06-15T06:35:35.188252Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!cp -r /kaggle/input/yolov7-weights-and-wheels/yolov7 yolo","metadata":{"execution":{"iopub.status.busy":"2023-06-15T06:35:35.192775Z","iopub.execute_input":"2023-06-15T06:35:35.193618Z","iopub.status.idle":"2023-06-15T06:35:39.074565Z","shell.execute_reply.started":"2023-06-15T06:35:35.193567Z","shell.execute_reply":"2023-06-15T06:35:39.073275Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from yolo.seg.segment import predict","metadata":{"execution":{"iopub.status.busy":"2023-06-15T06:35:39.078402Z","iopub.execute_input":"2023-06-15T06:35:39.078865Z","iopub.status.idle":"2023-06-15T06:35:43.738698Z","shell.execute_reply.started":"2023-06-15T06:35:39.078818Z","shell.execute_reply":"2023-06-15T06:35:43.737349Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Create a yaml file as expected by YOLOv7 (and others)\nyaml_text = \"\"\"\n# class names\nnames: \n  0: blood_vessel\n  1: glomerulus\n  2: unsure\n\"\"\"\nwith open('/kaggle/working/hubmap-coco.yaml', 'w') as text_file:\n    text_file.write(yaml_text)","metadata":{"execution":{"iopub.status.busy":"2023-06-15T06:35:43.744523Z","iopub.execute_input":"2023-06-15T06:35:43.747998Z","iopub.status.idle":"2023-06-15T06:35:43.756186Z","shell.execute_reply.started":"2023-06-15T06:35:43.747956Z","shell.execute_reply":"2023-06-15T06:35:43.754877Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import argparse\nimport os\nimport platform\nimport sys\nfrom pathlib import Path\nimport json\n\nimport torch\nimport torch.backends.cudnn as cudnn\n\n\n\nfrom models.common import DetectMultiBackend\nfrom utils.dataloaders import IMG_FORMATS, VID_FORMATS, LoadImages, LoadStreams\nfrom utils.general import (LOGGER, Profile, check_file, check_img_size, check_imshow, check_requirements, colorstr, cv2,\n                           increment_path, non_max_suppression, print_args, scale_coords, strip_optimizer, xyxy2xywh)\nfrom utils.plots import Annotator, colors, save_one_box\nfrom utils.segment.general import process_mask, scale_masks\nfrom utils.segment.plots import plot_masks\nfrom utils.torch_utils import select_device, smart_inference_mode","metadata":{"execution":{"iopub.status.busy":"2023-06-15T06:35:43.771223Z","iopub.execute_input":"2023-06-15T06:35:43.775063Z","iopub.status.idle":"2023-06-15T06:35:44.561082Z","shell.execute_reply.started":"2023-06-15T06:35:43.775021Z","shell.execute_reply":"2023-06-15T06:35:44.559887Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def encode_binary_mask(mask: np.ndarray) -> 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","metadata":{"execution":{"iopub.status.busy":"2023-06-15T06:35:44.562855Z","iopub.execute_input":"2023-06-15T06:35:44.563249Z","iopub.status.idle":"2023-06-15T06:35:44.592613Z","shell.execute_reply.started":"2023-06-15T06:35:44.563214Z","shell.execute_reply":"2023-06-15T06:35:44.591181Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Read .jsonl file and convert it to a list of dicts\n# The dicts contain IDs, class names and segmentation masks\n# from https://www.kaggle.com/code/leonidkulyk/eda-hubmap-hhv-interactive-annotations\nwith open('/kaggle/input/hubmap-hacking-the-human-vasculature/polygons.jsonl', 'r') as json_file:\n    json_list = list(json_file)\n    \ntiles_dicts = []\nfor json_str in json_list:\n    tiles_dicts.append(json.loads(json_str))","metadata":{"execution":{"iopub.status.busy":"2023-06-15T06:35:44.594656Z","iopub.execute_input":"2023-06-15T06:35:44.595068Z","iopub.status.idle":"2023-06-15T06:35:50.092134Z","shell.execute_reply.started":"2023-06-15T06:35:44.595026Z","shell.execute_reply":"2023-06-15T06:35:50.091147Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dict_of_tiles = {}\nfor tile in tiles_dicts:\n    dict_of_tiles[tile['id']] = tile['annotations']","metadata":{"execution":{"iopub.status.busy":"2023-06-15T06:35:50.095727Z","iopub.execute_input":"2023-06-15T06:35:50.096115Z","iopub.status.idle":"2023-06-15T06:35:50.102578Z","shell.execute_reply.started":"2023-06-15T06:35:50.096079Z","shell.execute_reply":"2023-06-15T06:35:50.10147Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_glomerulus_mask(annotations: Dict, mask_shape: Tuple = (512, 512)) -> np.ndarray:\n    \"\"\" Converts glomerulus labels into boolean mask \"\"\"\n    mask = np.ones(shape=mask_shape, dtype=np.uint8)\n    \n    for annotation in annotations: \n        if annotation['type'] == 'glomerulus':            \n            coords = np.array(annotation['coordinates'])\n            cv2.fillPoly(mask, pts=coords, color=0)\n        \n\n    return mask.astype(bool)\n    \n","metadata":{"execution":{"iopub.status.busy":"2023-06-15T06:35:50.104019Z","iopub.execute_input":"2023-06-15T06:35:50.10462Z","iopub.status.idle":"2023-06-15T06:35:50.117975Z","shell.execute_reply.started":"2023-06-15T06:35:50.104587Z","shell.execute_reply":"2023-06-15T06:35:50.116705Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def segment(\n        weights,\n        source,\n        data,\n        project,\n        imgsz=(640, 640),  # inference size (height, width)\n        conf_thres=0.25,  # confidence threshold\n        iou_thres=0.45,  # NMS IOU threshold\n        max_det=1000,  # maximum detections per image\n        device='',  # cuda device, i.e. 0 or 0,1,2,3 or cpu\n        view_img=False,  # show results\n        save_txt=False,  # save results to *.txt\n        save_conf=False,  # save confidences in --save-txt labels\n        save_crop=False,  # save cropped prediction boxes\n        nosave=False,  # do not save images/videos\n        classes=None,  # filter by class: --class 0, or --class 0 2 3\n        agnostic_nms=False,  # class-agnostic NMS\n        augment=False,  # augmented inference\n        visualize=False,  # visualize features\n        update=False,  # update all models\n        name='exp',  # save results to project/name\n        exist_ok=False,  # existing project/name ok, do not increment\n        line_thickness=3,  # bounding box thickness (pixels)\n        hide_labels=False,  # hide labels\n        hide_conf=False,  # hide confidences\n        half=False,  # use FP16 half-precision inference\n        dnn=False,  # use OpenCV DNN for ONNX inference\n    ):\n    with open('/kaggle/working/submission.csv', 'w') as sub_file:\n        # Write header\n        sub_file.write('id,height,width,prediction_string\\n')\n        \n\n        device = select_device(device)\n        model = DetectMultiBackend(weights, device=device, dnn=dnn, data=data, fp16=half)\n        stride, names, pt = model.stride, model.names, model.pt\n        imgsz = check_img_size(imgsz, s=stride)  # check image size\n\n        dataset = LoadImages(source, img_size=imgsz, stride=stride, auto=pt)\n        bs = 1  # batch_size\n\n        model.warmup(imgsz=(1 if pt else bs, 3, *imgsz))  # warmup\n        seen, windows, dt = 0, [], (Profile(), Profile(), Profile())\n        for path, im, im0s, vid_cap, s in dataset: \n            # Write id and size\n            image_id = Path(path).stem\n            sub_file.write(f'{image_id},512,512,')\n            \n            if image_id in dict_of_tiles:\n                annotations = dict_of_tiles[image_id]\n                glomerulus_mask = get_glomerulus_mask(annotations)\n            else:\n                annotations = []\n                glomerulus_mask = np.ones(shape=imgsz).astype(bool)\n                \n                \n            with dt[0]:\n                im = torch.from_numpy(im).to(device)\n                im = im.half() if model.fp16 else im.float()  # uint8 to fp16/32\n                im /= 255  # 0 - 255 to 0.0 - 1.0\n                if len(im.shape) == 3:\n                    im = im[None]  # expand for batch dim\n\n            # Inference\n            with dt[1]:\n                visualize = increment_path(save_dir / Path(path).stem, mkdir=True) if visualize else False\n                pred, out = model(im, augment=augment, visualize=visualize)\n                proto = out[1]\n\n            # NMS\n            with dt[2]:\n                pred = non_max_suppression(pred, conf_thres, iou_thres, classes, agnostic_nms, max_det=max_det, nm=32)\n\n            for i, det in enumerate(pred):  # per image\n                seen += 1\n\n                if len(det):\n                    masks = process_mask(proto[i], det[:, 6:], det[:, :4], im.shape[2:], upsample=True)  # HWC\n                    confs = det[:, 4]\n                    clasf = det[:, 5]\n\n                    for mask, confidence, classification in zip(masks, confs, clasf):\n                        binary_mask = mask.cpu().numpy()\n                        kernel = np.ones(shape=(3, 3), dtype=np.uint8)\n                        binary_mask = cv2.dilate(binary_mask, kernel, 3)\n                        \n                        binary_mask = binary_mask.astype(bool)\n                        binary_mask = binary_mask & glomerulus_mask\n                        \n                        kernel = np.ones(shape=(3, 3))\n\n                        encoded_mask = encode_binary_mask(binary_mask)\n                        sub_file.write(f'{int(classification)} {confidence} {encoded_mask.decode()} ' )\n        \n            sub_file.write('\\n')","metadata":{"execution":{"iopub.status.busy":"2023-06-15T06:36:35.902594Z","iopub.execute_input":"2023-06-15T06:36:35.902963Z","iopub.status.idle":"2023-06-15T06:36:35.922772Z","shell.execute_reply.started":"2023-06-15T06:36:35.902933Z","shell.execute_reply":"2023-06-15T06:36:35.921696Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"segment(source='/kaggle/input/hubmap-hacking-the-human-vasculature/test',\n            data='/kaggle/working/hubmap-coco.yaml',\n            imgsz=(512, 512), \n            classes=0,\n            weights='/kaggle/input/yolov7-weights-and-wheels/yolov7-fine-tune/yolov7-fine-tune/weights/best.pt',\n            name='yolov7-predict',\n            project='yolov7-predict',\n            exist_ok=True,\n            nosave=True,\n            save_txt=True,\n            view_img=True,\n            )","metadata":{"execution":{"iopub.status.busy":"2023-06-15T06:36:36.557201Z","iopub.execute_input":"2023-06-15T06:36:36.557896Z","iopub.status.idle":"2023-06-15T06:36:45.830938Z","shell.execute_reply.started":"2023-06-15T06:36:36.557863Z","shell.execute_reply":"2023-06-15T06:36:45.829719Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!cat submission.csv","metadata":{"execution":{"iopub.status.busy":"2023-06-15T06:35:50.150165Z","iopub.status.idle":"2023-06-15T06:35:50.151029Z","shell.execute_reply.started":"2023-06-15T06:35:50.150783Z","shell.execute_reply":"2023-06-15T06:35:50.150806Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}