Skip to content

FiftyOne Computer Vision Tips and Tricks – May 19, 2023

Welcome to our weekly FiftyOne tips and tricks blog where we recap interesting questions and answers that have recently popped up on Slack, GitHub, Stack Overflow, and Reddit.

Wait, what’s FiftyOne?

FiftyOne is an open source machine learning toolset that enables data science teams to improve the performance of their computer vision models by helping them curate high quality datasets, evaluate models, find mistakes, visualize embeddings, and get to production faster.

Ok, let’s dive into this week’s tips and tricks!

Deleting specific labels in a dataset

Community Slack member ZKW asked,

“Is there a method for deleting labels with specific classes in a field? For example, in a prediction I have classes ['person', 'car', 'bus', 'bike'], but I want to delete all the labels with the class ‘ bus‘ and ‘ bike and only leave ['person', 'car']. How can I delete them in the dataset, rather than creating a new view that omits them?”

If you want to omit certain classes from view, you can create a view using `filter_labels()`. For instance, we can use the negation operator ‘~` in conjunction with `is_in()` to filter our view to labels whose classes are not in a certain list:

from fiftyone import ViewField as F
classes_to_omit = ['bus','bike']
view = dataset.filter_labels(
    'ground_truth',
    ~F('label').is_in(classes_to_omit)
    )

To delete classes from the dataset entirely, you can use the `delete_labels()` method. One way to use this method is by passing in a list of label IDs that you want to delete. You can obtain the IDs of the labels you want to delete using `filter_labels()` as above, but without the negation operator, and then using the `values()` aggregation method (with `unwind = True` to flatten the list) to extract the IDs.

from fiftyone import ViewField as F

classes_to_delete = ['bus','bike']

labels_to_delete = dataset.filter_labels(
    'ground_truth',
    F('label').is_in(classes_to_delete)
    )

label_ids_to_delete = labels_to_delete.values(
    "ground_truth.detections.id", unwind=True
    )

dataset.delete_labels(ids = label_ids_to_delete)

For more information about the attributes of labels stored in dataset samples, check out the FiftyOne Docs.

Improving the performance of extracting and downloading of object patches

Community Slack member mserrari asked,

“I have images that are stored on a remote server that are about 60 MB. As I understand it, in order to generate a patch view and visualize it, I have to first download it into my browser. The patches are very small, less than 100KB. Is there a way to generate and fetch pre-generated patches from large images similar to the way thumbnails are generated, in order to reduce the time and overhead required to view them?

One possible solution is to use FiftyOne to generate the patches view on the same remote server where the dataset is located.

dataset.to_patches(my_field).export("/path/", dataset_type=fo.types.ImageClassificationDirectoryTree, label_field=my_field)

Learn more about object patches in the FiftyOne Docs.

Creating dataset views after filtering

Community Slack member Joy asked,

“How can I create a view of my dataset after a filtering operation?”

One solution is to create a saved view from the filtered view, and then load that saved view in code. For example loading a saved view you have created:

import fiftyone as fo

dataset = fo.load_dataset("quickstart")

# Retrieve a saved view
cats_view = dataset.load_saved_view("cats-view")
print(cats_view)

How to quickly load large thumbnails into the FiftyOne App

Community Slack member Alexey asked,

“I’m creating a dataset with very large image files using the FiftyOne app running on a Ubuntu host. On a remote MacOS host I have observed slow image loading in the FiftyOne App. It looks like the frontend downloads the entire image before any of the dataset manipulations take place. Is there a way to download only the thumbnail images that populate the grid in order to shorten the load time in the App?”

Yes! You can use multiple media fields to have lower-res thumbnails displayed in the Apps thumbnail grid. For example, here we create thumbnail images for use in the App’s grid view and store their paths in a thumbnail_path field:

import fiftyone as fo
import fiftyone.utils.image as foui
import fiftyone.zoo as foz

dataset = foz.load_zoo_dataset("quickstart")

# Generate some thumbnail images
foui.transform_images(
    dataset,
    size=(-1, 32),
    output_field="thumbnail_path",
    output_dir="/tmp/thumbnails",
)

More specifically in the snippet above, size=(-1, 32) is using fiftyone.utils.image.transform_image to specify an optional (width, height) for the image. One dimension can be -1, in which case the aspect ratio is preserved.

For more information on FiftyOne App configuration changes you can make, check out the FiftyOne Docs.

Adding custom sidebar groups

Community Slack member Agfian asked,

“I want to make a custom sidebar group in the FiftyOne App to better organize my fields. Is it possible to add the sidebar group using code at the same time as creating my dataset?”

Yes! For example in the snippet we add brightness to the Meta Features sidebar group:

sidebar_groups = fo.DatasetAppConfig.default_sidebar_groups(dataset)

features_sg = fo.SidebarGroupDocument(name="Meta Features")
features_sg.paths = ["brightness"]

# Add a new group
sidebar_groups.append(features_sg)

dataset.app_config.sidebar_groups = sidebar_groups
dataset.save()

For more information about working with Sidebar Groups, check out the FiftyOne Docs.

Join the FiftyOne community!

Join the thousands of engineers and data scientists already using FiftyOne to solve some of the most challenging problems in computer vision today!

What’s next?