Annotate data
Label your data so a model can learn from it. For a vision model, label images with tags for classification or bounding boxes for object detection. For a robot policy, tag each recorded sequence with the task it demonstrates. Organizing your data into a dataset makes bulk annotation and training workflows easier.
Tip
Once you’ve hand-labeled a small set of images and trained a first model on them, use automated annotation to have that model predict labels for the rest. You review and correct the predictions instead of labeling every image by hand. Automated annotation is available for classification and object detection models.
Tag images for classification
Tags are labels that apply to an entire image. Use them when you are building a classification model – for example, labeling images as “good-part” or “defective-part”.
- In the DATA tab, click an image to open it in the detail view.
- On the right side panel, find the Tags section.
- Click the + button next to Tags.
- Type a tag name (for example,
good-part) and press Enter. - The tag is saved immediately. Repeat for each image.
To tag multiple images at once, use an SDK.
async def main():
viam_client = await connect()
data_client = viam_client.data_client
binary_data_ids = ["binary-data-id-1", "binary-data-id-2"]
await data_client.add_tags_to_binary_data_by_ids(
tags=["good-part"],
binary_ids=binary_data_ids,
)
print("Tags added.")
viam_client.close()
binaryIDs := []string{"binary-data-id-1", "binary-data-id-2"}
err = dataClient.AddTagsToBinaryDataByIDs(
ctx,
[]string{"good-part"},
binaryIDs,
)
if err != nil {
logger.Fatal(err)
}
fmt.Println("Tags added.")
You can get binary data IDs by querying for images using the data client’s
binary_data_by_filter method, which returns objects that include the binary
data ID.
Choose tag names that are clear, consistent, and descriptive. Use lowercase with
hyphens (for example, good-part, defective-part, no-part). Avoid vague names like
type1 or other.
Draw bounding boxes for object detection
Bounding boxes mark the location of specific objects within an image. Use them when you are building an object detection model – for example, detecting packages on a conveyor belt.
- Open your dataset and click an image to open the detail view.
- In the side panel, click the Actions tab.
- Click Annotate to enter annotation mode.
- Select or create a label (for example,
package). - Hold Cmd (macOS) or Ctrl (Windows/Linux) and click-and-drag on the image to draw a rectangle around the object.
- The bounding box appears with your selected label. Adjust the box edges by dragging them if needed.
- Repeat for every object in the image that should be detected.
- Move to the next image and repeat.
async def main():
viam_client = await connect()
data_client = viam_client.data_client
bbox_id = await data_client.add_bounding_box_to_image_by_id(
binary_id="binary-data-id-1",
label="package",
x_min_normalized=0.15,
y_min_normalized=0.20,
x_max_normalized=0.85,
y_max_normalized=0.90,
)
print(f"Added bounding box: {bbox_id}")
viam_client.close()
bboxID, err := dataClient.AddBoundingBoxToImageByID(
ctx,
"binary-data-id-1",
"package",
0.15, // x_min_normalized
0.20, // y_min_normalized
0.85, // x_max_normalized
0.90, // y_max_normalized
)
if err != nil {
logger.Fatal(err)
}
fmt.Printf("Added bounding box: %s\n", bboxID)
Draw tight bounding boxes that closely fit the object. Do not include excessive background. If an image contains multiple objects, draw a separate bounding box for each one.
From code, coordinates are normalized 0.0-1.0, where (0.0, 0.0) is the top-left corner and (1.0, 1.0) is the bottom-right corner.
Tag sequences
A sequence’s tags label the whole sequence, such as the task a robot policy demonstration shows.
You usually set them when you record, through the capture-control module’s start_sequence command or CreateSequence.
See Sequences.
If you didn’t tag sequences while recording, add a tag from code. The Viam app and the CLI can’t edit a sequence.
The update replaces the sequence’s tags, so read the current tags first and pass them back with the new one.
sequence = await data_client.get_sequence("<sequence-id>")
await data_client.update_sequence(
id="<sequence-id>",
sequence_tags=list(sequence.sequence_tags) + ["pick-up-cup"],
)
The SDK builds the field mask from the arguments you pass, so you don’t set it yourself.
sequence, err := dataClient.GetSequence(ctx, "<sequence-id>")
if err != nil {
logger.Fatal(err)
}
err = dataClient.UpdateSequence(ctx, "<sequence-id>", &app.UpdateSequenceOptions{
SequenceTags: append(slices.Clone(sequence.SequenceTags), "pick-up-cup"),
FieldMask: []string{"sequence_tags"},
})
if err != nil {
logger.Fatal(err)
}
The field mask is required. It names the fields to change.
const sequence = await dataClient.getSequence("<sequence-id>");
await dataClient.updateSequence(
"<sequence-id>",
undefined, // resources
[...sequence.sequenceTags, "pick-up-cup"],
undefined, // startTime
undefined, // endTime
{ paths: ["sequence_tags"] },
);
The field mask is required. It names the fields to change.
To confirm, get the sequence again: its sequence_tags include the new tag.
Use the same tag for every demonstration of the same task.
To check a sequence dataset’s tags, see Verify dataset quality.
Troubleshooting
What’s next
- Automate annotation: speed up labeling by using an existing ML model to generate predictions automatically.
- Train a vision model with built-in training: use your labeled dataset to train a classification or object detection model.
- Train a model with a custom training script: train on a sequence dataset, such as a robot policy.
Was this page helpful?
Glad to hear it! If you have any other feedback please let us know:
We're sorry about that. To help us improve, please tell us what we can do better:
Thank you!