boxdiff


Nameboxdiff JSON
Version 0.2.0 PyPI version JSON
download
home_pagehttps://github.com/kevinsbarnard/box-diff
SummaryUtilities for comparing bounding boxes
upload_time2024-02-01 22:19:40
maintainer
docs_urlNone
authorKevin Barnard
requires_python>=3.10,<4.0
license
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # box-diff
Utilities for comparing bounding boxes

Author: Kevin Barnard, [kbarnard@mbari.org](mailto:kbarnard@mbari.org)

[![tests](https://github.com/kevinsbarnard/box-diff/workflows/tests/badge.svg)](https://github.com/kevinsbarnard/box-diff/actions/workflows/tests.yml)


## Installation

box-diff is available on PyPI as [boxdiff](https://pypi.org/project/boxdiff/):

```bash
pip install boxdiff
```

## Usage

All of box-diff is housed within the `boxdiff` package.

```python
import boxdiff
```

The core data models are defined in the `boxdiff.models` module. These are split into three groups:
- `BoundingBox`: ID + labeled 2D bounding box
- `Image`: ID + collection of bounding boxes
- `ImageSet`: ID + collection of images

*Note: IDs may be integers, UUIDs, or strings.*

Each group has a data model (defined in `boxdiff.models.core`), a delta (`boxdiff.models.deltas`), and a difference flag (`boxdiff.models.flags`).
The data model represents the object and its attributes, whereas a delta represents the difference in attribute values between two objects.
Difference flags represent the presence of attribute differences between two objects as derived from a delta object.

All of the data models are serializable to JSON. For example,
```python
json_str = bounding_box.to_json(indent=2)

print(json_str)
```
might give
```json
{
  "id": 0,
  "label": "label",
  "x": 0.0,
  "y": 0.0,
  "width": 1.0,
  "height": 1.0
}
```

Similarly, data model objects may be parsed from JSON. For example,
```python
bounding_box = BoundingBox.from_json(json_str)

print(bounding_box)
# BoundingBox(id=0, label='label', x=0.0, y=0.0, width=1.0, height=1.0)
```

### Bounding Boxes

A `BoundingBox` is defined by an ID, a label, and a 2D box (x, y, width, height).

```python
from boxdiff import BoundingBox

car_box = BoundingBox(
    id=0,
    label='car',
    x=100, y=200,
    width=300, height=80
)
```

Equality can be checked using the `==` operator:

```python
same_car_box = BoundingBox(
    id=0,
    label='car',
    x=100, y=200,
    width=300, height=80
)

print(car_box == same_car_box)
# True

corrected_car_box = BoundingBox(
    id=0,
    label='car',
    x=90, y=210,
    width=320, height=85
)

print(car_box == corrected_car_box)
# False
```

A `BoundingBoxDelta` between two boxes can be computed with the `-` operator:

```python
box_delta = corrected_car_box - car_box

print(box_delta)
# BoundingBoxDelta(id=1, label_old='car', label_new='car', x_delta=-10.0, y_delta=10.0, width_delta=20.0, height_delta=5.0)
```

`BoundingBoxDifference` flags may then be computed from the delta:

```python
print(box_delta.flags)
# BoundingBoxDifference.RESIZED|MOVED
```

Deltas may be applied to a bounding box using the `+` operator:

```python
new_car_box = car_box + box_delta

print(new_car_box)
# BoundingBox(id=1, label='car', x=90.0, y=210.0, width=320.0, height=85.0)

print(new_car_box == corrected_car_box)
# True
```

Area may be computed from a bounding box:

```python
print(car_box.area)
# 24000.0
```

Intersection over union between bounding boxes can be computed using the `iou` method:

```python
car_iou = car_box.iou(corrected_car_box)

print(car_iou)
# 0.695364238410596
```

### Images

An `Image` is defined by an ID and a collection of bounding boxes.

```python
from boxdiff import Image
from uuid import UUID

image = Image(
    id=UUID('78d76772-4664-467c-ae88-a25496234966'),
    bounding_boxes=[car_box]
)
```

Likewise, equality can be checked using the `==` operator and deltas computed using the `-` operator:

```python
corrected_image = Image(
    id=UUID('78d76772-4664-467c-ae88-a25496234966'),
    bounding_boxes=[corrected_car_box]
)

image_delta = corrected_image - image

print(image_delta)
# ImageDelta(
#   id=0, 
#   boxes_added=[], 
#   boxes_removed=[], 
#   box_deltas=[
#     BoundingBoxDelta(
#       id=0, 
#       label_old='car', 
#       label_new='car', 
#       x_delta=-10.0, 
#       y_delta=10.0, 
#       width_delta=20.0, 
#       height_delta=5.0
#     )
#   ]
# )
```

Similarly, flags may be computed from the delta:

```python
print(image_delta.flags)
# ImageDifference.BOXES_MODIFIED
```

### Image Sets

An `ImageSet` is defined by an ID and a collection of images.

```python
from boxdiff import ImageSet

image_set = ImageSet(
    id='my_image_set',
    images=[image, ...]
)
```

Its syntax and structure is analogous to that of an `Image`.

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/kevinsbarnard/box-diff",
    "name": "boxdiff",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.10,<4.0",
    "maintainer_email": "",
    "keywords": "",
    "author": "Kevin Barnard",
    "author_email": "kbarnard@mbari.org",
    "download_url": "https://files.pythonhosted.org/packages/5e/4e/3946ae2c95d81034513d8c4e9dde55abb59e0ac0d9770e9d04c9069d368c/boxdiff-0.2.0.tar.gz",
    "platform": null,
    "description": "# box-diff\nUtilities for comparing bounding boxes\n\nAuthor: Kevin Barnard, [kbarnard@mbari.org](mailto:kbarnard@mbari.org)\n\n[![tests](https://github.com/kevinsbarnard/box-diff/workflows/tests/badge.svg)](https://github.com/kevinsbarnard/box-diff/actions/workflows/tests.yml)\n\n\n## Installation\n\nbox-diff is available on PyPI as [boxdiff](https://pypi.org/project/boxdiff/):\n\n```bash\npip install boxdiff\n```\n\n## Usage\n\nAll of box-diff is housed within the `boxdiff` package.\n\n```python\nimport boxdiff\n```\n\nThe core data models are defined in the `boxdiff.models` module. These are split into three groups:\n- `BoundingBox`: ID + labeled 2D bounding box\n- `Image`: ID + collection of bounding boxes\n- `ImageSet`: ID + collection of images\n\n*Note: IDs may be integers, UUIDs, or strings.*\n\nEach group has a data model (defined in `boxdiff.models.core`), a delta (`boxdiff.models.deltas`), and a difference flag (`boxdiff.models.flags`).\nThe data model represents the object and its attributes, whereas a delta represents the difference in attribute values between two objects.\nDifference flags represent the presence of attribute differences between two objects as derived from a delta object.\n\nAll of the data models are serializable to JSON. For example,\n```python\njson_str = bounding_box.to_json(indent=2)\n\nprint(json_str)\n```\nmight give\n```json\n{\n  \"id\": 0,\n  \"label\": \"label\",\n  \"x\": 0.0,\n  \"y\": 0.0,\n  \"width\": 1.0,\n  \"height\": 1.0\n}\n```\n\nSimilarly, data model objects may be parsed from JSON. For example,\n```python\nbounding_box = BoundingBox.from_json(json_str)\n\nprint(bounding_box)\n# BoundingBox(id=0, label='label', x=0.0, y=0.0, width=1.0, height=1.0)\n```\n\n### Bounding Boxes\n\nA `BoundingBox` is defined by an ID, a label, and a 2D box (x, y, width, height).\n\n```python\nfrom boxdiff import BoundingBox\n\ncar_box = BoundingBox(\n    id=0,\n    label='car',\n    x=100, y=200,\n    width=300, height=80\n)\n```\n\nEquality can be checked using the `==` operator:\n\n```python\nsame_car_box = BoundingBox(\n    id=0,\n    label='car',\n    x=100, y=200,\n    width=300, height=80\n)\n\nprint(car_box == same_car_box)\n# True\n\ncorrected_car_box = BoundingBox(\n    id=0,\n    label='car',\n    x=90, y=210,\n    width=320, height=85\n)\n\nprint(car_box == corrected_car_box)\n# False\n```\n\nA `BoundingBoxDelta` between two boxes can be computed with the `-` operator:\n\n```python\nbox_delta = corrected_car_box - car_box\n\nprint(box_delta)\n# BoundingBoxDelta(id=1, label_old='car', label_new='car', x_delta=-10.0, y_delta=10.0, width_delta=20.0, height_delta=5.0)\n```\n\n`BoundingBoxDifference` flags may then be computed from the delta:\n\n```python\nprint(box_delta.flags)\n# BoundingBoxDifference.RESIZED|MOVED\n```\n\nDeltas may be applied to a bounding box using the `+` operator:\n\n```python\nnew_car_box = car_box + box_delta\n\nprint(new_car_box)\n# BoundingBox(id=1, label='car', x=90.0, y=210.0, width=320.0, height=85.0)\n\nprint(new_car_box == corrected_car_box)\n# True\n```\n\nArea may be computed from a bounding box:\n\n```python\nprint(car_box.area)\n# 24000.0\n```\n\nIntersection over union between bounding boxes can be computed using the `iou` method:\n\n```python\ncar_iou = car_box.iou(corrected_car_box)\n\nprint(car_iou)\n# 0.695364238410596\n```\n\n### Images\n\nAn `Image` is defined by an ID and a collection of bounding boxes.\n\n```python\nfrom boxdiff import Image\nfrom uuid import UUID\n\nimage = Image(\n    id=UUID('78d76772-4664-467c-ae88-a25496234966'),\n    bounding_boxes=[car_box]\n)\n```\n\nLikewise, equality can be checked using the `==` operator and deltas computed using the `-` operator:\n\n```python\ncorrected_image = Image(\n    id=UUID('78d76772-4664-467c-ae88-a25496234966'),\n    bounding_boxes=[corrected_car_box]\n)\n\nimage_delta = corrected_image - image\n\nprint(image_delta)\n# ImageDelta(\n#   id=0, \n#   boxes_added=[], \n#   boxes_removed=[], \n#   box_deltas=[\n#     BoundingBoxDelta(\n#       id=0, \n#       label_old='car', \n#       label_new='car', \n#       x_delta=-10.0, \n#       y_delta=10.0, \n#       width_delta=20.0, \n#       height_delta=5.0\n#     )\n#   ]\n# )\n```\n\nSimilarly, flags may be computed from the delta:\n\n```python\nprint(image_delta.flags)\n# ImageDifference.BOXES_MODIFIED\n```\n\n### Image Sets\n\nAn `ImageSet` is defined by an ID and a collection of images.\n\n```python\nfrom boxdiff import ImageSet\n\nimage_set = ImageSet(\n    id='my_image_set',\n    images=[image, ...]\n)\n```\n\nIts syntax and structure is analogous to that of an `Image`.\n",
    "bugtrack_url": null,
    "license": "",
    "summary": "Utilities for comparing bounding boxes",
    "version": "0.2.0",
    "project_urls": {
        "Homepage": "https://github.com/kevinsbarnard/box-diff",
        "Repository": "https://github.com/kevinsbarnard/box-diff"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "dcbeacbd8b41e0d45cffe37ad341d9ef99464f61018a2aae41f61d8e4db00ab0",
                "md5": "52bd56ab23e7bede8b1c3daf15b241b4",
                "sha256": "e771da66a7b6c5cbeb7582a5e35eb0a43b814415d86b62fd5aa35c066f40f7ed"
            },
            "downloads": -1,
            "filename": "boxdiff-0.2.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "52bd56ab23e7bede8b1c3daf15b241b4",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10,<4.0",
            "size": 5626,
            "upload_time": "2024-02-01T22:19:39",
            "upload_time_iso_8601": "2024-02-01T22:19:39.169146Z",
            "url": "https://files.pythonhosted.org/packages/dc/be/acbd8b41e0d45cffe37ad341d9ef99464f61018a2aae41f61d8e4db00ab0/boxdiff-0.2.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "5e4e3946ae2c95d81034513d8c4e9dde55abb59e0ac0d9770e9d04c9069d368c",
                "md5": "0ea59bca178ee66d700dcf608744f968",
                "sha256": "02f1fbead0f9710b4260b71ed69be6b31d066c614efff439b0af6697ce7fef1a"
            },
            "downloads": -1,
            "filename": "boxdiff-0.2.0.tar.gz",
            "has_sig": false,
            "md5_digest": "0ea59bca178ee66d700dcf608744f968",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10,<4.0",
            "size": 4403,
            "upload_time": "2024-02-01T22:19:40",
            "upload_time_iso_8601": "2024-02-01T22:19:40.341201Z",
            "url": "https://files.pythonhosted.org/packages/5e/4e/3946ae2c95d81034513d8c4e9dde55abb59e0ac0d9770e9d04c9069d368c/boxdiff-0.2.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-02-01 22:19:40",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "kevinsbarnard",
    "github_project": "box-diff",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "boxdiff"
}
        
Elapsed time: 0.59397s