sidescanpy.export.ml.coco#

COCO-format export for sonar targets.

Scoped to JSF for now: one canonical crop image + one bounding-box annotation per target, single category (no real class labels are assumed — Description/Tag are commonly empty), defaulting to min_confidence="verified" so a dataset export can’t silently ship unlocalized or low-confidence boxes.

The bbox itself is a fixed placeholder size (box_size), not a measured target dimension — no source catalog seen so far has real LengthMeters/WidthMeters data. This is recorded in the written JSON’s own info.description so the caveat travels with the file, not just with whatever presentation wraps it.

2026 rshomberg@uri.edu

Contents

CocoImageEntry

One target's canonical crop, ready to become a COCO image+annotation.

resolve_categories

Ordered class names for entries (index + 1 is the COCO id, index is the YOLO class).

write_coco

Write entries to output_path as a COCO-format JSON dataset.

class sidescanpy.export.ml.coco.CocoImageEntry(target, file_name, width, height, bbox_size=None)#

Bases: object

One target’s canonical crop, ready to become a COCO image+annotation.

Multiple entries may share the same file_name — e.g. every cataloged target that falls within one exported window (see sidescanpy.export.windows.targets_within_window). They become one shared COCO image record with one annotation per entry, rather than one image per target. Every entry sharing a file_name must agree on width/height (the same physical image).

bbox_size, if given, overrides write_coco/write_yolo’s global box_size for this entry only — for a real, measured target extent instead of the shared placeholder.

target=None records an image with no annotations (a background image): COCO gets the image record alone, YOLO an empty label file. Such entries bypass the confidence filter.

sidescanpy.export.ml.coco.resolve_categories(entries, category_name='target', categories=None)#

Ordered class names for entries (index + 1 is the COCO id, index is the YOLO class).

Uncategorized targets (Target.category is None) belong to category_name. With no explicit categories: the sorted set of names present (just [category_name] when nothing is categorized). With an explicit ordered categories list, that list is returned as-is so ids stay stable across separately-exported datasets.

Raises:
ValueError

If categories has duplicates, or a target’s category is not in it.

sidescanpy.export.ml.coco.write_coco(entries, output_path, *, category_name='target', box_size=(40.0, 40.0), min_confidence='verified', categories=None)#

Write entries to output_path as a COCO-format JSON dataset.

Per-annotation class comes from Target.category (None -> category_name). The categories list is the sorted set of names present with ids 1..N, or, if categories is given, that explicit ordered list (see resolve_categories()). With no categorized targets the output is the single category_name category, id 1.

Only targets with position_confidence at or above min_confidence (ordered unknown < approximate < verified) are included — pass min_confidence="approximate" or "unknown" explicitly to include lower-confidence targets; this must be an opt-in, not the default, per the design doc’s own rationale (a prior export in a sibling project shipped an unverified/wrong bounding-box hypothesis by not gating on this).

Entries sharing a file_name become one image with multiple annotations (see CocoImageEntry’s own docstring) — each entry’s own bbox_size (if set) is used for its box, else the shared box_size. An entry with target=None adds its image with no annotation.

Returns the dict that was written, for inline inspection/testing.

Raises:
ValueError

If two entries share a file_name but disagree on width/height.