from .bounding_box import BoundingBox
from iaa_od.utils import load_categories_dictionary, json_to_int_list
from dataclasses import InitVar, dataclass, field
from typing import Optional
[docs]
@dataclass(slots=True, kw_only=True)
class Annotation:
"""
Represents a single annotation in a Ground Truth JSON file.
Attributes:
gt_filepath (str): Path to the Ground Truth JSON file.
gt_name (str): Name of the Ground Truth dataset.
id (str): Unique identifier for the annotation.
category_id (int): Category ID of the annotated object.
image_id (str): Identifier of the image containing the annotation.
bbox_coords (BoundingBox): Bounding box coordinates of the annotation.
image_name (Optional[str]): Filename of the image (if available).
source_file (Optional[str]): Source file from which the annotation was derived (if available).
unit_id (Optional[int]): Identifier of the unit this annotation belongs to (if units were computed).
"""
# Ground Truth properties
gt_filepath: str
gt_name: str
# Annotation properties
id: str = field(init=False)
category_id: int = field(init=False)
image_id: str = field(init=False)
bbox_coords: BoundingBox = field(init=False)
# Additional properties
image_name: Optional[str] = None
source_file: Optional[str] = field(default=None, init=False)
unit_id: Optional[int] = field(default=None, init=False)
@property
def unique_id(self) -> str:
"""
Generate a unique identifier for the annotation by combining the Ground Truth name and the annotation ID.
Returns:
str: A unique identifier for the annotation.
"""
return f"{self.gt_name}_{self.id}"
# Init-only fields
annotation: InitVar[dict[str, str]]
image_height: InitVar[Optional[int]] = None
def __post_init__(self, annotation: dict[str, str], image_height: Optional[int]):
self.id = annotation["id"]
self.category_id = int(annotation["category_id"])
self.image_id = annotation["image_id"]
self.bbox_coords = BoundingBox(input_coords=json_to_int_list(annotation["bbox"]), image_height=image_height)
if not self.image_name:
self.image_name = annotation.get("image_name")
self.source_file = annotation.get("source_file")
def __str__(self):
categories_dict = load_categories_dictionary(self.gt_filepath)
annotation_string = "Annotation ID: " + str(self.id) + "\n"
annotation_string += "\tCategory in annotation: " + categories_dict[self.category_id] + "\n"
annotation_string += "\tImage ID: " + str(self.image_id) + "\n"
annotation_string += "\tBounding box coordinates: " + self.bbox_coords.__str__() + "\n"
if self.image_name:
annotation_string += "\tImage filename: " + self.image_name + "\n"
if self.source_file:
annotation_string += "\tSource file for GT: " + self.source_file + "\n"
return annotation_string