Open brimoor opened 2 years ago
For context, currently the only way to customize field colors is through configuring the color pool, which can be done both for the App and when using draw_labels()
, but one doesn't have control over which color is selected for each field:
import eta.core.annotations as etaa
import fiftyone as fo
import fiftyone.utils.annotations as foua
import fiftyone.zoo as foz
dataset = foz.load_zoo_dataset("quickstart")
#
# Option 1: tell the App to use a specific color pool
#
app_config = fo.AppConfig()
app_config.color_pool = ["#FF0000", "#00FF00", "#0000FF"]
session = fo.launch_app(dataset, config=app_config)
#
# Option 2: tell `draw_labels()` to use a specific color pool
#
# Manual colormap
colormap_config = etaa.ColormapConfig(
{
"type": "eta.core.annotations.ManualColormap",
"config": {"colors": ["#FF0000", "#00FF00", "#0000FF"]}
}
)
# Also customize look-and-feel for fun
draw_config = foua.DrawConfig(
{
"show_all_confidences": True,
"per_object_label_colors": False,
"show_object_names": False,
"show_object_attrs": False,
}
)
dataset.limit(10).draw_labels(
"/tmp/quickstart/",
label_fields=["ground_truth", "predictions"],
config=draw_config,
colormap_config=colormap_config,
overwrite=True,
)
Another look and feel customization that has been requested is to be able to specify the width of bounding box lines. This can be useful depending on the clutter of detections in samples, or if working with small objects.
Hello @brimoor, you mentioned in #1515 that this FR might be implemented soon. Has there been any start or preparation for the implementation or are you open to pull requests?
any update on this?
I have similar issue for cutomizing colors (https://github.com/voxel51/fiftyone/issues/3410)
@twmht yes, it's released in 0.21. https://docs.voxel51.com/user_guide/app.html#color-schemes-in-the-app
@lanzhenw
it's great to see that. Would you help me to check if this (https://github.com/voxel51/fiftyone/issues/3410) is a bug or not? I think the number of default color pools is enough for 3 classses.
@brimoor Is it possible to use this feature for fo.Segmentation
as well?
Because my mask's values are based on the instance id number instead of class id.
Example:
My mask is a 2D array with 0 for background(transparent).
And 1,2,3.... for the regions of the 1st,2nd,3rd instance respectively.
Along with each image&mask pair I have a list like below mapping the instance_ids
to a class_name like
annotation=[{"class_name":"cat","instance_id":"1"},{"class_name":"dog","instance_id":"2"}]
If I want to color cat: orange, dog:blue
I can't use dataset.mask_targets
method described here
Because it requires there to be a constant mapping mask_value->class
whereas in my case mask_value->class
changes for each example since the mask values are based on the instance_id. eg:
If an image has 2 cats it would be like 1->cat,2->cat, then another image with a dog&cat would be 1->dog,2->cat.
I would rather not have to save another copy of the mask in fiftyone format &
I especially want to use the mask_path
attribute to pass the mask (to save disk space).
So If I save my dataset like below how can I define a custom fo.ColorScheme
?
for p,annotation in (paths,annotations):
sample = fo.Sample(filepath='images/'+p)
sample["segmentation"] = fo.Segmentation(mask_path='masks/'+p,
labels={a['instance_id']:a['class_name'] for a in annotation},
# maybe a way to pass a color mapping per sample?
)
dataset.add_sample(sample)
Hi @cceyda 👋
Unfortunately fo.ColorScheme
does not yet include support for customizing colors for Segmentation
mask targets. We're planning to add that soon though!
We don't, however, have any plans to support the type of instance-based pixel scheme that you're using with the Segmentation
label type. It is intended specifically for semantic segmentation, where each pixel value represents the same semantic class across images in the dataset (hence how mask_targets
are implemented, as you point out).
Rather, for instance-based tasks we have Instance segmentation format.
You can convert your Segmentation
values into this format very easily!
# A segmentation in your "instance" format
mask_targets = {1: "cat", 2: "dog", ...}
segmentation = fo.Segmentation(...)
# Convert to FiftyOne's instance segmentation format
instances = segmentation.to_detections(mask_targets=mask_targets)
sample = fo.Sample(filepath=..., instances=instances)
You can effectively construct different mask_targets
for each sample, and the instances
field will have the correct label
for each instance.
@brimoor glad to hear there are plans to add customizing colors for Segmentation.
I have tried the format conversion code example you gave (which is a very useful conversion to have btw.) Interestingly for me I had to use the rgb(hex) format despite my masks having 2D(w,h) shape.
rgb2hex=lambda r:'#%02x%02x%02x' % (r, r, r)
mask_targets = {rgb2hex(a['instance_id']):a["class_name"] for a in annotations}
segmentation = fo.Segmentation(mask_path=mask_image_path)
instances = segmentation.to_detections(mask_targets=mask_targets)
sample = fo.Sample(filepath=image_path, instances=instances)
print(instances)
but I see this results in mask=array(...)
being saved in the sample which is something I would like to avoid as I have a pretty big dataset and I wanna save disk/memory space.
I understand it is probably this way because of the Detections
label not having a mask_path
attribute like Segmentation
and also because the masks are saved in relation to the bbox.
For the time being I'll remove the mask=array(...)
from the converted Detections
and just rely on the bbox color for the visuals (saving along with fo.Segmentation(mask_path=...)
). And maybe in the future there will be a more efficient format for saving/loading instance segmentations 🤔
Many users have requested fine-grained control over the colors used to render labels in the App.
Example requests:
#FF6D04
for myground_truth
field#499CEF
for all objects withlabel="cat"
in any field#6D04FF
for all objects with<field>=<value>
in theground_truth
fieldI think the right place to start with this is just to add support for these kind of customizations via the App config.
Rough example (structure needs work):
Comments
color_pool
strategy) will be importantsession.config.colors
may not be general enough here.Detection(s)
fields)