Skip to content

Commit

Permalink
fix converted bitmaps segmentations
Browse files Browse the repository at this point in the history
  • Loading branch information
vorozhkog committed Nov 8, 2024
1 parent 4de2dec commit 43cf691
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 56 deletions.
6 changes: 3 additions & 3 deletions local.env
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
TEAM_ID = 448
WORKSPACE_ID = 690
PROJECT_ID = 36688
TEAM_ID = 431
WORKSPACE_ID = 1019
PROJECT_ID = 42759

# options: "images" "annotations"
modal.state.selectedOutput="images"
Expand Down
32 changes: 22 additions & 10 deletions src/convert_geometry.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import supervisely as sly
from supervisely.annotation.json_geometries_map import GET_GEOMETRY_FROM_STR
from supervisely.geometry import polyline, rectangle
from supervisely.geometry import polyline, rectangle, bitmap
from supervisely.sly_logger import logger

from typing import List

def prepare_meta(meta: sly.ProjectMeta):
new_classes = []
Expand All @@ -21,31 +21,43 @@ def prepare_meta(meta: sly.ProjectMeta):
return meta


def convert_w_binding_key(label, new_obj_class: sly.ObjClass, binding_key=None) -> List:
labels = []
geometries = label.geometry.convert(new_obj_class.geometry_type)
for g in geometries:
labels.append(label.clone(geometry=g, obj_class=new_obj_class, binding_key=binding_key))
return labels


def convert_annotation(ann_info, img_info, src_meta, dst_meta, rectangle_mark):
try:
ann = sly.Annotation.from_json(ann_info.annotation, src_meta)
except Exception as e:
sly.logger.debug(f"Exception while creating sly.Annotation from JSON: {e}")
return sly.Annotation((img_info.height, img_info.width))
new_labels = []
for lbl in ann.labels:

for idx, label in enumerate(ann.labels):
try:
new_cls = dst_meta.obj_classes.get(lbl.obj_class.name)
if lbl.obj_class.geometry_type == new_cls.geometry_type:
new_labels.append(lbl)
new_cls = dst_meta.obj_classes.get(label.obj_class.name)
if label.obj_class.geometry_type == new_cls.geometry_type:
new_labels.append(label)
else:
converted_label = lbl.convert(new_cls)
if lbl.obj_class.geometry_type == polyline.Polyline:
binding_key = None
if label.obj_class.geometry_type == bitmap.Bitmap:
binding_key = f"{label.obj_class.name}_label_{idx}"
converted_label = convert_w_binding_key(label, new_cls, binding_key)
if label.obj_class.geometry_type == polyline.Polyline:
raise NotImplementedError("Shape Polyline is not supported")
if lbl.obj_class.geometry_type == rectangle.Rectangle:
if label.obj_class.geometry_type == rectangle.Rectangle:
new_descr = converted_label[0].description + " " + rectangle_mark
new_label = converted_label[0].clone(description=new_descr)
converted_label.pop()
converted_label.append(new_label)
new_labels.extend(converted_label)
except NotImplementedError:
logger.warning(
f"Unsupported conversion of annotation '{lbl.obj_class.geometry_type.name()}' type to '{new_cls.geometry_type.name()}'. Skipping annotation with [ID: {lbl.to_json()['id']}]",
f"Unsupported conversion of annotation '{label.obj_class.geometry_type.name()}' type to '{new_cls.geometry_type.name()}'. Skipping annotation with [ID: {label.to_json()['id']}]",
exc_info=False,
)
continue
Expand Down
124 changes: 81 additions & 43 deletions src/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import supervisely as sly
from supervisely.geometry import bitmap
from supervisely.io.fs import mkdir
from typing import List, Union

incremental_id = 0

Expand Down Expand Up @@ -76,6 +77,18 @@ def create_coco_dataset(coco_dataset_dir):
return img_dir, ann_dir


def get_bbox_labels(bbox_points: List[List[int, int]]) -> List[List[int, int]]:
"""
A helper function to convert list of bbox points into a bbox which contains them all
"""
min_x = min(bbox[0][0] for bbox in bbox_points)
min_y = min(bbox[0][1] for bbox in bbox_points)
max_x = max(bbox[1][0] for bbox in bbox_points)
max_y = max(bbox[1][1] for bbox in bbox_points)

return [[min_x, min_y], [max_x, max_y]]


