Load COCO annotations and convert them to `Detections`. If `force_masks` is `False`, masks are still loaded for images whose annotations include a `segmentation` field. This keeps mask handling consistent with other dataset loaders that infer masks from annotation content. Arg
(
images_directory_path: str,
annotations_path: str,
force_masks: bool = False,
use_iscrowd: bool = True,
)
| 394 | |
| 395 | |
| 396 | def load_coco_annotations( |
| 397 | images_directory_path: str, |
| 398 | annotations_path: str, |
| 399 | force_masks: bool = False, |
| 400 | use_iscrowd: bool = True, |
| 401 | ) -> tuple[list[str], list[str], dict[str, Detections]]: |
| 402 | """ |
| 403 | Load COCO annotations and convert them to `Detections`. |
| 404 | |
| 405 | If `force_masks` is `False`, masks are still loaded for images whose annotations |
| 406 | include a `segmentation` field. This keeps mask handling consistent with other |
| 407 | dataset loaders that infer masks from annotation content. |
| 408 | |
| 409 | Args: |
| 410 | images_directory_path: Path to the image directory. |
| 411 | annotations_path: Path to COCO JSON annotations. |
| 412 | force_masks: If `True`, always attempt to load masks. |
| 413 | use_iscrowd: If `True`, include `iscrowd` and `area` in detection data. |
| 414 | |
| 415 | Returns: |
| 416 | A tuple of `(classes, image_paths, annotations)`. |
| 417 | |
| 418 | Raises: |
| 419 | ValueError: If any annotation's ``file_name`` resolves to the images |
| 420 | directory itself, to a path outside the images directory (e.g. via |
| 421 | ``../`` traversal or an absolute path), or to a subdirectory instead |
| 422 | of a regular image file. |
| 423 | |
| 424 | Note: |
| 425 | Each annotation's ``file_name`` is validated against |
| 426 | ``images_directory_path`` before loading. Annotations that reference |
| 427 | paths outside the directory are rejected to prevent path-traversal |
| 428 | attacks when loading user-supplied annotation files. Symlinked images |
| 429 | pointing outside the resolved images directory are also rejected. |
| 430 | """ |
| 431 | coco_data = read_json_file(file_path=annotations_path) |
| 432 | classes = coco_categories_to_classes(coco_categories=coco_data["categories"]) |
| 433 | |
| 434 | class_index_mapping = build_coco_class_index_mapping( |
| 435 | coco_categories=coco_data["categories"], target_classes=classes |
| 436 | ) |
| 437 | |
| 438 | coco_images = coco_data["images"] |
| 439 | coco_annotations_groups = group_coco_annotations_by_image_id( |
| 440 | coco_annotations=coco_data["annotations"] |
| 441 | ) |
| 442 | |
| 443 | images = [] |
| 444 | annotations = {} |
| 445 | images_directory_resolved = Path(images_directory_path).resolve() |
| 446 | |
| 447 | for coco_image in coco_images: |
| 448 | image_name, image_width, image_height = ( |
| 449 | coco_image["file_name"], |
| 450 | coco_image["width"], |
| 451 | coco_image["height"], |
| 452 | ) |
| 453 | image_annotations = coco_annotations_groups.get(coco_image["id"], []) |