{
  "id": 302761,
  "title": "How to implement your own Yolo by using SAHI",
  "url": "/competitions/tensorflow-great-barrier-reef/discussion/302761",
  "author_name": "Dewei Chen",
  "post_date": "2022-01-24T06:56:56.981000",
  "votes": 16,
  "comment_count": 5,
  "views": 0,
  "content": "<p><strong>First of all</strong>, my work is base on <a href=\"https://www.kaggle.com/remekkinas/sahi-slicing-aided-hyper-inference-yv5-and-yx;\" target=\"_blank\">https://www.kaggle.com/remekkinas/sahi-slicing-aided-hyper-inference-yv5-and-yx;</a><br>\nand the discussion <a href=\"https://www.kaggle.com/c/tensorflow-great-barrier-reef/discussion/302586;\" target=\"_blank\">https://www.kaggle.com/c/tensorflow-great-barrier-reef/discussion/302586;</a> <br>\nIt's a amazing work, <strong>don't forget upvote him</strong> <a href=\"https://www.kaggle.com/remekkinas\" target=\"_blank\">@remekkinas</a> </p>\n<p>The original code is at here:<br>\n<a href=\"https://github.com/obss/sahi/blob/main/sahi/model.py\" target=\"_blank\">https://github.com/obss/sahi/blob/main/sahi/model.py</a></p>\n<p><strong>You need to define a new class by using \"DetectionModel\"</strong></p>\n<p>import logging<br>\nimport warnings<br>\nfrom typing import Dict, List, Optional, Union<br>\nimport numpy as np<br>\nfrom sahi.prediction import ObjectPrediction<br>\nfrom sahi.utils.compatibility import fix_full_shape_list, fix_shift_amount_list<br>\nfrom sahi.utils.cv import get_bbox_from_bool_mask<br>\nfrom sahi.utils.torch import cuda_is_available, empty_cuda_cache</p>\n<p>class YourYolov5DetectionModel(DetectionModel):</p>\n<pre><code>def load_model(self):\n\n    try:\n        import torch\n    except ImportError:\n        raise ImportError(\n            \"Please install torch and Your-YOLOv5 first for YOLOv5 inference.\"\n        )\n\n    # set model\n    try:\n        model = torch.hub.load('../input/yolov5-ds', \n                       'custom', \n                       path=self.model_path,\n                       source='local',\n                       force_reload=True)\n        model.conf = self.confidence_threshold\n        self.model = model\n    except Exception as e:\n        TypeError(\"model_path is not a valid yolov5 model path: \", e)\n\n    # set category_mapping\n    if not self.category_mapping:\n        category_mapping = {\n            str(ind): category_name\n            for ind, category_name in enumerate(self.category_names)\n        }\n        self.category_mapping = category_mapping\n\ndef perform_inference(self, image: np.ndarray, image_size: int = None):\n    \"\"\"\n    Prediction is performed using self.model and the prediction result is set to self._original_predictions.\n    Args:\n        image: np.ndarray\n            A numpy array that contains the image to be predicted. 3 channel image should be in RGB order.\n        image_size: int\n            Inference input size.\n    \"\"\"\n    try:\n        import yolov5\n    except ImportError:\n        raise ImportError('Please run \"pip install -U yolov5\" ' \"to install YOLOv5 first for YOLOv5 inference.\")\n\n    # Confirm model is loaded\n    assert self.model is not None, \"Model is not loaded, load it by calling .load_model()\"\n\n    if image_size is not None:\n        warnings.warn(\"Set 'image_size' at DetectionModel init.\", DeprecationWarning)\n        prediction_result = self.model(image, size=image_size, augment=True)\n    elif self.image_size is not None:\n        prediction_result = self.model(image, size=self.image_size)\n    else:\n        prediction_result = self.model(image)\n\n    self._original_predictions = prediction_result\n\n@property\ndef num_categories(self):\n    \"\"\"\n    Returns number of categories\n    \"\"\"\n    return len(self.model.names)\n\n@property\ndef has_mask(self):\n    \"\"\"\n    Returns if model output contains segmentation mask\n    \"\"\"\n    has_mask = self.model.with_mask\n    return has_mask\n\n@property\ndef category_names(self):\n    return self.model.names\n\ndef _create_object_prediction_list_from_original_predictions(\n    self,\n    shift_amount_list: Optional[List[List[int]]] = [[0, 0]],\n    full_shape_list: Optional[List[List[int]]] = None,\n):\n    \"\"\"\n    self._original_predictions is converted to a list of prediction.ObjectPrediction and set to\n    self._object_prediction_list_per_image.\n    Args:\n        shift_amount_list: list of list\n            To shift the box and mask predictions from sliced image to full sized image, should\n            be in the form of List[[shift_x, shift_y],[shift_x, shift_y],...]\n        full_shape_list: list of list\n            Size of the full image after shifting, should be in the form of\n            List[[height, width],[height, width],...]\n    \"\"\"\n    original_predictions = self._original_predictions\n\n    # compatilibty for sahi v0.8.15\n    shift_amount_list = fix_shift_amount_list(shift_amount_list)\n    full_shape_list = fix_full_shape_list(full_shape_list)\n\n    # handle all predictions\n    object_prediction_list_per_image = []\n    for image_ind, image_predictions_in_xyxy_format in enumerate(original_predictions.xyxy):\n        shift_amount = shift_amount_list[image_ind]\n        full_shape = None if full_shape_list is None else full_shape_list[image_ind]\n        object_prediction_list = []\n\n        # process predictions\n        for prediction in image_predictions_in_xyxy_format.cpu().detach().numpy():\n            x1 = int(prediction[0])\n            y1 = int(prediction[1])\n            x2 = int(prediction[2])\n            y2 = int(prediction[3])\n            bbox = [x1, y1, x2, y2]\n            score = prediction[4]\n            category_id = int(prediction[5])\n            category_name = self.category_mapping[str(category_id)]\n\n            # ignore invalid predictions\n            if bbox[0] &gt; bbox[2] or bbox[1] &gt; bbox[3] or bbox[0] &lt; 0 or bbox[1] &lt; 0 or bbox[2] &lt; 0 or bbox[3] &lt; 0:\n                logger.warning(f\"ignoring invalid prediction with bbox: {bbox}\")\n                continue\n            if full_shape is not None and (\n                bbox[1] &gt; full_shape[0]\n                or bbox[3] &gt; full_shape[0]\n                or bbox[0] &gt; full_shape[1]\n                or bbox[2] &gt; full_shape[1]\n            ):\n                logger.warning(f\"ignoring invalid prediction with bbox: {bbox}\")\n                continue\n\n            object_prediction = ObjectPrediction(\n                bbox=bbox,\n                category_id=category_id,\n                score=score,\n                bool_mask=None,\n                category_name=category_name,\n                shift_amount=shift_amount,\n                full_shape=full_shape,\n            )\n            object_prediction_list.append(object_prediction)\n        object_prediction_list_per_image.append(object_prediction_list)\n\n    self._object_prediction_list_per_image = object_prediction_list_per_image \n</code></pre>",
  "messages": [
    {
      "id": 1662286,
      "postDate": "2022-01-24T06:56:56.980Z",
      "content": "<p><strong>First of all</strong>, my work is base on <a href=\"https://www.kaggle.com/remekkinas/sahi-slicing-aided-hyper-inference-yv5-and-yx;\" target=\"_blank\">https://www.kaggle.com/remekkinas/sahi-slicing-aided-hyper-inference-yv5-and-yx;</a><br>\nand the discussion <a href=\"https://www.kaggle.com/c/tensorflow-great-barrier-reef/discussion/302586;\" target=\"_blank\">https://www.kaggle.com/c/tensorflow-great-barrier-reef/discussion/302586;</a> <br>\nIt's a amazing work, <strong>don't forget upvote him</strong> <a href=\"https://www.kaggle.com/remekkinas\" target=\"_blank\">@remekkinas</a> </p>\n<p>The original code is at here:<br>\n<a href=\"https://github.com/obss/sahi/blob/main/sahi/model.py\" target=\"_blank\">https://github.com/obss/sahi/blob/main/sahi/model.py</a></p>\n<p><strong>You need to define a new class by using \"DetectionModel\"</strong></p>\n<p>import logging<br>\nimport warnings<br>\nfrom typing import Dict, List, Optional, Union<br>\nimport numpy as np<br>\nfrom sahi.prediction import ObjectPrediction<br>\nfrom sahi.utils.compatibility import fix_full_shape_list, fix_shift_amount_list<br>\nfrom sahi.utils.cv import get_bbox_from_bool_mask<br>\nfrom sahi.utils.torch import cuda_is_available, empty_cuda_cache</p>\n<p>class YourYolov5DetectionModel(DetectionModel):</p>\n<pre><code>def load_model(self):\n\n    try:\n        import torch\n    except ImportError:\n        raise ImportError(\n            \"Please install torch and Your-YOLOv5 first for YOLOv5 inference.\"\n        )\n\n    # set model\n    try:\n        model = torch.hub.load('../input/yolov5-ds', \n                       'custom', \n                       path=self.model_path,\n                       source='local',\n                       force_reload=True)\n        model.conf = self.confidence_threshold\n        self.model = model\n    except Exception as e:\n        TypeError(\"model_path is not a valid yolov5 model path: \", e)\n\n    # set category_mapping\n    if not self.category_mapping:\n        category_mapping = {\n            str(ind): category_name\n            for ind, category_name in enumerate(self.category_names)\n        }\n        self.category_mapping = category_mapping\n\ndef perform_inference(self, image: np.ndarray, image_size: int = None):\n    \"\"\"\n    Prediction is performed using self.model and the prediction result is set to self._original_predictions.\n    Args:\n        image: np.ndarray\n            A numpy array that contains the image to be predicted. 3 channel image should be in RGB order.\n        image_size: int\n            Inference input size.\n    \"\"\"\n    try:\n        import yolov5\n    except ImportError:\n        raise ImportError('Please run \"pip install -U yolov5\" ' \"to install YOLOv5 first for YOLOv5 inference.\")\n\n    # Confirm model is loaded\n    assert self.model is not None, \"Model is not loaded, load it by calling .load_model()\"\n\n    if image_size is not None:\n        warnings.warn(\"Set 'image_size' at DetectionModel init.\", DeprecationWarning)\n        prediction_result = self.model(image, size=image_size, augment=True)\n    elif self.image_size is not None:\n        prediction_result = self.model(image, size=self.image_size)\n    else:\n        prediction_result = self.model(image)\n\n    self._original_predictions = prediction_result\n\n@property\ndef num_categories(self):\n    \"\"\"\n    Returns number of categories\n    \"\"\"\n    return len(self.model.names)\n\n@property\ndef has_mask(self):\n    \"\"\"\n    Returns if model output contains segmentation mask\n    \"\"\"\n    has_mask = self.model.with_mask\n    return has_mask\n\n@property\ndef category_names(self):\n    return self.model.names\n\ndef _create_object_prediction_list_from_original_predictions(\n    self,\n    shift_amount_list: Optional[List[List[int]]] = [[0, 0]],\n    full_shape_list: Optional[List[List[int]]] = None,\n):\n    \"\"\"\n    self._original_predictions is converted to a list of prediction.ObjectPrediction and set to\n    self._object_prediction_list_per_image.\n    Args:\n        shift_amount_list: list of list\n            To shift the box and mask predictions from sliced image to full sized image, should\n            be in the form of List[[shift_x, shift_y],[shift_x, shift_y],...]\n        full_shape_list: list of list\n            Size of the full image after shifting, should be in the form of\n            List[[height, width],[height, width],...]\n    \"\"\"\n    original_predictions = self._original_predictions\n\n    # compatilibty for sahi v0.8.15\n    shift_amount_list = fix_shift_amount_list(shift_amount_list)\n    full_shape_list = fix_full_shape_list(full_shape_list)\n\n    # handle all predictions\n    object_prediction_list_per_image = []\n    for image_ind, image_predictions_in_xyxy_format in enumerate(original_predictions.xyxy):\n        shift_amount = shift_amount_list[image_ind]\n        full_shape = None if full_shape_list is None else full_shape_list[image_ind]\n        object_prediction_list = []\n\n        # process predictions\n        for prediction in image_predictions_in_xyxy_format.cpu().detach().numpy():\n            x1 = int(prediction[0])\n            y1 = int(prediction[1])\n            x2 = int(prediction[2])\n            y2 = int(prediction[3])\n            bbox = [x1, y1, x2, y2]\n            score = prediction[4]\n            category_id = int(prediction[5])\n            category_name = self.category_mapping[str(category_id)]\n\n            # ignore invalid predictions\n            if bbox[0] &gt; bbox[2] or bbox[1] &gt; bbox[3] or bbox[0] &lt; 0 or bbox[1] &lt; 0 or bbox[2] &lt; 0 or bbox[3] &lt; 0:\n                logger.warning(f\"ignoring invalid prediction with bbox: {bbox}\")\n                continue\n            if full_shape is not None and (\n                bbox[1] &gt; full_shape[0]\n                or bbox[3] &gt; full_shape[0]\n                or bbox[0] &gt; full_shape[1]\n                or bbox[2] &gt; full_shape[1]\n            ):\n                logger.warning(f\"ignoring invalid prediction with bbox: {bbox}\")\n                continue\n\n            object_prediction = ObjectPrediction(\n                bbox=bbox,\n                category_id=category_id,\n                score=score,\n                bool_mask=None,\n                category_name=category_name,\n                shift_amount=shift_amount,\n                full_shape=full_shape,\n            )\n            object_prediction_list.append(object_prediction)\n        object_prediction_list_per_image.append(object_prediction_list)\n\n    self._object_prediction_list_per_image = object_prediction_list_per_image \n</code></pre>",
      "rawMarkdown": "**First of all**, my work is base on https://www.kaggle.com/remekkinas/sahi-slicing-aided-hyper-inference-yv5-and-yx;\nand the discussion https://www.kaggle.com/c/tensorflow-great-barrier-reef/discussion/302586; \nIt's a amazing work, **don't forget upvote him** @remekkinas \n\n\nThe original code is at here:\nhttps://github.com/obss/sahi/blob/main/sahi/model.py\n\n\n**You need to define a new class by using \"DetectionModel\"**\n\n\nimport logging\nimport warnings\nfrom typing import Dict, List, Optional, Union\nimport numpy as np\nfrom sahi.prediction import ObjectPrediction\nfrom sahi.utils.compatibility import fix_full_shape_list, fix_shift_amount_list\nfrom sahi.utils.cv import get_bbox_from_bool_mask\nfrom sahi.utils.torch import cuda_is_available, empty_cuda_cache\n\n\nclass YourYolov5DetectionModel(DetectionModel):\n\n    def load_model(self):\n\n        try:\n            import torch\n        except ImportError:\n            raise ImportError(\n                \"Please install torch and Your-YOLOv5 first for YOLOv5 inference.\"\n            )\n\n        # set model\n        try:\n            model = torch.hub.load('../input/yolov5-ds', \n                           'custom', \n                           path=self.model_path,\n                           source='local',\n                           force_reload=True)\n            model.conf = self.confidence_threshold\n            self.model = model\n        except Exception as e:\n            TypeError(\"model_path is not a valid yolov5 model path: \", e)\n\n        # set category_mapping\n        if not self.category_mapping:\n            category_mapping = {\n                str(ind): category_name\n                for ind, category_name in enumerate(self.category_names)\n            }\n            self.category_mapping = category_mapping\n\n    def perform_inference(self, image: np.ndarray, image_size: int = None):\n        \"\"\"\n        Prediction is performed using self.model and the prediction result is set to self._original_predictions.\n        Args:\n            image: np.ndarray\n                A numpy array that contains the image to be predicted. 3 channel image should be in RGB order.\n            image_size: int\n                Inference input size.\n        \"\"\"\n        try:\n            import yolov5\n        except ImportError:\n            raise ImportError('Please run \"pip install -U yolov5\" ' \"to install YOLOv5 first for YOLOv5 inference.\")\n\n        # Confirm model is loaded\n        assert self.model is not None, \"Model is not loaded, load it by calling .load_model()\"\n\n        if image_size is not None:\n            warnings.warn(\"Set 'image_size' at DetectionModel init.\", DeprecationWarning)\n            prediction_result = self.model(image, size=image_size, augment=True)\n        elif self.image_size is not None:\n            prediction_result = self.model(image, size=self.image_size)\n        else:\n            prediction_result = self.model(image)\n\n        self._original_predictions = prediction_result\n\n    @property\n    def num_categories(self):\n        \"\"\"\n        Returns number of categories\n        \"\"\"\n        return len(self.model.names)\n\n    @property\n    def has_mask(self):\n        \"\"\"\n        Returns if model output contains segmentation mask\n        \"\"\"\n        has_mask = self.model.with_mask\n        return has_mask\n\n    @property\n    def category_names(self):\n        return self.model.names\n\n    def _create_object_prediction_list_from_original_predictions(\n        self,\n        shift_amount_list: Optional[List[List[int]]] = [[0, 0]],\n        full_shape_list: Optional[List[List[int]]] = None,\n    ):\n        \"\"\"\n        self._original_predictions is converted to a list of prediction.ObjectPrediction and set to\n        self._object_prediction_list_per_image.\n        Args:\n            shift_amount_list: list of list\n                To shift the box and mask predictions from sliced image to full sized image, should\n                be in the form of List[[shift_x, shift_y],[shift_x, shift_y],...]\n            full_shape_list: list of list\n                Size of the full image after shifting, should be in the form of\n                List[[height, width],[height, width],...]\n        \"\"\"\n        original_predictions = self._original_predictions\n\n        # compatilibty for sahi v0.8.15\n        shift_amount_list = fix_shift_amount_list(shift_amount_list)\n        full_shape_list = fix_full_shape_list(full_shape_list)\n\n        # handle all predictions\n        object_prediction_list_per_image = []\n        for image_ind, image_predictions_in_xyxy_format in enumerate(original_predictions.xyxy):\n            shift_amount = shift_amount_list[image_ind]\n            full_shape = None if full_shape_list is None else full_shape_list[image_ind]\n            object_prediction_list = []\n\n            # process predictions\n            for prediction in image_predictions_in_xyxy_format.cpu().detach().numpy():\n                x1 = int(prediction[0])\n                y1 = int(prediction[1])\n                x2 = int(prediction[2])\n                y2 = int(prediction[3])\n                bbox = [x1, y1, x2, y2]\n                score = prediction[4]\n                category_id = int(prediction[5])\n                category_name = self.category_mapping[str(category_id)]\n\n                # ignore invalid predictions\n                if bbox[0] > bbox[2] or bbox[1] > bbox[3] or bbox[0] < 0 or bbox[1] < 0 or bbox[2] < 0 or bbox[3] < 0:\n                    logger.warning(f\"ignoring invalid prediction with bbox: {bbox}\")\n                    continue\n                if full_shape is not None and (\n                    bbox[1] > full_shape[0]\n                    or bbox[3] > full_shape[0]\n                    or bbox[0] > full_shape[1]\n                    or bbox[2] > full_shape[1]\n                ):\n                    logger.warning(f\"ignoring invalid prediction with bbox: {bbox}\")\n                    continue\n\n                object_prediction = ObjectPrediction(\n                    bbox=bbox,\n                    category_id=category_id,\n                    score=score,\n                    bool_mask=None,\n                    category_name=category_name,\n                    shift_amount=shift_amount,\n                    full_shape=full_shape,\n                )\n                object_prediction_list.append(object_prediction)\n            object_prediction_list_per_image.append(object_prediction_list)\n\n        self._object_prediction_list_per_image = object_prediction_list_per_image \n",
      "votes": 15
    },
    {
      "id": 1662593,
      "postDate": "2022-01-24T12:11:06.723Z",
      "content": "<p>Nice work. I will test this. </p>",
      "rawMarkdown": "Nice work. I will test this. ",
      "votes": 1
    },
    {
      "id": 1662377,
      "postDate": "2022-01-24T08:24:04.310Z",
      "content": "<p>Thank you for mentioning my work. I really appreciate. <br>\nGreat tip! If you do not mind I use this code in my implementation as well. Thank you!</p>",
      "rawMarkdown": "Thank you for mentioning my work. I really appreciate. \nGreat tip! If you do not mind I use this code in my implementation as well. Thank you!",
      "votes": 2,
      "replies": [
        {
          "id": 1662382,
          "postDate": "2022-01-24T08:28:27.733Z",
          "content": "<p>I'm glad to know it helped 😄😄😄</p>",
          "rawMarkdown": "I'm glad to know it helped 😄😄😄",
          "votes": 1
        },
        {
          "id": 1662386,
          "postDate": "2022-01-24T08:29:49.187Z",
          "content": "<p>Even more I thnink that this code helps a lot :) </p>",
          "rawMarkdown": "Even more I thnink that this code helps a lot :) ",
          "votes": 1
        }
      ]
    },
    {
      "id": 1662351,
      "postDate": "2022-01-24T07:52:31.257Z",
      "rawMarkdown": "",
      "votes": 1,
      "isDeleted": true
    }
  ],
  "comments": [
    {
      "id": 1662593,
      "author_name": "Charlie Craine",
      "author_url": "",
      "post_date": "2022-01-24T12:11:06.723000",
      "content": "<p>Nice work. I will test this. </p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 1662377,
      "author_name": "Remek Kinas",
      "author_url": "",
      "post_date": "2022-01-24T08:24:04.310000",
      "content": "<p>Thank you for mentioning my work. I really appreciate. <br>\nGreat tip! If you do not mind I use this code in my implementation as well. Thank you!</p>",
      "votes": 2,
      "replies": [
        {
          "id": 1662382,
          "author_name": "Dewei Chen",
          "author_url": "",
          "post_date": "2022-01-24T08:28:27.733000",
          "content": "<p>I'm glad to know it helped 😄😄😄</p>",
          "votes": 1,
          "replies": []
        },
        {
          "id": 1662386,
          "author_name": "Remek Kinas",
          "author_url": "",
          "post_date": "2022-01-24T08:29:49.187000",
          "content": "<p>Even more I thnink that this code helps a lot :) </p>",
          "votes": 1,
          "replies": []
        }
      ]
    },
    {
      "id": 1662351,
      "author_name": "",
      "author_url": "",
      "post_date": "2022-01-24T07:52:31.257000",
      "content": "",
      "votes": 1,
      "replies": []
    }
  ],
  "raw_markdown_by_id": {
    "1662286": "**First of all**, my work is base on https://www.kaggle.com/remekkinas/sahi-slicing-aided-hyper-inference-yv5-and-yx;\nand the discussion https://www.kaggle.com/c/tensorflow-great-barrier-reef/discussion/302586; \nIt's a amazing work, **don't forget upvote him** @remekkinas \n\n\nThe original code is at here:\nhttps://github.com/obss/sahi/blob/main/sahi/model.py\n\n\n**You need to define a new class by using \"DetectionModel\"**\n\n\nimport logging\nimport warnings\nfrom typing import Dict, List, Optional, Union\nimport numpy as np\nfrom sahi.prediction import ObjectPrediction\nfrom sahi.utils.compatibility import fix_full_shape_list, fix_shift_amount_list\nfrom sahi.utils.cv import get_bbox_from_bool_mask\nfrom sahi.utils.torch import cuda_is_available, empty_cuda_cache\n\n\nclass YourYolov5DetectionModel(DetectionModel):\n\n    def load_model(self):\n\n        try:\n            import torch\n        except ImportError:\n            raise ImportError(\n                \"Please install torch and Your-YOLOv5 first for YOLOv5 inference.\"\n            )\n\n        # set model\n        try:\n            model = torch.hub.load('../input/yolov5-ds', \n                           'custom', \n                           path=self.model_path,\n                           source='local',\n                           force_reload=True)\n            model.conf = self.confidence_threshold\n            self.model = model\n        except Exception as e:\n            TypeError(\"model_path is not a valid yolov5 model path: \", e)\n\n        # set category_mapping\n        if not self.category_mapping:\n            category_mapping = {\n                str(ind): category_name\n                for ind, category_name in enumerate(self.category_names)\n            }\n            self.category_mapping = category_mapping\n\n    def perform_inference(self, image: np.ndarray, image_size: int = None):\n        \"\"\"\n        Prediction is performed using self.model and the prediction result is set to self._original_predictions.\n        Args:\n            image: np.ndarray\n                A numpy array that contains the image to be predicted. 3 channel image should be in RGB order.\n            image_size: int\n                Inference input size.\n        \"\"\"\n        try:\n            import yolov5\n        except ImportError:\n            raise ImportError('Please run \"pip install -U yolov5\" ' \"to install YOLOv5 first for YOLOv5 inference.\")\n\n        # Confirm model is loaded\n        assert self.model is not None, \"Model is not loaded, load it by calling .load_model()\"\n\n        if image_size is not None:\n            warnings.warn(\"Set 'image_size' at DetectionModel init.\", DeprecationWarning)\n            prediction_result = self.model(image, size=image_size, augment=True)\n        elif self.image_size is not None:\n            prediction_result = self.model(image, size=self.image_size)\n        else:\n            prediction_result = self.model(image)\n\n        self._original_predictions = prediction_result\n\n    @property\n    def num_categories(self):\n        \"\"\"\n        Returns number of categories\n        \"\"\"\n        return len(self.model.names)\n\n    @property\n    def has_mask(self):\n        \"\"\"\n        Returns if model output contains segmentation mask\n        \"\"\"\n        has_mask = self.model.with_mask\n        return has_mask\n\n    @property\n    def category_names(self):\n        return self.model.names\n\n    def _create_object_prediction_list_from_original_predictions(\n        self,\n        shift_amount_list: Optional[List[List[int]]] = [[0, 0]],\n        full_shape_list: Optional[List[List[int]]] = None,\n    ):\n        \"\"\"\n        self._original_predictions is converted to a list of prediction.ObjectPrediction and set to\n        self._object_prediction_list_per_image.\n        Args:\n            shift_amount_list: list of list\n                To shift the box and mask predictions from sliced image to full sized image, should\n                be in the form of List[[shift_x, shift_y],[shift_x, shift_y],...]\n            full_shape_list: list of list\n                Size of the full image after shifting, should be in the form of\n                List[[height, width],[height, width],...]\n        \"\"\"\n        original_predictions = self._original_predictions\n\n        # compatilibty for sahi v0.8.15\n        shift_amount_list = fix_shift_amount_list(shift_amount_list)\n        full_shape_list = fix_full_shape_list(full_shape_list)\n\n        # handle all predictions\n        object_prediction_list_per_image = []\n        for image_ind, image_predictions_in_xyxy_format in enumerate(original_predictions.xyxy):\n            shift_amount = shift_amount_list[image_ind]\n            full_shape = None if full_shape_list is None else full_shape_list[image_ind]\n            object_prediction_list = []\n\n            # process predictions\n            for prediction in image_predictions_in_xyxy_format.cpu().detach().numpy():\n                x1 = int(prediction[0])\n                y1 = int(prediction[1])\n                x2 = int(prediction[2])\n                y2 = int(prediction[3])\n                bbox = [x1, y1, x2, y2]\n                score = prediction[4]\n                category_id = int(prediction[5])\n                category_name = self.category_mapping[str(category_id)]\n\n                # ignore invalid predictions\n                if bbox[0] > bbox[2] or bbox[1] > bbox[3] or bbox[0] < 0 or bbox[1] < 0 or bbox[2] < 0 or bbox[3] < 0:\n                    logger.warning(f\"ignoring invalid prediction with bbox: {bbox}\")\n                    continue\n                if full_shape is not None and (\n                    bbox[1] > full_shape[0]\n                    or bbox[3] > full_shape[0]\n                    or bbox[0] > full_shape[1]\n                    or bbox[2] > full_shape[1]\n                ):\n                    logger.warning(f\"ignoring invalid prediction with bbox: {bbox}\")\n                    continue\n\n                object_prediction = ObjectPrediction(\n                    bbox=bbox,\n                    category_id=category_id,\n                    score=score,\n                    bool_mask=None,\n                    category_name=category_name,\n                    shift_amount=shift_amount,\n                    full_shape=full_shape,\n                )\n                object_prediction_list.append(object_prediction)\n            object_prediction_list_per_image.append(object_prediction_list)\n\n        self._object_prediction_list_per_image = object_prediction_list_per_image \n",
    "1662593": "Nice work. I will test this. ",
    "1662377": "Thank you for mentioning my work. I really appreciate. \nGreat tip! If you do not mind I use this code in my implementation as well. Thank you!",
    "1662351": ""
  }
}