diff --git a/src/superannotate/lib/app/input_converters/converters/coco_converters/sa_vector_to_coco.py b/src/superannotate/lib/app/input_converters/converters/coco_converters/sa_vector_to_coco.py index b546d57a..29d836ed 100644 --- a/src/superannotate/lib/app/input_converters/converters/coco_converters/sa_vector_to_coco.py +++ b/src/superannotate/lib/app/input_converters/converters/coco_converters/sa_vector_to_coco.py @@ -40,7 +40,12 @@ def sa_vector_to_coco_object_detection( points["y2"] - points["y1"], ) polygons = bbox - area = int((points["x2"] - points["x1"]) * points["y2"] - points["y1"]) + # COCO bbox area is width * height. `bbox` is already + # (x, y, width, height), so reuse it — the previous expression + # `(x2 - x1) * y2 - y1` was mis-parenthesized (operator precedence made + # it `((x2 - x1) * y2) - y1`), producing a wrong area for every box not + # touching the top edge. Mirrors the keypoint path's `bbox[2] * bbox[3]`. + area = int(bbox[2] * bbox[3]) annotation = make_annotation( category_id, image_info["id"], bbox, polygons, area, anno_id diff --git a/tests/unit/test_coco_object_detection_area.py b/tests/unit/test_coco_object_detection_area.py new file mode 100644 index 00000000..10beb04b --- /dev/null +++ b/tests/unit/test_coco_object_detection_area.py @@ -0,0 +1,39 @@ +from types import SimpleNamespace + +from src.superannotate.lib.app.input_converters.converters.coco_converters.sa_vector_to_coco import ( # noqa: E501 + sa_vector_to_coco_object_detection, +) + + +def test_object_detection_area_is_width_times_height(): + """COCO bbox `area` must be width * height. + + Regression for an operator-precedence bug: `area` was computed as + `(x2 - x1) * y2 - y1`, i.e. `((x2 - x1) * y2) - y1`, instead of + `(x2 - x1) * (y2 - y1)`. For the box below (from the repo's own export + golden fixture) the old expression yields 9682 while the correct area is 437. + """ + captured = {} + + def make_annotation(category_id, image_id, bbox, segmentation, area, anno_id): + captured["bbox"] = bbox + captured["area"] = area + return {"id": anno_id, "bbox": bbox, "area": area} + + image_commons = SimpleNamespace(image_info={"id": 1}) + instances = [ + { + "type": "bbox", + "classId": 5, + "points": {"x1": 437.16, "y1": 341.5, "x2": 465.23, "y2": 357.09}, + } + ] + + _, annotations = sa_vector_to_coco_object_detection( + make_annotation, image_commons, instances, iter([1]) + ) + + assert len(annotations) == 1 + width, height = captured["bbox"][2], captured["bbox"][3] + assert captured["area"] == int(width * height) + assert captured["area"] == 437 # not the buggy 9682