diff --git a/labelbox/data/annotation_types/geometry/mask.py b/labelbox/data/annotation_types/geometry/mask.py index b184017f5..a18613af3 100644 --- a/labelbox/data/annotation_types/geometry/mask.py +++ b/labelbox/data/annotation_types/geometry/mask.py @@ -54,6 +54,13 @@ def geometry(self) -> Dict[str, Tuple[int, int, int]]: external_polygons = self._extract_polygons_from_contours( external_contours) holes = self._extract_polygons_from_contours(holes) + + if not external_polygons.is_valid: + external_polygons = external_polygons.buffer(0) + + if not holes.is_valid: + holes = holes.buffer(0) + return external_polygons.difference(holes).__geo_interface__ def draw(self, @@ -78,7 +85,6 @@ def draw(self, np.ndarray representing only this object as opposed to the mask that this object references which might have multiple objects determined by colors """ - mask = self.mask.value mask = np.alltrue(mask == self.color, axis=2).astype(np.uint8) diff --git a/labelbox/data/serialization/coco/instance_dataset.py b/labelbox/data/serialization/coco/instance_dataset.py index f5ab45a10..d5568f299 100644 --- a/labelbox/data/serialization/coco/instance_dataset.py +++ b/labelbox/data/serialization/coco/instance_dataset.py @@ -21,7 +21,6 @@ def mask_to_coco_object_annotation( # This is going to fill any holes into the multipolygon # If you need to support holes use the panoptic data format shapely = annotation.value.shapely.simplify(1).buffer(0) - if shapely.is_empty: return diff --git a/labelbox/data/serialization/coco/panoptic_dataset.py b/labelbox/data/serialization/coco/panoptic_dataset.py index 6226e40a2..aa2cf6cbd 100644 --- a/labelbox/data/serialization/coco/panoptic_dataset.py +++ b/labelbox/data/serialization/coco/panoptic_dataset.py @@ -22,7 +22,11 @@ def vector_to_coco_segment_info(canvas: np.ndarray, annotation: ObjectAnnotation, annotation_idx: int, image: CocoImage, category_id: int): + shapely = annotation.value.shapely + if shapely.is_empty: + return + xmin, ymin, xmax, ymax = shapely.bounds canvas = annotation.value.draw(height=image.height, width=image.width, @@ -40,6 +44,9 @@ def mask_to_coco_segment_info(canvas: np.ndarray, annotation, color = id_to_rgb(annotation_idx) mask = annotation.value.draw(color=color) shapely = annotation.value.shapely + if shapely.is_empty: + return + xmin, ymin, xmax, ymax = shapely.bounds canvas = np.where(canvas == (0, 0, 0), mask, canvas) return SegmentInfo(id=annotation_idx, @@ -70,20 +77,32 @@ def process_label(label: Label, for annotation_idx, annotation in enumerate(annotations[class_name]): categories[annotation.name] = hash_category_name(annotation.name) if isinstance(annotation.value, Mask): - segment, canvas = (mask_to_coco_segment_info( + coco_segment_info = mask_to_coco_segment_info( canvas, annotation, class_idx + 1, - categories[annotation.name])) + categories[annotation.name]) + + if coco_segment_info is None: + # Filter out empty masks + continue + + segment, canvas = coco_segment_info segments.append(segment) is_thing[annotation.name] = 0 elif isinstance(annotation.value, (Polygon, Rectangle)): - segment, canvas = vector_to_coco_segment_info( + coco_vector_info = vector_to_coco_segment_info( canvas, annotation, annotation_idx=(class_idx if all_stuff else annotation_idx) + 1, image=image, category_id=categories[annotation.name]) + + if coco_segment_info is None: + # Filter out empty annotations + continue + + segment, canvas = coco_vector_info segments.append(segment) is_thing[annotation.name] = 1 - int(all_stuff)