Skip to content

Commit

Permalink
Merge pull request #4693 from Laurent2916/mask_path_detection
Browse files Browse the repository at this point in the history
add `mask_path` to `fo.Detection` labels: sdk
  • Loading branch information
sashankaryal authored Nov 15, 2024
2 parents 887fb57 + b0147a0 commit 7e2e35e
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 5 deletions.
60 changes: 59 additions & 1 deletion fiftyone/core/labels.py
Original file line number Diff line number Diff line change
Expand Up @@ -401,18 +401,75 @@ class Detection(_HasAttributesDict, _HasID, Label):
mask (None): an instance segmentation mask for the detection within
its bounding box, which should be a 2D binary or 0/1 integer numpy
array
mask_path (None): the absolute path to the instance segmentation image
on disk
confidence (None): a confidence in ``[0, 1]`` for the detection
index (None): an index for the object
attributes ({}): a dict mapping attribute names to :class:`Attribute`
instances
"""

_MEDIA_FIELD = "mask_path"

label = fof.StringField()
bounding_box = fof.ListField(fof.FloatField())
mask = fof.ArrayField()
mask_path = fof.StringField()
confidence = fof.FloatField()
index = fof.IntField()

@property
def has_mask(self):
"""Whether this instance has a mask."""
return self.mask is not None or self.mask_path is not None

def get_mask(self):
"""Returns the segmentation mask for this instance.
Returns:
a numpy array, or ``None``
"""
if self.mask is not None:
return self.mask

if self.mask_path is not None:
return _read_mask(self.mask_path)

return None

def import_mask(self, update=False):
"""Imports this instance's mask from disk to its :attr:`mask`
attribute.
Args:
outpath: the path to write the map
update (False): whether to clear this instance's :attr:`mask_path`
attribute after importing
"""
if self.mask_path is not None:
self.mask = _read_mask(self.mask_path)

if update:
self.mask_path = None

def export_mask(self, outpath, update=False):
"""Exports this instance's mask to the given path.
Args:
outpath: the path to write the mask
update (False): whether to clear this instance's :attr:`mask`
attribute and set its :attr:`mask_path` attribute when
exporting in-database segmentations
"""
if self.mask_path is not None:
etau.copy_file(self.mask_path, outpath)
else:
_write_mask(self.mask, outpath)

if update:
self.mask = None
self.mask_path = outpath

def to_polyline(self, tolerance=2, filled=True):
"""Returns a :class:`Polyline` representation of this instance.
Expand Down Expand Up @@ -467,7 +524,8 @@ def to_segmentation(self, mask=None, frame_size=None, target=255):
Returns:
a :class:`Segmentation`
"""
if self.mask is None:
mask = self.get_mask()
if mask is None:
raise ValueError(
"Only detections with their `mask` attributes populated can "
"be converted to segmentations"
Expand Down
4 changes: 2 additions & 2 deletions fiftyone/utils/coco.py
Original file line number Diff line number Diff line change
Expand Up @@ -1304,7 +1304,7 @@ def from_label(
x, y, w, h = label.bounding_box
bbox = [x * width, y * height, w * width, h * height]

if label.mask is not None:
if label.has_mask() is not None:
segmentation = _instance_to_coco_segmentation(
label, frame_size, iscrowd=iscrowd, tolerance=tolerance
)
Expand Down Expand Up @@ -2116,7 +2116,7 @@ def _coco_objects_to_detections(
)

if detection is not None and (
not load_segmentations or detection.mask is not None
not load_segmentations or detection.has_mask() is not None
):
detections.append(detection)

Expand Down
2 changes: 1 addition & 1 deletion fiftyone/utils/cvat.py
Original file line number Diff line number Diff line change
Expand Up @@ -6400,7 +6400,7 @@ def _create_detection_shapes(
}
)
elif label_type in ("instance", "instances"):
if det.mask is None:
if det.has_mask() is None:
continue

polygon = det.to_polyline()
Expand Down
2 changes: 1 addition & 1 deletion fiftyone/utils/eta.py
Original file line number Diff line number Diff line change
Expand Up @@ -596,7 +596,7 @@ def to_detected_object(detection, name=None, extra_attrs=True):
bry = tly + h
bounding_box = etag.BoundingBox.from_coords(tlx, tly, brx, bry)

mask = detection.mask
mask = detection.get_mask()
confidence = detection.confidence

attrs = _to_eta_attributes(detection, extra_attrs=extra_attrs)
Expand Down

0 comments on commit 7e2e35e

Please sign in to comment.