In this tutorial we will be focusing on working with tags using Supervisely SDK. We'll go through complete cycle from creating TagMeta in project to assigning Tags to images and objects directly.
You will learn:
how to create tags for different tasks and scenarios with various parameters.
how to create tags (sly.TagMeta) in project
how to assign tags (sly.Tag) to images and objects
git clone https://github.com/supervisely-ecosystem/tutorial-working-with-tags
cd tutorial-working-with-tags
./create_venv.sh
Step 3. Open repository directory in Visual Studio Code.
code -r .
Step 4. Get Lemons (Annotated) project from ecosystem. Lemons (Annotated) is an example project with annotated lemons and kiwi fruits, with 6 images in it.
Step 5. change ✅ project ID ✅ in local.env file by copying the ID from the context menu of the project.
PROJECT_ID=111 # ⬅️ change value
Step 6. Start debugging src/main.py
Part 1. Tag Meta
Import libraries
import os
from dotenv import load_dotenv
import supervisely as sly
Init API client
Init API for communicating with Supervisely Instance. First, we load environment variables with credentials and project ID:
load_dotenv("local.env")
load_dotenv(os.path.expanduser("~/supervisely.env"))
api = sly.Api()
Create Tag Meta
TagMeta object contains general information about Tag. In order to create Tag itself you must create TagMeta object (information about tags that we will create and assign to images or objects) with parameters such as:
name (required) - name of the Tag.
value_type (required)- restricts Tag to have a certain value type. Available value types:
NONE = "none"
ANY_STRING = "any_string"
ANY_NUMBER = "any_number"
ONEOF_STRING = "oneof_string"
possible_values (required if value type is "oneof_string") - list of possible Tag values.
color (optional) - color of the Tag, must be an RGB value, if not specified, random color will be generated.
applicable_to (optional) - defines if Tag can be assigned to only images, to only objects or both. By default tag can be assigned to both images and objects.
applicable_classes (optional) - defines applicability of Tag only to certain classes. List of strings (class names).
Let's start with creating a simple TagMeta for showcasing, it can be applied to both images and objects, and also to any class. We won't use it for our project later. Tags with value type "none" can be used as "train" and "val" tags for example.
tag_meta = sly.TagMeta(
name="simple_tag",
value_type=sly.TagValueType.NONE
)
print(tag_meta)
# Name: simple_tag
# Value type: none
# Possible values: None
# Hotkey
# Applicable to all
# Applicable classes []
Let's make this TagMeta applicable only to images. We can recreate TagMeta with additional parameters. Most supervisely classes are immutable, so you have to assign or reassign them to variables.
Now we create a TagMeta with "any_string" value type to enter the origin of the fruit into it. This Tag can be assigned only to objects of classes "lemon" and "kiwi".
Part 3. Create Tags and update annotation on server
# get list of datasets in our project
datasets = api.dataset.get_list(project_id)
dataset_ids = [dataset.id for dataset in datasets]
# iterate over all images in project datasets
for dataset_id in dataset_ids:
# get list of images in dataset
images_infos = api.image.get_list(dataset_id=dataset_id)
for image_info in images_infos:
# get image id from image info
image_id = image_info.id
# download annotation
ann_json = api.annotation.download_json(image_id=image_id)
ann = sly.Annotation.from_json(data=ann_json, project_meta=project_meta)
# create and assign Tag to image
fruits_count_tag = sly.Tag(meta=fruits_count_tag_meta, value=len(ann.labels))
ann = ann.add_tag(fruits_count_tag)
# iterate over objects in annotation and assign appropriate tag
new_labels = []
for label in ann.labels:
new_label = None
if label.obj_class.name == "lemon":
name_tag = sly.Tag(meta=fruit_name_tag_meta, value="lemon")
size_tag = sly.Tag(meta=fruit_size_tag_meta, value="medium")
origin_tag = sly.Tag(meta=fruit_origin_tag_meta, value="Spain")
new_label = label.add_tags([name_tag, size_tag, origin_tag])
elif label.obj_class.name == "kiwi":
name_tag = sly.Tag(meta=fruit_name_tag_meta, value="kiwi")
size_tag = sly.Tag(meta=fruit_size_tag_meta, value="small")
origin_tag = sly.Tag(meta=fruit_origin_tag_meta, value="Italy")
new_label = label.add_tags([name_tag, size_tag, origin_tag])
if new_label:
new_labels.append(new_label)
# update and upload ann to Supervisely instance
ann = ann.clone(labels=new_labels)
api.annotation.upload_ann(img_id=image_id, ann=ann)
Retrieve images with object tags of interest
Sometimes, you may need to filter your images to retrieve only those that feature specific tags or meet certain criteria.
The code snippet below demonstrates how to get images featuring objects with multiple tags attached:
target_imageids = []
# Iterate over each dataset
for dataset in api.dataset.get_list(project_id):
# Get only images that contain object tags
filters = [{"type": "objects_tag", "data": {"include": True}}]
images = api.image.get_filtered_list(dataset.id, filters)
# Iterate over images in batches
for batch_infos in sly.batched(images, batch_size=500):
batch_ids = [info.id for info in batch_infos]
# Download annotations for batch images
ann_infos = api.annotation.download_batch(dataset.id, batch_ids)
# Extract image ID if any object on an image contains more than 1 tag
for ann_info in ann_infos:
ann = sly.Annotation.from_json(ann_info.annotation, project_meta)
if any([len(label.tags) > 1 for label in ann.labels]):
target_imageids.append(ann_info.image_id)
print(target_imageids)
# [31927, 31933, 31968, 32009, 32155, 32366]
Advanced API
Advanced API allows user to manage tags directly on images or objects without downloading annotation data from server.
Get project meta again after updating it with new tags.
ann_json = api.annotation.download_json(image_id=image_id)
ann = sly.Annotation.from_json(data=ann_json, project_meta=project_meta)
# iterate over objects in annotation and add appropriate tag
for label in ann.labels:
# get figure sly id
figure_id = label.geometry.sly_id
# get tag sly id
tag_meta = project_meta.get_tag_meta("imported_from")
if label.obj_class.name == "lemon":
api.advanced.add_tag_to_object(tag_meta_id=tag_meta.sly_id, figure_id=figure_id, value="Spain")
elif label.obj_class.name == "kiwi":
api.advanced.add_tag_to_object(tag_meta_id=tag_meta.sly_id, figure_id=figure_id, value="Italy")
Add Tag to set of images
With api.image.add_tag_batch() method you can add a tag to a list of images without need to update annotation of each image one by one.
# get tag meta from project meta
tag_meta = project_meta.get_tag_meta("fruits")
# create a list of images ids from images infos
image_ids = [image_info.id for image_info in images_infos]
# get tag meta id
tag_meta_id = tag_meta.sly_id
# update tags in batches.
api.image.add_tag_batch(image_ids, tag_meta_id, value=None, tag_meta=tag_meta)