PyBboxes
Light weight toolkit for bounding boxes providing conversion between bounding box types and simple computations. Supported bounding box types (italicized text indicates normalized values):
- albumentations : Albumentations Format
- [x-tl, y-tl, x-br, y-br] (Normalized VOC Format) Top-left coordinates & Bottom-right coordinates
- coco : COCO (Common Objects in Context)
- [x-tl, y-tl, w, h] Top-left corner & width & height
- fiftyone : FiftyOne
- [x-tl, y-tl, w, h] (Normalized COCO Format) Top-left coordinates & width & height
- voc : Pascal VOC
- [x-tl, y-tl, x-br, y-br] Top-left coordinates & Bottom-right coordinates
- yolo : YOLO
- [x-c, y-c, w, h] Center coordinates & width & height
Glossary
- tl: top-left
- br: bottom-right
- h: height
- w: width
- c: center
News 🔥
- 2024/10/07 - Annotations are supported for YOLO, COCO and VOC formats.
Roadmap 🛣️
Important Notice
Support for Python<3.8 will be dropped starting version 0.2
though the development for Python3.6 and Python3.7 may
continue where it will be developed under version 0.1.x
for future versions. This may introduce; however, certain
discrepancies and/or unsupported operations in the 0.1.x
versions. To fully utilize and benefit from the entire
package, we recommend using Python3.8 at minimum (Python>=3.8
).
Installation
Through pip (recommended),
pip install pybboxes
or build from source,
git clone https://github.com/devrimcavusoglu/pybboxes.git
cd pybboxes
python setup.py install
Bounding Boxes
You can easily create bounding box as easy as
from pybboxes import BoundingBox
my_coco_box = [98, 345, 322, 117]
coco_bbox = BoundingBox.from_coco(*my_coco_box)
Out of Bounds Boxes
Pybboxes supports OOB boxes, there exists a keyword strict
in both Box classes (construction) and in functional
modules. When strict=True
, it does not allow out-of-bounds boxes to be constructed and raises an exception, while
it does allow out-of-bounds boxes to be constructed and used when strict=False
. Also, there is a property is_oob
that indicates whether a particular bouding box is OOB or not.
Important Note that, if the return value for is_oob
is None
, then it indicates that OOB status is unknown
(e.g. image size required to determine, but not given). Thus, values None
and False
indicates different information.
from pybboxes import BoundingBox
image_size = (640, 480)
my_coco_box = [98, 345, 580, 245]
coco_bbox = BoundingBox.from_coco(*my_coco_box, image_size=image_size)
coco_bbox = BoundingBox.from_coco(*my_coco_box, image_size=image_size, strict=False)
coco_bbox.is_oob
If you want to allow OOB, but still check OOB status, you should use strict=False
and is_oob
where needed.
Conversion
With the BoundingBox
class the conversion is as easy as one method call.
from pybboxes import BoundingBox
my_coco_box = [98, 345, 322, 117]
coco_bbox = BoundingBox.from_coco(*my_coco_box)
voc_bbox = coco_bbox.to_voc()
voc_bbox_values = coco_bbox.to_voc(return_values=True)
However, if you try to make conversion between two bounding boxes that require scaling/normalization it'll give an error
from pybboxes import BoundingBox
my_coco_box = [98, 345, 322, 117]
coco_bbox = BoundingBox.from_coco(*my_coco_box)
coco_bbox.image_size = (640, 480)
yolo_bbox = coco_bbox.to_yolo()
Image size associated with the bounding box can be given at the instantiation or while using classmethods e.g
from_coco()
.
from pybboxes import BoundingBox
my_coco_box = [98, 345, 322, 117]
coco_bbox = BoundingBox.from_coco(*my_coco_box, image_size=(640, 480))
yolo_bbox = coco_bbox.to_yolo()
Box operations
Box operations now available as of v0.1.0
.
from pybboxes import BoundingBox
my_coco_box = [98, 345, 322, 117]
my_coco_box2 = [90, 350, 310, 122]
coco_bbox = BoundingBox.from_coco(*my_coco_box, image_size=(640, 480))
coco_bbox2 = BoundingBox.from_coco(*my_coco_box2, image_size=(640, 480))
iou = coco_bbox.iou(coco_bbox2)
area_union = coco_bbox + coco_bbox2
total_area = coco_bbox.area + coco_bbox2.area
intersection_area = coco_bbox * coco_bbox2
first_bbox_diff = coco_bbox - coco_bbox2
second_bbox_diff = coco_bbox2 - coco_bbox
bbox_ratio = coco_bbox / coco_bbox2
Functional
Note: functional computations are moved under pybboxes.functional
starting with the version 0.1.0
. The only
exception is that convert_bbox()
which still can be used by importing pybboxes
only (for backward compatibility).
Conversion
You are able to convert from any bounding box type to another.
import pybboxes as pbx
coco_bbox = (1,2,3,4)
voc_bbox = (1,2,3,4)
pbx.convert_bbox(coco_bbox, from_type="coco", to_type="voc")
pbx.convert_bbox(voc_bbox, from_type="voc", to_type="coco")
Some formats require image width and height information for scaling, e.g. YOLO bbox (resulting coordinates
are rounded to 2 decimals to ease reading).
import pybboxes as pbx
voc_bbox = (1,2,3,4)
pbx.convert_bbox(voc_bbox, from_type="voc", to_type="yolo", image_size=(28, 28))
Computation
You can also make computations on supported bounding box formats.
import pybboxes.functional as pbf
coco_bbox = (1,2,3,4)
voc_bbox = (1,2,3,4)
pbf.compute_area(coco_bbox, bbox_type="coco")
pbf.compute_area(voc_bbox, bbox_type="voc")
Annotation file conversion
pybboxes
now supports the conversion of annotation file(s) across different annotation formats. (yolo, voc and coco are currently supported)
This is a 3 step process.
1. Instantiate the Annotations class
from pybboxes.annotations import Annotations
anns = Annotations(annotation_type='yolo')
Important you have to explicitly declare annotation_type
beforehand. post declaration, you will be only able to load annotation in declared format but you will be able to export to other annotation formats.
2. Load the annotations file
After you have instantiated the Annotations
class declaring annotation_type
, you can now load the annotations using appropriate method of the Annotations
class.
2.1 Load from yolo
from pybboxes.annotations import Annotations
anns = Annotations(annotation_type='yolo')
anns.load_from_yolo(labels_dir='./labels', images_dir='./images', classes_file='./classes.txt')
As yolo normalizes the bounding box metadata, path to corresponding images directory must be provided (via images_dir
) so that physical dimension of image data can be inferred.
Also, path to classes_file
(usually classes.txt) should be provided that lists all the class labels that is used for the annotation. Without this, pybboxes
will fail to assign appropriate class labels when converting across different annotations format.
2.2 Load from voc
from pybboxes.annotations import Annotations
anns = Annotations(annotation_type='voc')
anns.load_from_voc(labels_dir='./labels')
2.3 Load from coco
from pybboxes.annotations import Annotations
anns = Annotations(annotation_type='coco')
anns.load_from_coco(json_path='./validation.json')
3. Saving annotations to different format
3.1 Saving annotations to yolo format
As every image data has its own corresponding annotation file in yolo format, you have to provide path to export_dir
where all the annotation files will be written.
from pybboxes.annotations import Annotations
anns = Annotations(annotation_type='coco')
anns.load_from_coco(json_path='./validation.json')
anns.save_as_yolo(export_dir='./labels')
This will create all the required annotation files (in yolo format) in given directory. Additionally, it will also create classes.txt
in the given folder which will list all the class labels used for the annotation.
3.2 Saving annotations to voc format
Just like yolo format, in voc format, every image data has also its own corresponding annotation file. So, you have to provide path to export_dir
where all the annotation files will be written.
from pybboxes.annotations import Annotations
anns = Annotations(annotation_type='coco')
anns.load_from_coco(json_path='./validation.json')
anns.save_as_voc(export_dir='./labels')
3.3 Saving annotations to coco format
To export annotations in coco format, you just have to provide name (or path) of the output file (in json format) via export_file
.
from pybboxes.annotations import Annotations
anns = Annotations(annotation_type='voc')
anns.load_from_voc(labels_dir='./labels')
anns.save_as_coco(export_file='./validation.json')
Contributing
Installation
Install the package as follows, which will set you ready for the development mode.
pip install -e .[dev]
Tests
To tests simply run.
python -m tests.run_tests
Code Style
To check code style,
python -m tests.run_code_style check
To format codebase,
python -m tests.run_code_style format
License
Licensed under the MIT License.