Package: boxdiff
box-diffUtilities for comparing bounding boxesAuthor: Kevin Barnard,kbarnard@mbari.orgInstallationbox-diff is available on PyPI asboxdiff:pipinstallboxdiffUsageAll of box-diff is housed within theboxdiffpackage.importboxdiffThe core data models are defined in theboxdiff.modelsmodule. These are split into three groups:BoundingBox: ID + labeled 2D bounding boxImage: ID + collection of bounding boxesImageSet: ID + collection of imagesNote: IDs may be integers, UUIDs, or strings.Each group has a data model (defined inboxdiff.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,json_str=bounding_box.to_json(indent=2)print(json_str)might give{"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,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 BoxesABoundingBoxis defined by an ID, a label, and a 2D box (x, y, width, height).fromboxdiffimportBoundingBoxcar_box=BoundingBox(id=0,label='car',x=100,y=200,width=300,height=80)Equality can be checked using the==operator:same_car_box=BoundingBox(id=0,label='car',x=100,y=200,width=300,height=80)print(car_box==same_car_box)# Truecorrected_car_box=BoundingBox(id=0,label='car',x=90,y=210,width=320,height=85)print(car_box==corrected_car_box)# FalseABoundingBoxDeltabetween two boxes can be computed with the-operator:box_delta=corrected_car_box-car_boxprint(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)BoundingBoxDifferenceflags may then be computed from the delta:print(box_delta.flags)# BoundingBoxDifference.RESIZED|MOVEDDeltas may be applied to a bounding box using the+operator:new_car_box=car_box+box_deltaprint(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)# TrueArea may be computed from a bounding box:print(car_box.area)# 24000.0Intersection over union between bounding boxes can be computed using theioumethod:car_iou=car_box.iou(corrected_car_box)print(car_iou)# 0.695364238410596ImagesAnImageis defined by an ID and a collection of bounding boxes.fromboxdiffimportImagefromuuidimportUUIDimage=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:corrected_image=Image(id=UUID('78d76772-4664-467c-ae88-a25496234966'),bounding_boxes=[corrected_car_box])image_delta=corrected_image-imageprint(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:print(image_delta.flags)# ImageDifference.BOXES_MODIFIEDImage SetsAnImageSetis defined by an ID and a collection of images.fromboxdiffimportImageSetimage_set=ImageSet(id='my_image_set',images=[image,...])Its syntax and structure is analogous to that of anImage.