Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FR] Support non-binary/grayscale masks in fo.Detection #4961

Open
3 of 6 tasks
Laurent2916 opened this issue Oct 22, 2024 · 5 comments
Open
3 of 6 tasks

[FR] Support non-binary/grayscale masks in fo.Detection #4961

Laurent2916 opened this issue Oct 22, 2024 · 5 comments
Labels
feature Work on a feature request

Comments

@Laurent2916
Copy link
Contributor

Proposal Summary

Currently fo.Detection supports:

an instance segmentation mask for the detection within its bounding box, which should be a 2D binary or 0/1 integer numpy array

In practice it is possible to store a [0, 1] float numpy array (i.e. a continuous mask), since there doesn't seem to be checks in place to prevent that. This is very useful when using/training segmentation models that operate on such continuous masks (i.e. non binary/thresholded masks) like MVANet, RMBG-1.4, BiRefNet, etc.

I was wondering if supporting continuous mask would be feasible in Fiftyone, because continuous masks currently are thresholded (at 0) in the UI, which often makes visualizing them difficult. Having the ability to enable, disable and change the threshold value in the UI would be very useful.

Note: Using continuous masks probably breaks some methods such as to_polyline and to_segmentation, though I don't use them often so I don't know.

What areas of FiftyOne does this feature affect?

  • App: FiftyOne application
  • Core: Core fiftyone Python library
  • Server: FiftyOne server

Willingness to contribute

The FiftyOne Community welcomes contributions! Would you or another member of your organization be willing to contribute an implementation of this feature?

  • Yes. I can contribute this feature independently
  • Yes. I would be willing to contribute this feature with guidance from the FiftyOne community
  • No. I cannot contribute this feature at this time
@Laurent2916 Laurent2916 added the feature Work on a feature request label Oct 22, 2024
@deltheil
Copy link

[...] continuous masks currently are thresholded (at 0) in the UI [...] Having the ability to enable, disable and change the threshold value in the UI would be very useful.

I had a look at the Looker package which takes care of this. So roughly:

  • The FiftyOne server graphql API returns masks as they are stored in Mongo, i.e. base64-encoded and zlib compressed numpy format (e.g. see mainSampleQuery)
  • They are deserialized client-side part of numpy.ts
  • There is a corresponding painter which prepares the overlay pixels drawn in a HTML canvas

FWIW, I have tested this quick-n-dirty patch which is enough in our case (but this is a poor man solution):

--- a/app/packages/looker/src/numpy.ts
+++ b/app/packages/looker/src/numpy.ts
@@ -158,6 +158,13 @@ function parse(array: Uint8Array): OverlayMask {
           rawData.byteLength / ArrayType.BYTES_PER_ELEMENT
         );

+  // Binarize mask with a hard coded threshold (= 127)
+  if (ArrayType === Uint8Array) {
+    for (let i = 0; i < typedData.length; i++) {
+      typedData[i] = typedData[i] >= 127 ? 255 : 0;
+    }
+  }
+
   return {
     arrayType: typedData.constructor.name,
     buffer: typedData.buffer,

Ideally, it would be great if the Segmentation painter (from PainterFactory) could take care of this and thus accept additional arguments to pass an optional threshold and/or adjust mask opacity (alpha matting). Of course, the UI should expose these additional options.

cc @brimoor does that make sense? Could we achieve something similar via the plugins framework?

@brimoor
Copy link
Contributor

brimoor commented Nov 14, 2024

cc @benjaminpkane @sashankaryal: I'm onboard with supporting floating point instance masks. What do you think?

@benjaminpkane
Copy link
Contributor

I defer to @sashankaryal

@sashankaryal
Copy link
Contributor

I'm open to it. With the work we did in #5120, it should be an easy lift. I'll own it.

@deltheil
Copy link

I'm open to it. With the work we did in #5120, it should be an easy lift. I'll own it.

That's great!

Just to be clear re: continuous masks, and to avoid any ambiguity w.r.t. "floating point" instance masks. In our case, we are currently storing masks with dtype=np.uint8 in the fiftyone.core.labels.Detection.mask field (i.e. with (integer) values between 0 and 255, instead of just 0/1). This works like a charm generally speaking.

As stated above, we would greatly benefit from 1st class citizen support of such masks within the Looker package and on the UI side:

Having the ability to enable, disable and change the threshold value in the UI would be very useful.

Hope that helps.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Work on a feature request
Projects
None yet
Development

No branches or pull requests

5 participants