Skip to content

Bbox

Class for manipulating bounding boxes.

All bounding boxes are converted to internally the VOC format: [xmin, ymin, xmax, ymax], and can be exported to the VOC, COCO and YOLO formats.

Source code in detection_datasets/bbox.py
class Bbox:
    """Class for manipulating bounding boxes.

    All bounding boxes are converted to internally the VOC format: [xmin, ymin, xmax, ymax], and can be exported to the
    VOC, COCO and YOLO formats.
    """

    def __init__(self, bbox: list[float], width: float, height: float, bbox_id: int) -> None:
        self.bbox = bbox
        self.width = width
        self.height = height
        self.bbox_id = bbox_id
        self._validate_bbox()

    @classmethod
    def from_voc(cls, bbox: list[float], width: float, height: float, bbox_id: int) -> Bbox:
        """Keep the bbox in VOC format: xmin, ymin, xmax, ymax."""

        return Bbox(bbox, width, height, bbox_id)

    @classmethod
    def from_coco(cls, bbox: list[float], width: float, height: float, bbox_id: int) -> Bbox:
        """Convert the bbox from COCO format: xmin, ymin, w, h."""

        bbox = [bbox[0], bbox[1], bbox[0] + bbox[2], bbox[1] + bbox[3]]
        return Bbox(bbox, width, height, bbox_id)

    @classmethod
    def from_yolo(cls, bbox: list[float], width: float, height: float, bbox_id: int) -> Bbox:
        """Convert the bbox from YOLO format: relative xc, yc, w, h."""

        assert bbox[0] < 1 and bbox[1] < 1 and bbox[2] < 1 and bbox[3] < 1, "yolo bbox must be relative"

        bbox = [bbox[0] - bbox[2] / 2, bbox[1] - bbox[3] / 2, bbox[0] + bbox[2] / 2, bbox[1] + bbox[3] / 2]
        bbox = [bbox[0] * width, bbox[1] * height, bbox[2] * width, bbox[3] * height]
        return Bbox(bbox, width, height, bbox_id)

    def to_voc(self) -> list[float]:
        """Bbox is already in VOC format internally."""

        return self.bbox

    def to_coco(self) -> list[float]:
        """Convert the bbox to COCO format: xmin, ymin, w, h."""

        return [self.bbox[0], self.bbox[1], self.bbox[2] - self.bbox[0], self.bbox[3] - self.bbox[1]]

    def to_yolo(self) -> list[float]:
        """Convert the bbox to YOLO format: relative xc, yc, w, h."""

        bbox = self.to_coco()
        bbox = [bbox[0] / self.width, bbox[1] / self.height, bbox[2] / self.width, bbox[3] / self.height]
        return bbox

    def _validate_bbox(self) -> None:
        """Asserts that the bbox to the correct size."""

        assert self.bbox[2] >= self.bbox[0] and self.bbox[3] >= self.bbox[1], "bbox must be a rectangle"

        # assert self.bbox[2] <= self.width and self.bbox[3] <= self.height, "bbox must be inside the image"
        if not self.bbox[2] <= self.width:
            print(f"Warning: incorrect bbox_id {self.bbox_id}: x_max {self.bbox[2]} > image width {self.width}")
        if not self.bbox[3] <= self.height:
            print(f"Warning: incorrect bbox_id {self.bbox_id}: y_max {self.bbox[3]} > image height {self.height}")

    def __repr__(self):
        return f"Bbox id {self.bbox_id} {self.bbox}"

    def __print__(self):
        return self.__repr__()

from_coco(bbox, width, height, bbox_id) classmethod #

Convert the bbox from COCO format: xmin, ymin, w, h.

Source code in detection_datasets/bbox.py
@classmethod
def from_coco(cls, bbox: list[float], width: float, height: float, bbox_id: int) -> Bbox:
    """Convert the bbox from COCO format: xmin, ymin, w, h."""

    bbox = [bbox[0], bbox[1], bbox[0] + bbox[2], bbox[1] + bbox[3]]
    return Bbox(bbox, width, height, bbox_id)

from_voc(bbox, width, height, bbox_id) classmethod #

Keep the bbox in VOC format: xmin, ymin, xmax, ymax.

Source code in detection_datasets/bbox.py
@classmethod
def from_voc(cls, bbox: list[float], width: float, height: float, bbox_id: int) -> Bbox:
    """Keep the bbox in VOC format: xmin, ymin, xmax, ymax."""

    return Bbox(bbox, width, height, bbox_id)

from_yolo(bbox, width, height, bbox_id) classmethod #

Convert the bbox from YOLO format: relative xc, yc, w, h.

Source code in detection_datasets/bbox.py
@classmethod
def from_yolo(cls, bbox: list[float], width: float, height: float, bbox_id: int) -> Bbox:
    """Convert the bbox from YOLO format: relative xc, yc, w, h."""

    assert bbox[0] < 1 and bbox[1] < 1 and bbox[2] < 1 and bbox[3] < 1, "yolo bbox must be relative"

    bbox = [bbox[0] - bbox[2] / 2, bbox[1] - bbox[3] / 2, bbox[0] + bbox[2] / 2, bbox[1] + bbox[3] / 2]
    bbox = [bbox[0] * width, bbox[1] * height, bbox[2] * width, bbox[3] * height]
    return Bbox(bbox, width, height, bbox_id)

to_coco() #

Convert the bbox to COCO format: xmin, ymin, w, h.

Source code in detection_datasets/bbox.py
def to_coco(self) -> list[float]:
    """Convert the bbox to COCO format: xmin, ymin, w, h."""

    return [self.bbox[0], self.bbox[1], self.bbox[2] - self.bbox[0], self.bbox[3] - self.bbox[1]]

to_voc() #

Bbox is already in VOC format internally.

Source code in detection_datasets/bbox.py
def to_voc(self) -> list[float]:
    """Bbox is already in VOC format internally."""

    return self.bbox

to_yolo() #

Convert the bbox to YOLO format: relative xc, yc, w, h.

Source code in detection_datasets/bbox.py
def to_yolo(self) -> list[float]:
    """Convert the bbox to YOLO format: relative xc, yc, w, h."""

    bbox = self.to_coco()
    bbox = [bbox[0] / self.width, bbox[1] / self.height, bbox[2] / self.width, bbox[3] / self.height]
    return bbox