def create_coco_annotation(
categories_mapping,
image_infos,
Expand All @@ -89,6 +102,7 @@ def create_coco_annotation(
rectangle_mark,
):
global incremental_id
incremental_id += 1
for image_info, ann in zip(image_infos, anns):
image_coco_ann = dict(
license="None",
Expand All @@ -104,53 +118,77 @@ def create_coco_annotation(
if coco_captions is not None and include_captions:
coco_captions["images"].append(image_coco_ann)

for label in ann.labels:
if rectangle_mark in label.description:
segmentation = []
elif label.geometry.name() == bitmap.Bitmap.name():
segmentation = extend_mask_up_to_image(
label.geometry.data,
(image_info.height, image_info.width),
label.geometry.origin,
)
segmentation = coco_segmentation_rle(segmentation)
else:
segmentation = label.geometry.to_json()["points"]["exterior"]
segmentation = [coco_segmentation(segmentation)]

bbox = label.geometry.to_bbox().to_json()["points"]["exterior"]
bbox = coco_bbox(bbox)

label_id += 1
coco_ann["annotations"].append(
dict(
segmentation=segmentation, # a list of polygon vertices around the object, but can also be a run-length-encoded (RLE) bit mask
area=label.geometry.area, # Area is measured in pixels (e. a 10px by 20px box would have an area of 200)
iscrowd=0, # Is Crowd specifies whether the segmentation is for a single object or for a group/cluster of objects
image_id=incremental_id, # The image id corresponds to a specific image in the dataset
bbox=bbox, # he COCO bounding box format is [top left x position, top left y position, width, height]
category_id=categories_mapping[
label.obj_class.name
], # The category id corresponds to a single category specified in the categories section
id=label_id, # Each annotation also has an id (unique to all other annotations in the dataset)
groups = ann.get_bindings()

for binding_key, labels in groups.items():
labels: List[sly.Label]
if binding_key is not None: # -> converted bitmap labels
to_segm = lambda x: x.geometry.to_json()["points"]["exterior"]
segmentation = [coco_segmentation(to_segm(label)) for label in labels]
bbox_points = [l.geometry.to_bbox().to_json()["points"]["exterior"] for l in labels]
bbox = coco_bbox(get_bbox_labels(bbox_points))
label_id += 1
coco_ann["annotations"].append(
dict(
segmentation=segmentation, # a list of polygon vertices around the object, but can also be a run-length-encoded (RLE) bit mask
area=sum(
[label.area for label in labels]
), # Area is measured in pixels (e. a 10px by 20px box would have an area of 200)
iscrowd=0, # Is Crowd specifies whether the segmentation is for a single object or for a group/cluster of objects
image_id=incremental_id, # The image id corresponds to a specific image in the dataset
bbox=bbox, # he COCO bounding box format is [top left x position, top left y position, width, height]
category_id=categories_mapping[
labels[0].obj_class.name
], # The category id corresponds to a single category specified in the categories section
id=label_id, # Each annotation also has an id (unique to all other annotations in the dataset)
)
)
)
if coco_captions is not None and include_captions:
for tag in ann.img_tags:
if (
tag.meta.name == "caption"
and tag.meta.value_type == sly.TagValueType.ANY_STRING
):
caption_id += 1
coco_captions["annotations"].append(
else: # -> other labels such as rectangles and polygons
for label in labels:
if rectangle_mark in label.description:
segmentation = []
# elif (
# label.geometry.name() == bitmap.Bitmap.name()
# ): # There are no bitmap labels, as they are converted into polygons in advance? Most likely redundant code
# segmentation = extend_mask_up_to_image(
# label.geometry.data,
# (image_info.height, image_info.width),
# label.geometry.origin,
# )
# segmentation = coco_segmentation_rle(segmentation)

bbox = label.geometry.to_bbox().to_json()["points"]["exterior"]
bbox = coco_bbox(bbox)

label_id += 1
coco_ann["annotations"].append(
dict(
image_id=incremental_id,
id=caption_id,
caption=tag.value,
segmentation=segmentation, # a list of polygon vertices around the object, but can also be a run-length-encoded (RLE) bit mask
area=label.geometry.area, # Area is measured in pixels (e. a 10px by 20px box would have an area of 200)
iscrowd=0, # Is Crowd specifies whether the segmentation is for a single object or for a group/cluster of objects
image_id=incremental_id, # The image id corresponds to a specific image in the dataset
bbox=bbox, # he COCO bounding box format is [top left x position, top left y position, width, height]
category_id=categories_mapping[
label.obj_class.name
], # The category id corresponds to a single category specified in the categories section
id=label_id, # Each annotation also has an id (unique to all other annotations in the dataset)
)
)
progress.iter_done_report()
incremental_id += 1
if coco_captions is not None and include_captions:
for tag in ann.img_tags:
if (
tag.meta.name == "caption"
and tag.meta.value_type == sly.TagValueType.ANY_STRING
):
caption_id += 1
coco_captions["annotations"].append(
dict(
image_id=incremental_id,
id=caption_id,
caption=tag.value,
)
)
progress.iter_done_report()
return coco_ann, label_id, coco_captions, caption_id


Expand Down

0 comments on commit 43cf691

Please sign in to comment.