You MUST call the initialise_labels function (once per data unit) before trying to import your labels/annotations.
- Import the dependencies.
- Authenticate your Encord client.
- Specify the Annotate Project with the data you want to label.
- Specify the label row you want to import your label to. This specifies the data unit (image, image group, image sequence, video, or DICOM series) you want to add your labels to.
- Use the initialise_labels function ONCE to prepare the row for your labels.
- Apply your labels to the label row.
- Save the label row.
One label row is equivalent to one data unit. You only need to use the initialise_labels function and save the label row ONCE per data unit, regardless of how many labels are added to the data unit. However, any future changes to a data unit need to be initialized and saved.
Object Labels
Bounding Box
Bounding Box
BasicThis example includes the following:
- Single image labeling
- Image Group labeling
- Image Sequence labeling
- Video labeling
- Single image labeling
- Image Group labeling
- Image Sequence labeling
- Video labeling
- Radio button options
- Checklist options
- Text input
- Number input

Copy
from encord import EncordUserClient, Project
from encord.objects import Object, ObjectInstance
from encord.objects.coordinates import BoundingBoxCoordinates
# User input
SSH_PATH = "/Users/chris-encord/ssh-private-key.txt" # Replace with the file path to your SSH private key
PROJECT_ID = "00000000-0000-0000-0000-000000000000" # Replace with the unique Project ID
BUNDLE_SIZE = 10
# Data unit titles in your Project.
IMAGE_TITLE = "cherries-001.jpg"
IMG_GROUP_TITLE = "cherries-ig"
IMG_SEQUENCE_TITLE = "cherries-is"
VIDEO_TITLE = "cherries-vid-001.mp4"
# Authorize connection to Encord
user_client: EncordUserClient = EncordUserClient.create_with_ssh_private_key(
ssh_private_key_path=SSH_PATH,
# For US platform users use domain="https://api.us.encord.com"
domain="https://api.encord.com",
)
project: Project = user_client.get_project(PROJECT_ID)
# Find bounding box object "Cherries" in the ontology.
ontology_structure = project.ontology_structure
box_ontology_object: Object = ontology_structure.get_child_by_title(title="Cherries", type_=Object)
assert box_ontology_object is not None, "Bounding box object 'Cherries' not found in ontology."
# Initialise label rows
label_rows = {}
all_titles = [IMAGE_TITLE, IMG_GROUP_TITLE, IMG_SEQUENCE_TITLE, VIDEO_TITLE]
with project.create_bundle(bundle_size=BUNDLE_SIZE) as bundle:
for title in all_titles:
rows = project.list_label_rows_v2(data_title_eq=title)
assert isinstance(rows, list), f"Expected list for '{title}', got {type(rows)}"
if not rows:
print(f"Skipping: No label row found for {title}")
continue
lr = rows[0]
lr.initialise_labels(bundle=bundle)
assert lr.ontology_structure is not None, f"Ontology not initialized for '{title}'"
label_rows[title] = lr
# Coordinates for the bounding box
box = BoundingBoxCoordinates(height=0.35, width=0.35, top_left_x=0.1, top_left_y=0.1)
# Create instances and attach to frames
label_rows_to_save = []
# 1. One image > annotate frame 0
image_lr = label_rows.get(IMAGE_TITLE)
if image_lr is not None:
inst: ObjectInstance = box_ontology_object.create_instance()
inst.set_for_frames(coordinates=box, frames=0)
image_lr.add_object_instance(inst)
label_rows_to_save.append(image_lr)
# 2. One image group > annotate frame 0
img_group_lr = label_rows.get(IMG_GROUP_TITLE)
if img_group_lr is not None:
inst: ObjectInstance = box_ontology_object.create_instance()
inst.set_for_frames(coordinates=box, frames=0)
img_group_lr.add_object_instance(inst)
label_rows_to_save.append(img_group_lr)
# 3. One image sequence > annotate frame 0
img_sequence_lr = label_rows.get(IMG_SEQUENCE_TITLE)
if img_sequence_lr is not None:
inst: ObjectInstance = box_ontology_object.create_instance()
inst.set_for_frames(coordinates=box, frames=0)
img_sequence_lr.add_object_instance(inst)
label_rows_to_save.append(img_sequence_lr)
# 4. One video > reuse SAME instance across 3 consecutive frames (frames 100, 101, 102)
video_lr = label_rows.get(VIDEO_TITLE)
if video_lr is not None:
inst: ObjectInstance = box_ontology_object.create_instance()
consecutive_frames = [100, 101, 102]
for f in consecutive_frames:
inst.set_for_frames(coordinates=box, frames=f)
video_lr.add_object_instance(inst)
label_rows_to_save.append(video_lr)
# Save the label rows
with project.create_bundle(bundle_size=BUNDLE_SIZE) as bundle:
for lr in label_rows_to_save:
lr.save(bundle=bundle)
print(f"Saved label row for {lr.data_title}")
print("Done: created one bounding box on image, image group, image sequence, and 3 video frames.")
Rotatable Bounding Box
Rotatable Bounding Box
BasicThis example includes the following:
- Single image labeling
- Image Group labeling
- Image Sequence labeling
- Video labeling
- Single image labeling
- Image Group labeling
- Image Sequence labeling
- Video labeling
- Radio button options
- Checklist options
- Text input
- Number input

Copy
from encord import EncordUserClient, Project
from encord.objects import Object, ObjectInstance
from encord.objects.coordinates import RotatableBoundingBoxCoordinates
# User input
SSH_PATH = "/Users/chris-encord/ssh-private-key.txt" # Replace with the file path to your SSH private key
PROJECT_ID = "00000000-0000-0000-0000-000000000000" # Replace with the unique Project ID
BUNDLE_SIZE = 10
# Data unit titles in your project
IMAGE_TITLE = "persimmons-001.jpg"
IMG_GROUP_TITLE = "persimmons-ig"
IMG_SEQUENCE_TITLE = "persimmons-is"
VIDEO_TITLE = "persimmons-vid-001.mp4"
# Authorize connection to Encord
user_client: EncordUserClient = EncordUserClient.create_with_ssh_private_key(
ssh_private_key_path=SSH_PATH,
# For US platform users use domain="https://api.us.encord.com"
domain="https://api.encord.com",
)
project: Project = user_client.get_project(PROJECT_ID)
# Find rotatable bbox object "Persimmons" in the ontology
ontology_structure = project.ontology_structure
rbbox_ontology_object: Object = ontology_structure.get_child_by_title(title="Persimmons", type_=Object)
assert rbbox_ontology_object is not None, "Rotatable bbox object 'Persimmons' not found in ontology."
# Initialise label rows
label_rows = {}
all_titles = [IMAGE_TITLE, IMG_GROUP_TITLE, IMG_SEQUENCE_TITLE, VIDEO_TITLE]
with project.create_bundle(bundle_size=BUNDLE_SIZE) as bundle:
for title in all_titles:
rows = project.list_label_rows_v2(data_title_eq=title)
assert isinstance(rows, list), f"Expected list for '{title}', got {type(rows)}"
if not rows:
print(f"Skipping: No label row found for {title}")
continue
lr = rows[0]
lr.initialise_labels(bundle=bundle)
assert lr.ontology_structure is not None, f"Ontology not initialized for '{title}'"
label_rows[title] = lr
# Coordinates for the rotatable bounding box
rbbox = RotatableBoundingBoxCoordinates(height=0.35, width=0.35, top_left_x=0.1, top_left_y=0.1, theta=25)
# Create instances and attach to frames
label_rows_to_save = []
# 1. One image > annotate frame 0
image_lr = label_rows.get(IMAGE_TITLE)
if image_lr is not None:
inst: ObjectInstance = rbbox_ontology_object.create_instance()
inst.set_for_frames(coordinates=rbbox, frames=0)
image_lr.add_object_instance(inst)
label_rows_to_save.append(image_lr)
# 2. One image group > annotate frame 0
img_group_lr = label_rows.get(IMG_GROUP_TITLE)
if img_group_lr is not None:
inst: ObjectInstance = rbbox_ontology_object.create_instance()
inst.set_for_frames(coordinates=rbbox, frames=0)
img_group_lr.add_object_instance(inst)
label_rows_to_save.append(img_group_lr)
# 3. One image sequence > annotate frame 0
img_sequence_lr = label_rows.get(IMG_SEQUENCE_TITLE)
if img_sequence_lr is not None:
inst: ObjectInstance = rbbox_ontology_object.create_instance()
inst.set_for_frames(coordinates=rbbox, frames=0)
img_sequence_lr.add_object_instance(inst)
label_rows_to_save.append(img_sequence_lr)
# 4 One video > reuse SAME instance across 3 consecutive frames (frames 100, 101, 102)
video_lr = label_rows.get(VIDEO_TITLE)
if video_lr is not None:
inst: ObjectInstance = rbbox_ontology_object.create_instance()
consecutive_frames = [100, 101, 102]
for f in consecutive_frames:
inst.set_for_frames(coordinates=rbbox, frames=f)
video_lr.add_object_instance(inst)
label_rows_to_save.append(video_lr)
# Save label rows
with project.create_bundle(bundle_size=BUNDLE_SIZE) as bundle:
for lr in label_rows_to_save:
lr.save(bundle=bundle)
print(f"Saved label row for {lr.data_title}")
print("Done: created one rotatable bounding box on image, image group, image sequence, and 3 video frames.")
Polygons (Advanced)
Polygons (Advanced)
Polygons can have simple and complex shapes, including being enclosed in one another, and encompassing separate regions. In each case the polygon’s coordinates are arranged in a different way.BasicThis example includes the following:Simple PolygonImport a simple polygon using the recommended method.
DonutImport a complex polygon with a hole in it.
Multiple PolygonsImport a complex polygon that is in multiple parts.
Donut with Object InsideImports a complex polygon that has a hole in it with another polygon inside.
Polygons OntologyThis ontology applies for all polygon shapes (simple, donut, multiple polygons, donut with object inside).
- Single image labeling
- Image Group labeling
- Image Sequence labeling
- Video labeling
- Single image labeling
- Image Group labeling
- Image Sequence labeling
- Video labeling
- Radio button options
- Checklist options
- Text input
- Number input
Copy
PolygonCoordinates(polygons=[[[PointCoordinate(x1, y1), PointCoordinate(x2, y2),...]]]





Copy
from encord import EncordUserClient, Project
from encord.objects import Object, ObjectInstance
from encord.objects.coordinates import PointCoordinate, PolygonCoordinates
# User input
SSH_PATH = "/Users/chris-encord/ssh-private-key.txt" # Replace with the file path to your SSH private key
PROJECT_ID = "00000000-0000-0000-0000-000000000000" # Replace with the unique Project ID
BUNDLE_SIZE = 10
# Data unit titles in your Project
IMAGE_TITLE = "blueberries-001.jpg"
IMG_GROUP_TITLE = "blueberries-ig"
IMG_SEQUENCE_TITLE = "blueberries-is"
VIDEO_TITLE = "blueberries-vid-001.mp4"
# Authorize connection to Encord
user_client: EncordUserClient = EncordUserClient.create_with_ssh_private_key(
ssh_private_key_path=SSH_PATH,
# For US platform users use domain="https://api.us.encord.com"
domain="https://api.encord.com",
)
project: Project = user_client.get_project(PROJECT_ID)
# Find the polygon object "Blueberries" in the ontology
ontology_structure = project.ontology_structure
polygon_ontology_object: Object = ontology_structure.get_child_by_title(title="Blueberries", type_=Object)
assert polygon_ontology_object is not None, "Polygon object 'Blueberries' not found in ontology."
# Initialise label rows
label_rows = {}
all_titles = [IMAGE_TITLE, IMG_GROUP_TITLE, IMG_SEQUENCE_TITLE, VIDEO_TITLE]
with project.create_bundle(bundle_size=BUNDLE_SIZE) as bundle:
for title in all_titles:
rows = project.list_label_rows_v2(data_title_eq=title)
assert isinstance(rows, list), f"Expected list for '{title}', got {type(rows)}"
if not rows:
print(f"Skipping: No label row found for {title}")
continue
lr = rows[0]
lr.initialise_labels(bundle=bundle)
assert lr.ontology_structure is not None, f"Ontology not initialized for '{title}'"
label_rows[title] = lr
# Coordinates: A simple 5-point polygon (single ring)
poly = PolygonCoordinates(
polygons=[
[
[
PointCoordinate(0.10, 0.10),
PointCoordinate(0.20, 0.15),
PointCoordinate(0.25, 0.25),
PointCoordinate(0.15, 0.30),
PointCoordinate(0.08, 0.22),
]
]
]
)
# Create instances and attach to frames
label_rows_to_save = []
# 1. One image > annotate frame 0
image_lr = label_rows.get(IMAGE_TITLE)
if image_lr is not None:
inst: ObjectInstance = polygon_ontology_object.create_instance()
inst.set_for_frames(coordinates=poly, frames=0)
image_lr.add_object_instance(inst)
label_rows_to_save.append(image_lr)
# 2. One image group > annotate frame 0
img_group_lr = label_rows.get(IMG_GROUP_TITLE)
if img_group_lr is not None:
inst: ObjectInstance = polygon_ontology_object.create_instance()
inst.set_for_frames(coordinates=poly, frames=0)
img_group_lr.add_object_instance(inst)
label_rows_to_save.append(img_group_lr)
# 3. One image sequence > annotate frame 0
img_sequence_lr = label_rows.get(IMG_SEQUENCE_TITLE)
if img_sequence_lr is not None:
inst: ObjectInstance = polygon_ontology_object.create_instance()
inst.set_for_frames(coordinates=poly, frames=0)
img_sequence_lr.add_object_instance(inst)
label_rows_to_save.append(img_sequence_lr)
# 4. One video > reuse SAME instance across 3 consecutive frames (frames 100, 101, 102)
video_lr = label_rows.get(VIDEO_TITLE)
if video_lr is not None:
inst: ObjectInstance = polygon_ontology_object.create_instance()
consecutive_frames = [100, 101, 102]
for f in consecutive_frames:
inst.set_for_frames(coordinates=poly, frames=f)
video_lr.add_object_instance(inst)
label_rows_to_save.append(video_lr)
# Save label rows
with project.create_bundle(bundle_size=BUNDLE_SIZE) as bundle:
for lr in label_rows_to_save:
lr.save(bundle=bundle)
print(f"Saved label row for {lr.data_title}")
print("Done: created one polygon on image, image group, image sequence, and 3 video frames.")
Copy
from encord import EncordUserClient, Project
from encord.objects import Object, ObjectInstance
from encord.objects.coordinates import PointCoordinate, PolygonCoordinates
# User input
SSH_PATH = "/Users/chris-encord/ssh-private-key.txt" # Replace with the file path to your SSH private key
PROJECT_ID = "00000000-0000-0000-0000-000000000000" # Replace with the unique Project ID
BUNDLE_SIZE = 10
# Data unit titles in your Project
IMAGE_TITLE = "blueberries-001.jpg"
IMG_GROUP_TITLE = "blueberries-ig"
IMG_SEQUENCE_TITLE = "blueberries-is"
VIDEO_TITLE = "blueberries-vid-001.mp4"
# Authorize connection to Encord
user_client: EncordUserClient = EncordUserClient.create_with_ssh_private_key(
ssh_private_key_path=SSH_PATH,
# For US platform users use domain="https://api.us.encord.com"
domain="https://api.encord.com",
)
project: Project = user_client.get_project(PROJECT_ID)
# Find the polygon object "Blueberries" in the ontology
ontology_structure = project.ontology_structure
polygon_ontology_object: Object = ontology_structure.get_child_by_title(title="Blueberries", type_=Object)
assert polygon_ontology_object is not None, "Polygon object 'Blueberries' not found in ontology."
# Initialise label rows
label_rows = {}
all_titles = [IMAGE_TITLE, IMG_GROUP_TITLE, IMG_SEQUENCE_TITLE, VIDEO_TITLE]
with project.create_bundle(bundle_size=BUNDLE_SIZE) as bundle:
for title in all_titles:
rows = project.list_label_rows_v2(data_title_eq=title)
assert isinstance(rows, list), f"Expected list for '{title}', got {type(rows)}"
if not rows:
print(f"Skipping: No label row found for {title}")
continue
lr = rows[0]
lr.initialise_labels(bundle=bundle)
assert lr.ontology_structure is not None, f"Ontology not initialized for '{title}'"
label_rows[title] = lr
# Donut polygon coordinates
outer_ring = [
PointCoordinate(0.30, 0.30),
PointCoordinate(0.40, 0.28),
PointCoordinate(0.50, 0.35),
PointCoordinate(0.52, 0.48),
PointCoordinate(0.46, 0.60),
PointCoordinate(0.36, 0.62),
PointCoordinate(0.26, 0.55),
PointCoordinate(0.24, 0.42),
]
inner_ring = [ # hole
PointCoordinate(0.36, 0.42),
PointCoordinate(0.42, 0.41),
PointCoordinate(0.45, 0.48),
PointCoordinate(0.41, 0.53),
PointCoordinate(0.34, 0.50),
]
poly_donut = PolygonCoordinates(polygons=[[outer_ring, inner_ring]])
# Create instances and attach to frames
label_rows_to_save = []
# 1. One image > annotate frame 0
image_lr = label_rows.get(IMAGE_TITLE)
if image_lr is not None:
inst: ObjectInstance = polygon_ontology_object.create_instance()
inst.set_for_frames(coordinates=poly_donut, frames=0)
image_lr.add_object_instance(inst)
label_rows_to_save.append(image_lr)
# 2. One image group > annotate frame 0
img_group_lr = label_rows.get(IMG_GROUP_TITLE)
if img_group_lr is not None:
inst: ObjectInstance = polygon_ontology_object.create_instance()
inst.set_for_frames(coordinates=poly_donut, frames=0)
img_group_lr.add_object_instance(inst)
label_rows_to_save.append(img_group_lr)
# 3. One image sequence > annotate frame 0
img_sequence_lr = label_rows.get(IMG_SEQUENCE_TITLE)
if img_sequence_lr is not None:
inst: ObjectInstance = polygon_ontology_object.create_instance()
inst.set_for_frames(coordinates=poly_donut, frames=0)
img_sequence_lr.add_object_instance(inst)
label_rows_to_save.append(img_sequence_lr)
# 4. One video > reuse SAME instance across 3 consecutive frames (frames 100, 101, 102)
video_lr = label_rows.get(VIDEO_TITLE)
if video_lr is not None:
inst: ObjectInstance = polygon_ontology_object.create_instance()
consecutive_frames = [100, 101, 102]
for f in consecutive_frames:
inst.set_for_frames(coordinates=poly_donut, frames=f)
video_lr.add_object_instance(inst)
label_rows_to_save.append(video_lr)
# Save label rows
with project.create_bundle(bundle_size=BUNDLE_SIZE) as bundle:
for lr in label_rows_to_save:
lr.save(bundle=bundle)
print(f"Saved label row for {lr.data_title}")
print("Done: created one donut polygon on image, image group, image sequence, and 3 video frames.")
Copy
from encord import EncordUserClient, Project
from encord.objects import Object, ObjectInstance
from encord.objects.coordinates import PointCoordinate, PolygonCoordinates
# User input
SSH_PATH = "/Users/chris-encord/ssh-private-key.txt" # Replace with the file path to your SSH private key
PROJECT_ID = "00000000-0000-0000-0000-000000000000" # Replace with the unique Project ID
BUNDLE_SIZE = 10
# Data unit titles in your Project
IMAGE_TITLE = "blueberries-001.jpg"
IMG_GROUP_TITLE = "blueberries-ig"
IMG_SEQUENCE_TITLE = "blueberries-is"
VIDEO_TITLE = "blueberries-vid-001.mp4"
# Authorize connection to Encord
user_client: EncordUserClient = EncordUserClient.create_with_ssh_private_key(
ssh_private_key_path=SSH_PATH,
# For US platform users use domain="https://api.us.encord.com"
domain="https://api.encord.com",
)
project: Project = user_client.get_project(PROJECT_ID)
# Find the polygon object "Blueberries" in the ontology
ontology_structure = project.ontology_structure
polygon_ontology_object: Object = ontology_structure.get_child_by_title(title="Blueberries", type_=Object)
assert polygon_ontology_object is not None, "Polygon object 'Blueberries' not found in ontology."
# Initialise label rows
label_rows = {}
all_titles = [IMAGE_TITLE, IMG_GROUP_TITLE, IMG_SEQUENCE_TITLE, VIDEO_TITLE]
with project.create_bundle(bundle_size=BUNDLE_SIZE) as bundle:
for title in all_titles:
rows = project.list_label_rows_v2(data_title_eq=title)
assert isinstance(rows, list), f"Expected list for '{title}', got {type(rows)}"
if not rows:
print(f"Skipping: No label row found for {title}")
continue
lr = rows[0]
lr.initialise_labels(bundle=bundle)
assert lr.ontology_structure is not None, f"Ontology not initialized for '{title}'"
label_rows[title] = lr
# Multi-polygon coordinates: Two separate simple polygons
ring_a = [
PointCoordinate(0.15, 0.15),
PointCoordinate(0.22, 0.18),
PointCoordinate(0.24, 0.25),
PointCoordinate(0.18, 0.28),
PointCoordinate(0.12, 0.22),
]
ring_b = [
PointCoordinate(0.55, 0.35),
PointCoordinate(0.62, 0.38),
PointCoordinate(0.66, 0.45),
PointCoordinate(0.60, 0.50),
PointCoordinate(0.53, 0.43),
]
poly_multi = PolygonCoordinates(polygons=[[ring_a], [ring_b]])
# Create instances and attach to frames
label_rows_to_save = []
# 1. One image > annotate frame 0
image_lr = label_rows.get(IMAGE_TITLE)
if image_lr is not None:
inst: ObjectInstance = polygon_ontology_object.create_instance()
inst.set_for_frames(coordinates=poly_multi, frames=0)
image_lr.add_object_instance(inst)
label_rows_to_save.append(image_lr)
# 2. One image group > annotate frame 0
img_group_lr = label_rows.get(IMG_GROUP_TITLE)
if img_group_lr is not None:
inst: ObjectInstance = polygon_ontology_object.create_instance()
inst.set_for_frames(coordinates=poly_multi, frames=0)
img_group_lr.add_object_instance(inst)
label_rows_to_save.append(img_group_lr)
# 3. One image sequence > annotate frame 0
img_sequence_lr = label_rows.get(IMG_SEQUENCE_TITLE)
if img_sequence_lr is not None:
inst: ObjectInstance = polygon_ontology_object.create_instance()
inst.set_for_frames(coordinates=poly_multi, frames=0)
img_sequence_lr.add_object_instance(inst)
label_rows_to_save.append(img_sequence_lr)
# 4. One video > reuse SAME instance across 3 consecutive frames (frames 100, 101, 102)
video_lr = label_rows.get(VIDEO_TITLE)
if video_lr is not None:
inst: ObjectInstance = polygon_ontology_object.create_instance()
consecutive_frames = [100, 101, 102]
for f in consecutive_frames:
inst.set_for_frames(coordinates=poly_multi, frames=f)
video_lr.add_object_instance(inst)
label_rows_to_save.append(video_lr)
# Save label rows
with project.create_bundle(bundle_size=BUNDLE_SIZE) as bundle:
for lr in label_rows_to_save:
lr.save(bundle=bundle)
print(f"Saved label row for {lr.data_title}")
print("Done: created one multi-polygon (two separate rings) on image, image group, image sequence, and 3 video frames.")
Copy
# Import dependencies
from pathlib import Path
from encord import EncordUserClient, Project
from encord.objects import ChecklistAttribute, Object, ObjectInstance, Option, RadioAttribute, TextAttribute
from encord.objects.coordinates import PointCoordinate, PolygonCoordinates
from encord.objects.attributes import NumericAttribute
SSH_PATH = "/Users/chris-encord/ssh-private-key.txt"
# SSH_PATH = get_ssh_key() # replace it with access key
PROJECT_ID = "00000000-0000-0000-0000-000000000000"
BUNDLE_SIZE = 100
# Create user client using access key
user_client: EncordUserClient = EncordUserClient.create_with_ssh_private_key(
ssh_private_key_path=SSH_PATH,
# For US platform users use "https://api.us.encord.com"
domain="https://api.encord.com",
)
# Get project for which labels are to be added
project: Project = user_client.get_project(PROJECT_ID)
assert project is not None, "Project not found — check PROJECT_ID"
# Get ontology structure
ontology_structure = project.ontology_structure
assert ontology_structure is not None, "Ontology structure is missing in the project"
# Find polygon object for blueberries
polygon_ontology_object: Object = ontology_structure.get_child_by_title(title="Blueberries", type_=Object)
assert polygon_ontology_object is not None, "Object 'Blueberries' not found in ontology"
# Get radio attribute for blueberry type
blueberry_type_radio_attribute = ontology_structure.get_child_by_title(type_=RadioAttribute, title="Type?")
assert blueberry_type_radio_attribute is not None, "Radio attribute 'Type?' not found"
# Find number attribute in the ontology
blueberry_quality_number_attribute = ontology_structure.get_child_by_title(type_=NumericAttribute, title="Overall Quality")
assert blueberry_quality_number_attribute is not None, "Number attribute 'Overall Quality' not found in ontology."
# Get radio options
bluegold_option = blueberry_type_radio_attribute.get_child_by_title(type_=Option, title="Bluegold")
assert bluegold_option is not None, "Option 'Bluegold' not found under radio attribute 'Type?'"
duke_option = blueberry_type_radio_attribute.get_child_by_title(type_=Option, title="Duke")
assert duke_option is not None, "Option 'Duke' not found under radio attribute 'Type?'"
blueray_option = blueberry_type_radio_attribute.get_child_by_title(type_=Option, title="Blueray")
assert blueray_option is not None, "Option 'Blueray' not found under radio attribute 'Type?'"
other_blueberry_option = blueberry_type_radio_attribute.get_child_by_title(type_=Option, title="Other blueberry type")
assert other_blueberry_option is not None, "Option 'Other blueberry type' not found under radio attribute 'Type?'"
# Bluegold Qualities
bluegold_checklist_attribute = ontology_structure.get_child_by_title(
type_=ChecklistAttribute, title="Bluegold Qualities?"
)
assert bluegold_checklist_attribute is not None, "Checklist attribute 'Bluegold Qualities?' not found"
bluegold_plump_option = bluegold_checklist_attribute.get_child_by_title(type_=Option, title="Plump")
assert bluegold_plump_option is not None, "Option 'Plump' not found under 'Bluegold Qualities?'"
bluegold_juicy_option = bluegold_checklist_attribute.get_child_by_title(type_=Option, title="Juicy")
assert bluegold_juicy_option is not None, "Option 'Juicy' not found under 'Bluegold Qualities?'"
bluegold_large_option = bluegold_checklist_attribute.get_child_by_title(type_=Option, title="Large")
assert bluegold_large_option is not None, "Option 'Large' not found under 'Bluegold Qualities?'"
# Duke Qualities
duke_checklist_attribute = ontology_structure.get_child_by_title(type_=ChecklistAttribute, title="Duke Qualities?")
assert duke_checklist_attribute is not None, "Checklist attribute 'Duke Qualities?' not found"
duke_plump_option = duke_checklist_attribute.get_child_by_title(type_=Option, title="Plump")
assert duke_plump_option is not None, "Option 'Plump' not found under 'Duke Qualities?'"
duke_juicy_option = duke_checklist_attribute.get_child_by_title(type_=Option, title="Juicy")
assert duke_juicy_option is not None, "Option 'Juicy' not found under 'Duke Qualities?'"
duke_large_option = duke_checklist_attribute.get_child_by_title(type_=Option, title="Large")
assert duke_large_option is not None, "Option 'Large' not found under 'Duke Qualities?'"
# Blueray Qualities
blueray_checklist_attribute = ontology_structure.get_child_by_title(
type_=ChecklistAttribute, title="Blueray Qualities?"
)
assert blueray_checklist_attribute is not None, "Checklist attribute 'Blueray Qualities?' not found"
blueray_plump_option = blueray_checklist_attribute.get_child_by_title(type_=Option, title="Plump")
assert blueray_plump_option is not None, "Option 'Plump' not found under 'Blueray Qualities?'"
blueray_juicy_option = blueray_checklist_attribute.get_child_by_title(type_=Option, title="Juicy")
assert blueray_juicy_option is not None, "Option 'Juicy' not found under 'Blueray Qualities?'"
blueray_large_option = blueray_checklist_attribute.get_child_by_title(type_=Option, title="Large")
assert blueray_large_option is not None, "Option 'Large' not found under 'Blueray Qualities?'"
# Other blueberry type — text input
other_blueberry_option_text_attribute = ontology_structure.get_child_by_title(
type_=TextAttribute, title="Specify blueberry type"
)
assert other_blueberry_option_text_attribute is not None, "Text attribute 'Specify blueberry type' not found"
# Dictionary of labels per data unit and per frame with blueberry type specified, including quality options
video_frame_labels = {
"blueberries-001.jpg": {
0: {
"label_ref": "blueberry_001",
"coordinates": PolygonCoordinates(
polygons=[
# Donut + inner polygon
[
# Outer ring
[
PointCoordinate(0.10, 0.10),
PointCoordinate(0.22, 0.09),
PointCoordinate(0.21, 0.22),
PointCoordinate(0.09, 0.21),
PointCoordinate(0.10, 0.10),
],
# Inner ring
[
PointCoordinate(0.13, 0.13),
PointCoordinate(0.13, 0.18),
PointCoordinate(0.18, 0.18),
PointCoordinate(0.18, 0.13),
PointCoordinate(0.13, 0.13),
],
],
# Shape inside the hole
[
[
PointCoordinate(0.145, 0.145),
PointCoordinate(0.165, 0.150),
PointCoordinate(0.160, 0.165),
PointCoordinate(0.145, 0.145),
]
],
]
),
"blueberry_type": "Bluegold",
"bluegold_quality_options": "Plump, Juicy",
"blueberry_quality": 7
}
},
"blueberries-010.jpg": {
0: [
{
"label_ref": "blueberry_002",
"coordinates": PolygonCoordinates(
polygons=[
# First donut + inner polygon
[
# Outer ring
[
PointCoordinate(0.10, 0.10),
PointCoordinate(0.22, 0.09),
PointCoordinate(0.21, 0.22),
PointCoordinate(0.09, 0.21),
PointCoordinate(0.10, 0.10),
],
# Inner ring
[
PointCoordinate(0.13, 0.13),
PointCoordinate(0.13, 0.18),
PointCoordinate(0.18, 0.18),
PointCoordinate(0.18, 0.13),
PointCoordinate(0.13, 0.13),
],
],
# Shape inside the hole
[
[
PointCoordinate(0.145, 0.145),
PointCoordinate(0.165, 0.150),
PointCoordinate(0.160, 0.165),
PointCoordinate(0.145, 0.145),
]
],
]
),
"blueberry_type": "Duke",
"duke_quality_options": "Plump, Juicy, Large",
"blueberry_quality": 9
},
{
"label_ref": "blueberry_003",
"coordinates": PolygonCoordinates(
polygons=[
# Second donut + inner polygon
[
# Outer ring
[
PointCoordinate(0.30, 0.10),
PointCoordinate(0.42, 0.11),
PointCoordinate(0.41, 0.22),
PointCoordinate(0.29, 0.21),
PointCoordinate(0.30, 0.10),
],
# Inner ring
[
PointCoordinate(0.33, 0.13),
PointCoordinate(0.33, 0.18),
PointCoordinate(0.38, 0.18),
PointCoordinate(0.38, 0.13),
PointCoordinate(0.33, 0.13),
],
],
# Shape inside the hole
[
[
PointCoordinate(0.345, 0.145),
PointCoordinate(0.355, 0.155),
PointCoordinate(0.350, 0.165),
PointCoordinate(0.340, 0.160),
PointCoordinate(0.345, 0.145),
]
],
]
),
"blueberry_type": "Blueray",
"blueray_quality_options": "Plump",
"blueberry_quality": 6
},
{
"label_ref": "blueberry_004",
"coordinates": PolygonCoordinates(
polygons=[
# Third donut + inner polygon
[
# Outer ring
[
PointCoordinate(0.10, 0.30),
PointCoordinate(0.22, 0.29),
PointCoordinate(0.21, 0.42),
PointCoordinate(0.09, 0.41),
PointCoordinate(0.10, 0.30),
],
# Inner ring
[
PointCoordinate(0.13, 0.33),
PointCoordinate(0.13, 0.38),
PointCoordinate(0.18, 0.38),
PointCoordinate(0.18, 0.33),
PointCoordinate(0.13, 0.33),
],
],
# Shape inside the hole
[
[
PointCoordinate(0.145, 0.345),
PointCoordinate(0.155, 0.355),
PointCoordinate(0.150, 0.370),
PointCoordinate(0.140, 0.360),
PointCoordinate(0.145, 0.345),
]
],
]
),
"blueberry_type": "Other blueberry type",
"Specify blueberry type": "Highbush",
"blueberry_quality": 3
},
],
},
"blueberries-ig": {
0: {
"label_ref": "blueberry_005",
"coordinates": PolygonCoordinates(
polygons=[
# Donut + inner polygon
[
# Outer ring
[
PointCoordinate(0.10, 0.10),
PointCoordinate(0.22, 0.09),
PointCoordinate(0.21, 0.22),
PointCoordinate(0.09, 0.21),
PointCoordinate(0.10, 0.10),
],
# Inner ring
[
PointCoordinate(0.13, 0.13),
PointCoordinate(0.13, 0.18),
PointCoordinate(0.18, 0.18),
PointCoordinate(0.18, 0.13),
PointCoordinate(0.13, 0.13),
],
],
# Shape inside the hole
[
[
PointCoordinate(0.145, 0.145),
PointCoordinate(0.165, 0.150),
PointCoordinate(0.160, 0.165),
PointCoordinate(0.145, 0.145),
]
],
]
),
"blueberry_type": "Bluegold",
"bluegold_quality_options": "Plump, Juicy",
"blueberry_quality": 7
},
2: [
{
"label_ref": "blueberry_006",
"coordinates": PolygonCoordinates(
polygons=[
# First donut + inner polygon
[
# Outer ring
[
PointCoordinate(0.10, 0.10),
PointCoordinate(0.22, 0.09),
PointCoordinate(0.21, 0.22),
PointCoordinate(0.09, 0.21),
PointCoordinate(0.10, 0.10),
],
# Inner ring
[
PointCoordinate(0.13, 0.13),
PointCoordinate(0.13, 0.18),
PointCoordinate(0.18, 0.18),
PointCoordinate(0.18, 0.13),
PointCoordinate(0.13, 0.13),
],
],
# Shape inside the hole
[
[
PointCoordinate(0.145, 0.145),
PointCoordinate(0.165, 0.150),
PointCoordinate(0.160, 0.165),
PointCoordinate(0.145, 0.145),
]
],
]
),
"blueberry_type": "Duke",
"duke_quality_options": "Large",
"blueberry_quality": 5
},
{
"label_ref": "blueberry_007",
"coordinates": PolygonCoordinates(
polygons=[
# Second donut + inner polygon
[
# Outer ring
[
PointCoordinate(0.30, 0.10),
PointCoordinate(0.42, 0.11),
PointCoordinate(0.41, 0.22),
PointCoordinate(0.29, 0.21),
PointCoordinate(0.30, 0.10),
],
# Inner ring
[
PointCoordinate(0.33, 0.13),
PointCoordinate(0.33, 0.18),
PointCoordinate(0.38, 0.18),
PointCoordinate(0.38, 0.13),
PointCoordinate(0.33, 0.13),
],
],
# Shape inside the hole
[
[
PointCoordinate(0.345, 0.145),
PointCoordinate(0.355, 0.155),
PointCoordinate(0.350, 0.165),
PointCoordinate(0.340, 0.160),
PointCoordinate(0.345, 0.145),
]
],
]
),
"blueberry_type": "Blueray",
"blueray_quality_options": "Plump",
"blueberry_quality": 5
},
{
"label_ref": "blueberry_008",
"coordinates": PolygonCoordinates(
polygons=[
# Third donut + inner polygon
[
# Outer ring
[
PointCoordinate(0.10, 0.30),
PointCoordinate(0.22, 0.29),
PointCoordinate(0.21, 0.42),
PointCoordinate(0.09, 0.41),
PointCoordinate(0.10, 0.30),
],
# Inner ring
[
PointCoordinate(0.13, 0.33),
PointCoordinate(0.13, 0.38),
PointCoordinate(0.18, 0.38),
PointCoordinate(0.18, 0.33),
PointCoordinate(0.13, 0.33),
],
],
# Shape inside the hole
[
[
PointCoordinate(0.145, 0.345),
PointCoordinate(0.155, 0.355),
PointCoordinate(0.150, 0.370),
PointCoordinate(0.140, 0.360),
PointCoordinate(0.145, 0.345),
]
],
]
),
"blueberry_type": "Other blueberry type",
"Specify blueberry type": "Lowbush",
"blueberry_quality": 3
},
],
},
"blueberries-is": {
0: {
"label_ref": "blueberry_009",
"coordinates": PolygonCoordinates(
polygons=[
# Donut + inner polygon
[
# Outer ring
[
PointCoordinate(0.10, 0.10),
PointCoordinate(0.22, 0.09),
PointCoordinate(0.21, 0.22),
PointCoordinate(0.09, 0.21),
PointCoordinate(0.10, 0.10),
],
# Inner ring
[
PointCoordinate(0.13, 0.13),
PointCoordinate(0.13, 0.18),
PointCoordinate(0.18, 0.18),
PointCoordinate(0.18, 0.13),
PointCoordinate(0.13, 0.13),
],
],
# Shape inside the hole
[
[
PointCoordinate(0.145, 0.145),
PointCoordinate(0.165, 0.150),
PointCoordinate(0.160, 0.165),
PointCoordinate(0.145, 0.145),
]
],
]
),
"blueberry_type": "Bluegold",
"bluegold_quality_options": "Plump",
"blueberry_quality": 4
},
3: [
{
"label_ref": "blueberry_010",
"coordinates": PolygonCoordinates(
polygons=[
# First donut + inner polygon
[
# Outer ring
[
PointCoordinate(0.10, 0.10),
PointCoordinate(0.22, 0.09),
PointCoordinate(0.21, 0.22),
PointCoordinate(0.09, 0.21),
PointCoordinate(0.10, 0.10),
],
# Inner ring
[
PointCoordinate(0.13, 0.13),
PointCoordinate(0.13, 0.18),
PointCoordinate(0.18, 0.18),
PointCoordinate(0.18, 0.13),
PointCoordinate(0.13, 0.13),
],
],
# Shape inside the hole
[
[
PointCoordinate(0.145, 0.145),
PointCoordinate(0.165, 0.150),
PointCoordinate(0.160, 0.165),
PointCoordinate(0.145, 0.145),
]
],
]
),
"blueberry_type": "Duke",
"duke_quality_options": "Plump, Juicy, Large",
"blueberry_quality": 9
},
{
"label_ref": "blueberry_011",
"coordinates": PolygonCoordinates(
polygons=[
# Second donut + inner polygon
[
# Outer ring
[
PointCoordinate(0.30, 0.10),
PointCoordinate(0.42, 0.11),
PointCoordinate(0.41, 0.22),
PointCoordinate(0.29, 0.21),
PointCoordinate(0.30, 0.10),
],
# Inner ring
[
PointCoordinate(0.33, 0.13),
PointCoordinate(0.33, 0.18),
PointCoordinate(0.38, 0.18),
PointCoordinate(0.38, 0.13),
PointCoordinate(0.33, 0.13),
],
],
# Shape inside the hole
[
[
PointCoordinate(0.345, 0.145),
PointCoordinate(0.355, 0.155),
PointCoordinate(0.350, 0.165),
PointCoordinate(0.340, 0.160),
PointCoordinate(0.345, 0.145),
]
],
]
),
"blueberry_type": "Blueray",
"blueray_quality_options": "Plump",
"blueberry_quality": 6
},
{
"label_ref": "blueberry_012",
"coordinates": PolygonCoordinates(
polygons=[
# Third donut + inner polygon
[
# Outer ring
[
PointCoordinate(0.10, 0.30),
PointCoordinate(0.22, 0.29),
PointCoordinate(0.21, 0.42),
PointCoordinate(0.09, 0.41),
PointCoordinate(0.10, 0.30),
],
# Inner ring
[
PointCoordinate(0.13, 0.33),
PointCoordinate(0.13, 0.38),
PointCoordinate(0.18, 0.38),
PointCoordinate(0.18, 0.33),
PointCoordinate(0.13, 0.33),
],
],
# Shape inside the hole
[
[
PointCoordinate(0.145, 0.345),
PointCoordinate(0.155, 0.355),
PointCoordinate(0.150, 0.370),
PointCoordinate(0.140, 0.360),
PointCoordinate(0.145, 0.345),
]
],
]
),
"blueberry_type": "Other blueberry type",
"Specify blueberry type": "Highbush",
"blueberry_quality": 5
},
],
},
"blueberries-vid-001.mp4": {
103: [
{
"label_ref": "blueberry_013",
"coordinates": PolygonCoordinates(
polygons=[
# First donut + inner polygon
[
# Outer ring
[
PointCoordinate(0.10, 0.10),
PointCoordinate(0.22, 0.09),
PointCoordinate(0.21, 0.22),
PointCoordinate(0.09, 0.21),
PointCoordinate(0.10, 0.10),
],
# Inner ring
[
PointCoordinate(0.13, 0.13),
PointCoordinate(0.13, 0.18),
PointCoordinate(0.18, 0.18),
PointCoordinate(0.18, 0.13),
PointCoordinate(0.13, 0.13),
],
],
# Shape inside the hole
[
[
PointCoordinate(0.145, 0.145),
PointCoordinate(0.165, 0.150),
PointCoordinate(0.160, 0.165),
PointCoordinate(0.145, 0.145),
]
],
]
),
"blueberry_type": "Blueray",
"blueray_quality_options": "Plump",
"blueberry_quality": 4
},
{
"label_ref": "blueberry_014",
"coordinates": PolygonCoordinates(
polygons=[
# Second donut + inner polygon
[
# Outer ring
[
PointCoordinate(0.30, 0.10),
PointCoordinate(0.42, 0.11),
PointCoordinate(0.41, 0.22),
PointCoordinate(0.29, 0.21),
PointCoordinate(0.30, 0.10),
],
# Inner ring
[
PointCoordinate(0.33, 0.13),
PointCoordinate(0.33, 0.18),
PointCoordinate(0.38, 0.18),
PointCoordinate(0.38, 0.13),
PointCoordinate(0.33, 0.13),
],
],
# Shape inside the hole
[
[
PointCoordinate(0.345, 0.145),
PointCoordinate(0.355, 0.155),
PointCoordinate(0.350, 0.165),
PointCoordinate(0.340, 0.160),
PointCoordinate(0.345, 0.145),
]
],
]
),
"blueberry_type": "Bluegold",
"bluegold_quality_options": "Plump, Juicy, Large",
"blueberry_quality": 9
},
{
"label_ref": "blueberry_015",
"coordinates": PolygonCoordinates(
polygons=[
# Third donut + inner polygon
[
# Outer ring
[
PointCoordinate(0.10, 0.30),
PointCoordinate(0.22, 0.29),
PointCoordinate(0.21, 0.42),
PointCoordinate(0.09, 0.41),
PointCoordinate(0.10, 0.30),
],
# Inner ring
[
PointCoordinate(0.13, 0.33),
PointCoordinate(0.13, 0.38),
PointCoordinate(0.18, 0.38),
PointCoordinate(0.18, 0.33),
PointCoordinate(0.13, 0.33),
],
],
# Shape inside the hole
[
[
PointCoordinate(0.145, 0.345),
PointCoordinate(0.155, 0.355),
PointCoordinate(0.150, 0.370),
PointCoordinate(0.140, 0.360),
PointCoordinate(0.145, 0.345),
]
],
]
),
"blueberry_type": "Other blueberry type",
"Specify blueberry type": "Lowbush",
"blueberry_quality": 8
},
],
104: [
{
"label_ref": "blueberry_016",
"coordinates": PolygonCoordinates(
polygons=[
# Fourth donut + inner polygon
[
# Outer ring
[
PointCoordinate(0.30, 0.30),
PointCoordinate(0.42, 0.31),
PointCoordinate(0.41, 0.42),
PointCoordinate(0.29, 0.41),
PointCoordinate(0.30, 0.30),
],
# Inner ring
[
PointCoordinate(0.33, 0.33),
PointCoordinate(0.33, 0.38),
PointCoordinate(0.38, 0.38),
PointCoordinate(0.38, 0.33),
PointCoordinate(0.33, 0.33),
],
],
# Shape inside the hole
[
[
PointCoordinate(0.345, 0.345),
PointCoordinate(0.360, 0.350),
PointCoordinate(0.355, 0.365),
PointCoordinate(0.345, 0.345),
]
],
]
),
"blueberry_type": "Blueray",
"blueray_quality_options": "Plump",
"blueberry_quality": 7
},
{
"label_ref": "blueberry_014",
"coordinates": PolygonCoordinates(
polygons=[
# Second donut + inner polygon
[
# Outer ring
[
PointCoordinate(0.31, 0.10),
PointCoordinate(0.45, 0.12),
PointCoordinate(0.43, 0.25),
PointCoordinate(0.30, 0.22),
PointCoordinate(0.31, 0.10),
],
# Inner ring
[
PointCoordinate(0.34, 0.14),
PointCoordinate(0.34, 0.19),
PointCoordinate(0.39, 0.20),
PointCoordinate(0.40, 0.15),
PointCoordinate(0.34, 0.14),
],
],
# Shape inside the hole
[
[
PointCoordinate(0.355, 0.155),
PointCoordinate(0.370, 0.160),
PointCoordinate(0.365, 0.175),
PointCoordinate(0.350, 0.170),
PointCoordinate(0.355, 0.155),
]
],
]
),
"blueberry_type": "Bluegold",
"bluegold_quality_options": "Plump, Juicy, Large",
"blueberry_quality": 9
},
{
"label_ref": "blueberry_017",
"coordinates": PolygonCoordinates(
polygons=[
# Fifth donut + inner polygon
[
# Outer ring
[
PointCoordinate(0.50, 0.10),
PointCoordinate(0.62, 0.12),
PointCoordinate(0.61, 0.22),
PointCoordinate(0.49, 0.21),
PointCoordinate(0.50, 0.10),
],
# Inner ring
[
PointCoordinate(0.53, 0.13),
PointCoordinate(0.53, 0.18),
PointCoordinate(0.58, 0.18),
PointCoordinate(0.58, 0.13),
PointCoordinate(0.53, 0.13),
],
],
# Shape inside the hole
[
[
PointCoordinate(0.545, 0.145),
PointCoordinate(0.560, 0.150),
PointCoordinate(0.555, 0.165),
PointCoordinate(0.540, 0.160),
PointCoordinate(0.545, 0.145),
]
],
]
),
"blueberry_type": "Other blueberry type",
"Specify blueberry type": "Highbush",
"blueberry_quality": 2
},
],
105: [
{
"label_ref": "blueberry_016",
"coordinates": PolygonCoordinates(
polygons=[
# Fourth donut + inner polygon
[
# Outer ring
[
PointCoordinate(0.33, 0.33),
PointCoordinate(0.47, 0.34),
PointCoordinate(0.45, 0.46),
PointCoordinate(0.31, 0.45),
PointCoordinate(0.33, 0.33),
],
# Inner ring
[
PointCoordinate(0.36, 0.36),
PointCoordinate(0.37, 0.41),
PointCoordinate(0.42, 0.42),
PointCoordinate(0.43, 0.37),
PointCoordinate(0.36, 0.36),
],
],
# Shape inside the hole
[
[
PointCoordinate(0.375, 0.375),
PointCoordinate(0.395, 0.380),
PointCoordinate(0.390, 0.395),
PointCoordinate(0.370, 0.390),
PointCoordinate(0.375, 0.375),
]
],
]
),
"blueberry_type": "Blueray",
"blueray_quality_options": "Plump",
"blueberry_quality": 5
},
{
"label_ref": "blueberry_014",
"coordinates": PolygonCoordinates(
polygons=[
# Second donut + inner polygon
[
# Outer ring
[
PointCoordinate(0.33, 0.12),
PointCoordinate(0.46, 0.13),
PointCoordinate(0.44, 0.26),
PointCoordinate(0.31, 0.25),
PointCoordinate(0.33, 0.12),
],
# Inner ring
[
PointCoordinate(0.36, 0.16),
PointCoordinate(0.37, 0.21),
PointCoordinate(0.41, 0.22),
PointCoordinate(0.42, 0.17),
PointCoordinate(0.36, 0.16),
],
],
# Shape inside the hole
[
[
PointCoordinate(0.375, 0.175),
PointCoordinate(0.390, 0.180),
PointCoordinate(0.385, 0.195),
PointCoordinate(0.370, 0.190),
PointCoordinate(0.375, 0.175),
]
],
]
),
"blueberry_type": "Bluegold",
"bluegold_quality_options": "Plump, Juicy, Large",
"blueberry_quality": 8
},
{
"label_ref": "blueberry_017",
"coordinates": PolygonCoordinates(
polygons=[
# Fifth donut + inner polygon
[
# Outer ring
[
PointCoordinate(0.53, 0.13),
PointCoordinate(0.67, 0.14),
PointCoordinate(0.66, 0.26),
PointCoordinate(0.52, 0.25),
PointCoordinate(0.53, 0.13),
],
# Inner ring
[
PointCoordinate(0.56, 0.16),
PointCoordinate(0.57, 0.21),
PointCoordinate(0.62, 0.22),
PointCoordinate(0.63, 0.17),
PointCoordinate(0.56, 0.16),
],
],
# Shape inside the hole
[
[
PointCoordinate(0.575, 0.175),
PointCoordinate(0.595, 0.180),
PointCoordinate(0.590, 0.195),
PointCoordinate(0.570, 0.190),
PointCoordinate(0.575, 0.175),
]
],
]
),
"blueberry_type": "Other blueberry type",
"Specify blueberry type": "Highbush",
"blueberry_quality": 6
},
],
},
}
# Loop through each data unit (image, video, etc.)
for data_unit, frame_coordinates in video_frame_labels.items():
object_instances_by_label_ref = {}
# Get the label row for the current data unit
label_rows = project.list_label_rows_v2(data_title_eq=data_unit)
assert isinstance(label_rows, list), f"Expected list of label rows for '{data_unit}', got {type(label_rows)}"
assert label_rows, f"No label rows found for data unit: {data_unit}"
label_row = label_rows[0]
assert label_row is not None, f"Label row is None for {data_unit}"
# Initialize label row using bundle
with project.create_bundle(bundle_size=BUNDLE_SIZE) as bundle:
label_row.initialise_labels()
assert label_row.ontology_structure is not None, f"Ontology not initialized for label row: {data_unit}"
for frame_number, items in frame_coordinates.items():
assert isinstance(frame_number, int), f"Frame number must be int, got {type(frame_number)}"
if not isinstance(items, list): # Single or multiple objects in the frame
items = [items]
for item in items:
label_ref = item["label_ref"]
coord = item["coordinates"]
blueberry_type = item["blueberry_type"]
blueberry_quality = item["blueberry_quality"]
assert blueberry_type in {
"Bluegold",
"Duke",
"Blueray",
"Other blueberry type",
}, f"Unexpected blueberry type '{blueberry_type}' in data unit '{data_unit}'"
if label_ref not in object_instances_by_label_ref:
polygon_object_instance: ObjectInstance = polygon_ontology_object.create_instance()
assert polygon_object_instance is not None, f"Failed to create ObjectInstance for {label_ref}"
object_instances_by_label_ref[label_ref] = polygon_object_instance
checklist_attribute = None
# Set blueberry quality attribute
polygon_object_instance.set_answer(attribute=blueberry_quality_number_attribute, answer=blueberry_quality)
# Set blueberry type attribute
if blueberry_type == "Bluegold":
assert bluegold_option is not None, "Missing 'bluegold_option'"
polygon_object_instance.set_answer(
attribute=blueberry_type_radio_attribute, answer=bluegold_option
)
checklist_attribute = bluegold_checklist_attribute
elif blueberry_type == "Duke":
assert duke_option is not None, "Missing 'duke_option'"
polygon_object_instance.set_answer(attribute=blueberry_type_radio_attribute, answer=duke_option)
checklist_attribute = duke_checklist_attribute
elif blueberry_type == "Blueray":
assert blueray_option is not None, "Missing 'blueray_option'"
polygon_object_instance.set_answer(
attribute=blueberry_type_radio_attribute, answer=blueray_option
)
checklist_attribute = blueray_checklist_attribute
elif blueberry_type == "Other blueberry type":
assert other_blueberry_option is not None, "Missing 'other_blueberry_option'"
polygon_object_instance.set_answer(
attribute=blueberry_type_radio_attribute, answer=other_blueberry_option
)
text_answer = item.get("Specify blueberry type", "")
assert isinstance(text_answer, str), "'Specify blueberry type' must be a string"
polygon_object_instance.set_answer(
attribute=other_blueberry_option_text_attribute,
answer=text_answer,
)
# Set checklist attributes
checklist_answers = []
quality_key = f"{blueberry_type.lower()}_quality_options"
quality_options = item.get(quality_key, "").split(", ")
for quality in quality_options:
option = None
if quality == "Plump":
option = (
bluegold_plump_option
if blueberry_type == "Bluegold"
else duke_plump_option
if blueberry_type == "Duke"
else blueray_plump_option
if blueberry_type == "Blueray"
else None
)
elif quality == "Juicy":
option = (
bluegold_juicy_option
if blueberry_type == "Bluegold"
else duke_juicy_option
if blueberry_type == "Duke"
else blueray_juicy_option
if blueberry_type == "Blueray"
else None
)
elif quality == "Large":
option = (
bluegold_large_option
if blueberry_type == "Bluegold"
else duke_large_option
if blueberry_type == "Duke"
else blueray_large_option
if blueberry_type == "Blueray"
else None
)
if option:
checklist_answers.append(option)
else:
assert blueberry_type == "Other blueberry type", (
f"Invalid quality '{quality}' for type '{blueberry_type}'"
)
if checklist_attribute and checklist_answers:
polygon_object_instance.set_answer(
attribute=checklist_attribute, answer=checklist_answers, overwrite=True
)
else:
polygon_object_instance = object_instances_by_label_ref[label_ref]
# Assign the object to the frame and track it
polygon_object_instance.set_for_frames(coordinates=coord, frames=frame_number)
# Add object instances to label_row **only if they have frames assigned**
for polygon_object_instance in object_instances_by_label_ref.values():
assert isinstance(polygon_object_instance, ObjectInstance), "Expected ObjectInstance type"
if polygon_object_instance.get_annotation_frames():
label_row.add_object_instance(polygon_object_instance)
# Save label row using the bundle
assert label_row is not None, "Trying to save a None label row"
label_row.save(bundle=bundle)
print("Labels with blueberry type radio buttons, checklist attributes, number attributes, and text labels added for all data units.")
DEPRECATED - Polygons
DEPRECATED - Polygons
While this method works for simple polygons, we STRONGLY recommend using the new Polygon method for creating simple polygons.This example includes the following:
- Single image labeling
- Image Group labeling
- Image Sequence labeling
- Video labeling
- Radio button options
- Checklist options
- Text input
- Number input
Copy
# Import dependencies
from pathlib import Path
from encord import EncordUserClient, Project
from encord.objects import ChecklistAttribute, Object, ObjectInstance, Option, RadioAttribute, TextAttribute
from encord.objects.attributes import NumericAttribute
from encord.objects.coordinates import PointCoordinate, PolygonCoordinates
# User input
SSH_PATH = "/Users/chris-encord/ssh-private-key.txt"
# SSH_PATH = get_ssh_key() # replace it with access key
PROJECT_ID = "00000000-0000-0000-0000-000000000000"
BUNDLE_SIZE = 100
# Create user client using access key
user_client: EncordUserClient = EncordUserClient.create_with_ssh_private_key(
ssh_private_key_path=SSH_PATH,
# For US platform users use "https://api.us.encord.com"
domain="https://api.encord.com",
)
# Get project for which labels are to be added
project: Project = user_client.get_project(PROJECT_ID)
assert project is not None, "Project not found — check PROJECT_ID"
# Get ontology structure
ontology_structure = project.ontology_structure
assert ontology_structure is not None, "Ontology structure is missing in the project"
# Find polygon object for blueberries
polygon_ontology_object: Object = ontology_structure.get_child_by_title(title="Blueberries", type_=Object)
assert polygon_ontology_object is not None, "Object 'Blueberries' not found in ontology"
# Get radio attribute for blueberry type
blueberry_type_radio_attribute = ontology_structure.get_child_by_title(type_=RadioAttribute, title="Type?")
assert blueberry_type_radio_attribute is not None, "Radio attribute 'Type?' not found"
# Find number attribute in the ontology
blueberry_quality_number_attribute = ontology_structure.get_child_by_title(type_=NumericAttribute, title="Overall Quality")
assert blueberry_quality_number_attribute is not None, "Number attribute 'Overall Quality' not found in ontology."
# Get radio options
bluegold_option = blueberry_type_radio_attribute.get_child_by_title(type_=Option, title="Bluegold")
assert bluegold_option is not None, "Option 'Bluegold' not found under radio attribute 'Type?'"
duke_option = blueberry_type_radio_attribute.get_child_by_title(type_=Option, title="Duke")
assert duke_option is not None, "Option 'Duke' not found under radio attribute 'Type?'"
blueray_option = blueberry_type_radio_attribute.get_child_by_title(type_=Option, title="Blueray")
assert blueray_option is not None, "Option 'Blueray' not found under radio attribute 'Type?'"
other_blueberry_option = blueberry_type_radio_attribute.get_child_by_title(type_=Option, title="Other blueberry type")
assert other_blueberry_option is not None, "Option 'Other blueberry type' not found under radio attribute 'Type?'"
# Bluegold Qualities
bluegold_checklist_attribute = ontology_structure.get_child_by_title(
type_=ChecklistAttribute, title="Bluegold Qualities?"
)
assert bluegold_checklist_attribute is not None, "Checklist attribute 'Bluegold Qualities?' not found"
bluegold_plump_option = bluegold_checklist_attribute.get_child_by_title(type_=Option, title="Plump")
assert bluegold_plump_option is not None, "Option 'Plump' not found under 'Bluegold Qualities?'"
bluegold_juicy_option = bluegold_checklist_attribute.get_child_by_title(type_=Option, title="Juicy")
assert bluegold_juicy_option is not None, "Option 'Juicy' not found under 'Bluegold Qualities?'"
bluegold_large_option = bluegold_checklist_attribute.get_child_by_title(type_=Option, title="Large")
assert bluegold_large_option is not None, "Option 'Large' not found under 'Bluegold Qualities?'"
# Duke Qualities
duke_checklist_attribute = ontology_structure.get_child_by_title(type_=ChecklistAttribute, title="Duke Qualities?")
assert duke_checklist_attribute is not None, "Checklist attribute 'Duke Qualities?' not found"
duke_plump_option = duke_checklist_attribute.get_child_by_title(type_=Option, title="Plump")
assert duke_plump_option is not None, "Option 'Plump' not found under 'Duke Qualities?'"
duke_juicy_option = duke_checklist_attribute.get_child_by_title(type_=Option, title="Juicy")
assert duke_juicy_option is not None, "Option 'Juicy' not found under 'Duke Qualities?'"
duke_large_option = duke_checklist_attribute.get_child_by_title(type_=Option, title="Large")
assert duke_large_option is not None, "Option 'Large' not found under 'Duke Qualities?'"
# Blueray Qualities
blueray_checklist_attribute = ontology_structure.get_child_by_title(
type_=ChecklistAttribute, title="Blueray Qualities?"
)
assert blueray_checklist_attribute is not None, "Checklist attribute 'Blueray Qualities?' not found"
blueray_plump_option = blueray_checklist_attribute.get_child_by_title(type_=Option, title="Plump")
assert blueray_plump_option is not None, "Option 'Plump' not found under 'Blueray Qualities?'"
blueray_juicy_option = blueray_checklist_attribute.get_child_by_title(type_=Option, title="Juicy")
assert blueray_juicy_option is not None, "Option 'Juicy' not found under 'Blueray Qualities?'"
blueray_large_option = blueray_checklist_attribute.get_child_by_title(type_=Option, title="Large")
assert blueray_large_option is not None, "Option 'Large' not found under 'Blueray Qualities?'"
# Other blueberry type — text input
other_blueberry_option_text_attribute = ontology_structure.get_child_by_title(
type_=TextAttribute, title="Specify blueberry type"
)
assert other_blueberry_option_text_attribute is not None, "Text attribute 'Specify blueberry type' not found"
# Dictionary of labels per data unit and per frame with blueberry type specified, including quality options
video_frame_labels = {
"blueberries-001.jpg": {
0: {
"label_ref": "blueberry_001",
"coordinates": PolygonCoordinates(
[
PointCoordinate(0.01, 0.02),
PointCoordinate(0.03, 0.03),
PointCoordinate(0.05, 0.02),
PointCoordinate(0.04, 0.01),
PointCoordinate(0.02, 0.01),
]
),
"blueberry_type": "Bluegold",
"bluegold_quality_options": "Plump, Juicy",
"blueberry_quality": 7
}
},
"blueberries-010.jpg": {
0: [
{
"label_ref": "blueberry_002",
"coordinates": PolygonCoordinates(
[
PointCoordinate(0.01, 0.02),
PointCoordinate(0.03, 0.03),
PointCoordinate(0.05, 0.02),
PointCoordinate(0.04, 0.01),
PointCoordinate(0.02, 0.01),
]
),
"blueberry_type": "Duke",
"duke_quality_options": "Plump, Juicy, Large",
"blueberry_quality": 9
},
{
"label_ref": "blueberry_003",
"coordinates": PolygonCoordinates(
[
PointCoordinate(0.04, 0.05),
PointCoordinate(0.06, 0.06),
PointCoordinate(0.08, 0.05),
PointCoordinate(0.07, 0.04),
PointCoordinate(0.05, 0.04),
]
),
"blueberry_type": "Blueray",
"blueray_quality_options": "Plump",
},
{
"label_ref": "blueberry_004",
"coordinates": PolygonCoordinates(
[
PointCoordinate(0.07, 0.02),
PointCoordinate(0.09, 0.03),
PointCoordinate(0.11, 0.02),
PointCoordinate(0.10, 0.01),
PointCoordinate(0.08, 0.01),
]
),
"blueberry_type": "Other blueberry type",
"Specify blueberry type": "Highbush",
},
],
},
"blueberries-ig": {
0: {
"label_ref": "blueberry_005",
"coordinates": PolygonCoordinates(
[
PointCoordinate(0.01, 0.02),
PointCoordinate(0.03, 0.03),
PointCoordinate(0.05, 0.02),
PointCoordinate(0.04, 0.01),
PointCoordinate(0.02, 0.01),
]
),
"blueberry_type": "Bluegold",
"bluegold_quality_options": "Plump, Juicy",
"blueberry_quality": 8
},
2: [
{
"label_ref": "blueberry_006",
"coordinates": PolygonCoordinates(
[
PointCoordinate(0.01, 0.02),
PointCoordinate(0.03, 0.03),
PointCoordinate(0.05, 0.02),
PointCoordinate(0.04, 0.01),
PointCoordinate(0.02, 0.01),
]
),
"blueberry_type": "Duke",
"duke_quality_options": "Large",
"blueberry_quality": 7
},
{
"label_ref": "blueberry_007",
"coordinates": PolygonCoordinates(
[
PointCoordinate(0.04, 0.05),
PointCoordinate(0.06, 0.06),
PointCoordinate(0.08, 0.05),
PointCoordinate(0.07, 0.04),
PointCoordinate(0.05, 0.04),
]
),
"blueberry_type": "Blueray",
"blueray_quality_options": "Plump",
"blueberry_quality": 4
},
{
"label_ref": "blueberry_008",
"coordinates": PolygonCoordinates(
[
PointCoordinate(0.07, 0.02),
PointCoordinate(0.09, 0.03),
PointCoordinate(0.11, 0.02),
PointCoordinate(0.10, 0.01),
PointCoordinate(0.08, 0.01),
]
),
"blueberry_type": "Other blueberry type",
"Specify blueberry type": "Lowbush",
"blueberry_quality": 3
},
],
},
"blueberries-is": {
0: {
"label_ref": "blueberry_009",
"coordinates": PolygonCoordinates(
[
PointCoordinate(0.01, 0.02),
PointCoordinate(0.03, 0.03),
PointCoordinate(0.05, 0.02),
PointCoordinate(0.04, 0.01),
PointCoordinate(0.02, 0.01),
]
),
"blueberry_type": "Bluegold",
"bluegold_quality_options": "Plump",
"blueberry_quality": 5
},
3: [
{
"label_ref": "blueberry_010",
"coordinates": PolygonCoordinates(
[
PointCoordinate(0.01, 0.02),
PointCoordinate(0.03, 0.03),
PointCoordinate(0.05, 0.02),
PointCoordinate(0.04, 0.01),
PointCoordinate(0.02, 0.01),
]
),
"blueberry_type": "Duke",
"duke_quality_options": "Plump, Juicy, Large",
"blueberry_quality": 9
},
{
"label_ref": "blueberry_011",
"coordinates": PolygonCoordinates(
[
PointCoordinate(0.04, 0.05),
PointCoordinate(0.06, 0.06),
PointCoordinate(0.08, 0.05),
PointCoordinate(0.07, 0.04),
PointCoordinate(0.05, 0.04),
]
),
"blueberry_type": "Blueray",
"blueray_quality_options": "Plump",
"blueberry_quality": 5
},
{
"label_ref": "blueberry_012",
"coordinates": PolygonCoordinates(
[
PointCoordinate(0.07, 0.02),
PointCoordinate(0.09, 0.03),
PointCoordinate(0.11, 0.02),
PointCoordinate(0.10, 0.01),
PointCoordinate(0.08, 0.01),
]
),
"blueberry_type": "Other blueberry type",
"Specify blueberry type": "Powder Blue",
"blueberry_quality": 4
},
],
},
"blueberries-vid-001.mp4": {
103: [
{
"label_ref": "blueberry_013",
"coordinates": PolygonCoordinates(
[
PointCoordinate(0.01, 0.02),
PointCoordinate(0.03, 0.03),
PointCoordinate(0.05, 0.02),
PointCoordinate(0.04, 0.01),
PointCoordinate(0.02, 0.01),
]
),
"blueberry_type": "Blueray",
"blueray_quality_options": "Plump",
"blueberry_quality": 4
},
{
"label_ref": "blueberry_014",
"coordinates": PolygonCoordinates(
[
PointCoordinate(0.04, 0.05),
PointCoordinate(0.06, 0.06),
PointCoordinate(0.08, 0.05),
PointCoordinate(0.07, 0.04),
PointCoordinate(0.05, 0.04),
]
),
"blueberry_type": "Bluegold",
"bluegold_quality_options": "Plump, Juicy, Large",
"blueberry_quality": 9
},
{
"label_ref": "blueberry_015",
"coordinates": PolygonCoordinates(
[
PointCoordinate(0.07, 0.02),
PointCoordinate(0.09, 0.03),
PointCoordinate(0.11, 0.02),
PointCoordinate(0.10, 0.01),
PointCoordinate(0.08, 0.01),
]
),
"blueberry_type": "Other blueberry type",
"Specify blueberry type": "Lowbush",
"blueberry_quality": 6
},
],
104: [
{
"label_ref": "blueberry_016",
"coordinates": PolygonCoordinates(
[
PointCoordinate(0.01, 0.02),
PointCoordinate(0.03, 0.03),
PointCoordinate(0.05, 0.02),
PointCoordinate(0.04, 0.01),
PointCoordinate(0.02, 0.01),
]
),
"blueberry_type": "Blueray",
"blueray_quality_options": "Plump",
},
{
"label_ref": "blueberry_014",
"coordinates": PolygonCoordinates(
[
PointCoordinate(0.041, 0.052),
PointCoordinate(0.061, 0.062),
PointCoordinate(0.081, 0.052),
PointCoordinate(0.071, 0.042),
PointCoordinate(0.051, 0.042),
]
),
"blueberry_type": "Bluegold",
"bluegold_quality_options": "Plump, Juicy, Large",
"blueberry_quality": 9
},
{
"label_ref": "blueberry_017",
"coordinates": PolygonCoordinates(
[
PointCoordinate(0.07, 0.02),
PointCoordinate(0.09, 0.03),
PointCoordinate(0.11, 0.02),
PointCoordinate(0.10, 0.01),
PointCoordinate(0.08, 0.01),
]
),
"blueberry_type": "Other blueberry type",
"Specify blueberry type": "Highbush",
"blueberry_quality": 6
},
],
105: [
{
"label_ref": "blueberry_016",
"coordinates": PolygonCoordinates(
[
PointCoordinate(0.011, 0.022),
PointCoordinate(0.031, 0.032),
PointCoordinate(0.051, 0.022),
PointCoordinate(0.041, 0.012),
PointCoordinate(0.021, 0.012),
]
),
"blueberry_type": "Blueray",
"blueray_quality_options": "Plump",
"blueberry_quality": 6
},
{
"label_ref": "blueberry_014",
"coordinates": PolygonCoordinates(
[
PointCoordinate(0.043, 0.055),
PointCoordinate(0.063, 0.065),
PointCoordinate(0.083, 0.055),
PointCoordinate(0.073, 0.045),
PointCoordinate(0.053, 0.045),
]
),
"blueberry_type": "Bluegold",
"bluegold_quality_options": "Plump, Juicy, Large",
"blueberry_quality": 7
},
{
"label_ref": "blueberry_017",
"coordinates": PolygonCoordinates(
[
PointCoordinate(0.071, 0.022),
PointCoordinate(0.091, 0.032),
PointCoordinate(0.111, 0.022),
PointCoordinate(0.101, 0.012),
PointCoordinate(0.081, 0.012),
]
),
"blueberry_type": "Other blueberry type",
"Specify blueberry type": "Powder Blue",
"blueberry_quality": 1
},
],
},
}
# Loop through each data unit (image, video, etc.)
for data_unit, frame_coordinates in video_frame_labels.items():
object_instances_by_label_ref = {}
# Get the label row for the current data unit
label_rows = project.list_label_rows_v2(data_title_eq=data_unit)
assert isinstance(label_rows, list), f"Expected list of label rows for '{data_unit}', got {type(label_rows)}"
assert label_rows, f"No label rows found for data unit: {data_unit}"
label_row = label_rows[0]
assert label_row is not None, f"Label row is None for {data_unit}"
# Initialize label row using bundle
with project.create_bundle(bundle_size=BUNDLE_SIZE) as bundle:
label_row.initialise_labels()
assert label_row.ontology_structure is not None, f"Ontology not initialized for label row: {data_unit}"
for frame_number, items in frame_coordinates.items():
assert isinstance(frame_number, int), f"Frame number must be int, got {type(frame_number)}"
if not isinstance(items, list): # Single or multiple objects in the frame
items = [items]
for item in items:
label_ref = item["label_ref"]
coord = item["coordinates"]
blueberry_type = item["blueberry_type"]
blueberry_quality = item["blueberry_quality"]
assert blueberry_type in {
"Bluegold",
"Duke",
"Blueray",
"Other blueberry type",
}, f"Unexpected blueberry type '{blueberry_type}' in data unit '{data_unit}'"
if label_ref not in object_instances_by_label_ref:
polygon_object_instance: ObjectInstance = polygon_ontology_object.create_instance()
assert polygon_object_instance is not None, f"Failed to create ObjectInstance for {label_ref}"
object_instances_by_label_ref[label_ref] = polygon_object_instance
checklist_attribute = None
# Set blueberry quality attribute
polygon_object_instance.set_answer(attribute=blueberry_quality_number_attribute, answer=blueberry_quality)
# Set blueberry type attribute
if blueberry_type == "Bluegold":
assert bluegold_option is not None, "Missing 'bluegold_option'"
polygon_object_instance.set_answer(
attribute=blueberry_type_radio_attribute, answer=bluegold_option
)
checklist_attribute = bluegold_checklist_attribute
elif blueberry_type == "Duke":
assert duke_option is not None, "Missing 'duke_option'"
polygon_object_instance.set_answer(attribute=blueberry_type_radio_attribute, answer=duke_option)
checklist_attribute = duke_checklist_attribute
elif blueberry_type == "Blueray":
assert blueray_option is not None, "Missing 'blueray_option'"
polygon_object_instance.set_answer(
attribute=blueberry_type_radio_attribute, answer=blueray_option
)
checklist_attribute = blueray_checklist_attribute
elif blueberry_type == "Other blueberry type":
assert other_blueberry_option is not None, "Missing 'other_blueberry_option'"
polygon_object_instance.set_answer(
attribute=blueberry_type_radio_attribute, answer=other_blueberry_option
)
text_answer = item.get("Specify blueberry type", "")
assert isinstance(text_answer, str), "'Specify blueberry type' must be a string"
polygon_object_instance.set_answer(
attribute=other_blueberry_option_text_attribute,
answer=text_answer,
)
# Set checklist attributes
checklist_answers = []
quality_key = f"{blueberry_type.lower()}_quality_options"
quality_options = item.get(quality_key, "").split(", ")
for quality in quality_options:
option = None
if quality == "Plump":
option = (
bluegold_plump_option
if blueberry_type == "Bluegold"
else duke_plump_option
if blueberry_type == "Duke"
else blueray_plump_option
if blueberry_type == "Blueray"
else None
)
elif quality == "Juicy":
option = (
bluegold_juicy_option
if blueberry_type == "Bluegold"
else duke_juicy_option
if blueberry_type == "Duke"
else blueray_juicy_option
if blueberry_type == "Blueray"
else None
)
elif quality == "Large":
option = (
bluegold_large_option
if blueberry_type == "Bluegold"
else duke_large_option
if blueberry_type == "Duke"
else blueray_large_option
if blueberry_type == "Blueray"
else None
)
if option:
checklist_answers.append(option)
else:
assert blueberry_type == "Other blueberry type", (
f"Invalid quality '{quality}' for type '{blueberry_type}'"
)
if checklist_attribute and checklist_answers:
polygon_object_instance.set_answer(
attribute=checklist_attribute, answer=checklist_answers, overwrite=True
)
else:
polygon_object_instance = object_instances_by_label_ref[label_ref]
# Assign the object to the frame and track it
polygon_object_instance.set_for_frames(coordinates=coord, frames=frame_number)
# Add object instances to label_row **only if they have frames assigned**
for polygon_object_instance in object_instances_by_label_ref.values():
assert isinstance(polygon_object_instance, ObjectInstance), "Expected ObjectInstance type"
if polygon_object_instance.get_annotation_frames():
label_row.add_object_instance(polygon_object_instance)
# Save label row using the bundle
assert label_row is not None, "Trying to save a None label row"
label_row.save(bundle=bundle)
print("Labels with blueberry type radio buttons, checklist attributes, number attributes, and text labels added for all data units.")
Polyline
Polyline
BasicThis example includes the following:
- Single image labeling
- Image Group labeling
- Image Sequence labeling
- Video labeling
- Single image labeling
- Image Group labeling
- Image Sequence labeling
- Video labeling
- Radio button options
- Checklist options
- Text input
- Number input

Copy
from encord import EncordUserClient, Project
from encord.objects import Object, ObjectInstance
from encord.objects.coordinates import PolylineCoordinates, PointCoordinate
# User input
SSH_PATH = "/Users/chris-encord/ssh-private-key.txt" # Replace with the file path to your SSH private key
PROJECT_ID = "00000000-0000-0000-0000-000000000000" # Replace with the unique Project ID
BUNDLE_SIZE = 10
# Data unit titles in your Project
IMAGE_TITLE = "cherries-001.jpg"
IMG_GROUP_TITLE = "cherries-ig"
IMG_SEQUENCE_TITLE = "cherries-is"
VIDEO_TITLE = "cherries-vid-001.mp4"
# Ontology object title for your POLYLINE object
POLYLINE_OBJECT_TITLE = "Branches"
# Authorize connection to Encord
user_client: EncordUserClient = EncordUserClient.create_with_ssh_private_key(
ssh_private_key_path=SSH_PATH,
# For US platform users use domain="https://api.us.encord.com"
domain="https://api.encord.com",
)
project: Project = user_client.get_project(PROJECT_ID)
# Find a POLYLINE object in the ontology by title
ontology_structure = project.ontology_structure
polyline_object: Object = ontology_structure.get_child_by_title(title=POLYLINE_OBJECT_TITLE, type_=Object)
assert polyline_object is not None, f"Polyline object '{POLYLINE_OBJECT_TITLE}' not found in ontology."
# Initialise label rows
label_rows = {}
all_titles = [IMAGE_TITLE, IMG_GROUP_TITLE, IMG_SEQUENCE_TITLE, VIDEO_TITLE]
with project.create_bundle(bundle_size=BUNDLE_SIZE) as bundle:
for title in all_titles:
rows = project.list_label_rows_v2(data_title_eq=title)
assert isinstance(rows, list), f"Expected list for '{title}', got {type(rows)}"
if not rows:
print(f"Skipping: No label row found for {title}")
continue
lr = rows[0]
lr.initialise_labels(bundle=bundle)
assert lr.ontology_structure is not None, f"Ontology not initialized for '{title}'"
label_rows[title] = lr
# Polyline coordinates: A simple bent line with 5 vertices
pline = PolylineCoordinates([
PointCoordinate(0.10, 0.80),
PointCoordinate(0.20, 0.60),
PointCoordinate(0.40, 0.55),
PointCoordinate(0.65, 0.40),
PointCoordinate(0.85, 0.35),
])
# Create instances and attach to frames
label_rows_to_save = []
# 1. One image > frame 0
image_lr = label_rows.get(IMAGE_TITLE)
if image_lr is not None:
inst: ObjectInstance = polyline_object.create_instance()
inst.set_for_frames(coordinates=pline, frames=0)
image_lr.add_object_instance(inst)
label_rows_to_save.append(image_lr)
# 2. One image group > frame 0
img_group_lr = label_rows.get(IMG_GROUP_TITLE)
if img_group_lr is not None:
inst: ObjectInstance = polyline_object.create_instance()
inst.set_for_frames(coordinates=pline, frames=0)
img_group_lr.add_object_instance(inst)
label_rows_to_save.append(img_group_lr)
# 3. One image sequence > frame 0
img_sequence_lr = label_rows.get(IMG_SEQUENCE_TITLE)
if img_sequence_lr is not None:
inst: ObjectInstance = polyline_object.create_instance()
inst.set_for_frames(coordinates=pline, frames=0)
img_sequence_lr.add_object_instance(inst)
label_rows_to_save.append(img_sequence_lr)
# 4. One video > reuse SAME instance across 3 consecutive frames (frames 100, 101, 102)
video_lr = label_rows.get(VIDEO_TITLE)
if video_lr is not None:
inst: ObjectInstance = polyline_object.create_instance()
for f in [100, 101, 102]:
inst.set_for_frames(coordinates=pline, frames=f)
video_lr.add_object_instance(inst)
label_rows_to_save.append(video_lr)
# Save label rows
with project.create_bundle(bundle_size=BUNDLE_SIZE) as bundle:
for lr in label_rows_to_save:
lr.save(bundle=bundle)
print(f"Saved label row for {lr.data_title}")
print("Done: created one polyline on image, image group, image sequence, and 3 video frames.")
Keypoint
Keypoint
BasicThis example includes the following:
- Single image labeling
- Image Group labeling
- Image Sequence labeling
- Video labeling
- Single image labeling
- Image Group labeling
- Image Sequence labeling
- Video labeling
- Radio button options
- Checklist options
- Text input
- Number input

Copy
from encord import EncordUserClient, Project
from encord.objects import Object, ObjectInstance
from encord.objects.coordinates import PointCoordinate
# User input
SSH_PATH = "/Users/chris-encord/ssh-private-key.txt" # Replace with the file path to your SSH private key
PROJECT_ID = "00000000-0000-0000-0000-000000000000" # Replace with the unique Project ID
BUNDLE_SIZE = 10
# Data unit titles in your Project
IMAGE_TITLE = "blueberries-001.jpg"
IMG_GROUP_TITLE = "blueberries-ig"
IMG_SEQUENCE_TITLE = "blueberries-is"
VIDEO_TITLE = "blueberries-vid-001.mp4"
# Ontology object title for your KEYPOINT object
KEYPOINT_OBJECT_TITLE = "Floral axis"
# Authorize connection to Encord
user_client: EncordUserClient = EncordUserClient.create_with_ssh_private_key(
ssh_private_key_path=SSH_PATH,
# For US platform users use domain="https://api.us.encord.com"
domain="https://api.encord.com",
)
project: Project = user_client.get_project(PROJECT_ID)
# Find a KEYPOINT object in the ontology by title
ontology_structure = project.ontology_structure
keypoint_object: Object = ontology_structure.get_child_by_title(title=KEYPOINT_OBJECT_TITLE, type_=Object)
assert keypoint_object is not None, f"Keypoint object '{KEYPOINT_OBJECT_TITLE}' not found in ontology."
# Initialise label rows
label_rows = {}
all_titles = [IMAGE_TITLE, IMG_GROUP_TITLE, IMG_SEQUENCE_TITLE, VIDEO_TITLE]
with project.create_bundle(bundle_size=BUNDLE_SIZE) as bundle:
for title in all_titles:
rows = project.list_label_rows_v2(data_title_eq=title)
assert isinstance(rows, list), f"Expected list for '{title}', got {type(rows)}"
if not rows:
print(f"Skipping: No label row found for {title}")
continue
lr = rows[0]
lr.initialise_labels(bundle=bundle)
assert lr.ontology_structure is not None, f"Ontology not initialized for '{title}'"
label_rows[title] = lr
# Keypoint coordinates: A single point roughly near the center
kp = PointCoordinate(0.5, 0.5)
# Create instances and attach to frames
label_rows_to_save = []
# 1. One image > frame 0
image_lr = label_rows.get(IMAGE_TITLE)
if image_lr is not None:
inst: ObjectInstance = keypoint_object.create_instance()
inst.set_for_frames(coordinates=kp, frames=0)
image_lr.add_object_instance(inst)
label_rows_to_save.append(image_lr)
# 2. One image group > frame 0
img_group_lr = label_rows.get(IMG_GROUP_TITLE)
if img_group_lr is not None:
inst: ObjectInstance = keypoint_object.create_instance()
inst.set_for_frames(coordinates=kp, frames=0)
img_group_lr.add_object_instance(inst)
label_rows_to_save.append(img_group_lr)
# 3. One image sequence > frame 0
img_sequence_lr = label_rows.get(IMG_SEQUENCE_TITLE)
if img_sequence_lr is not None:
inst: ObjectInstance = keypoint_object.create_instance()
inst.set_for_frames(coordinates=kp, frames=0)
img_sequence_lr.add_object_instance(inst)
label_rows_to_save.append(img_sequence_lr)
# 4. One video > reuse SAME instance across 3 consecutive frames (frames 100, 101, 102)
video_lr = label_rows.get(VIDEO_TITLE)
if video_lr is not None:
inst: ObjectInstance = keypoint_object.create_instance()
for f in [100, 101, 102]:
inst.set_for_frames(coordinates=kp, frames=f)
video_lr.add_object_instance(inst)
label_rows_to_save.append(video_lr)
# Save label rows
with project.create_bundle(bundle_size=BUNDLE_SIZE) as bundle:
for lr in label_rows_to_save:
lr.save(bundle=bundle)
print(f"Saved label row for {lr.data_title}")
print("Done: created one keypoint on image, image group, image sequence, and 3 video frames.")
Bitmask
Bitmask
BasicThis example includes the following:
- Single image labeling
- Image Group labeling
- Image Sequence labeling
- Video labeling
- Single image labeling
- Image Group labeling
- Image Sequence labeling
- Video labeling
- Radio button options
- Checklist options
- Text input
- Number input

Copy
from encord import EncordUserClient, Project
from encord.objects import Object, ObjectInstance
from encord.objects.coordinates import BitmaskCoordinates
import numpy as np
# User input
SSH_PATH = "/Users/chris-encord/ssh-private-key.txt" # Replace with your SSH private key
PROJECT_ID = "00000000-0000-0000-0000-000000000000" # Replace with your Project ID
BUNDLE_SIZE = 10
# Data unit titles in your Project
IMAGE_TITLE = "apples-001.jpg"
IMG_GROUP_TITLE = "apples-ig"
IMG_SEQUENCE_TITLE = "apples-is"
VIDEO_TITLE = "apples-vid-001.mp4"
# Fixed frame size
FRAME_H, FRAME_W = 1080, 1920
# Authorize connection to Encord
user_client: EncordUserClient = EncordUserClient.create_with_ssh_private_key(
ssh_private_key_path=SSH_PATH,
# For US platform users use domain="https://api.us.encord.com"
domain="https://api.encord.com",
)
project: Project = user_client.get_project(PROJECT_ID)
# Find the bitmask object "Apples" in the ontology
ontology_structure = project.ontology_structure
bitmask_ontology_object: Object = ontology_structure.get_child_by_title(title="Apples", type_=Object)
assert bitmask_ontology_object is not None, "Bitmask object 'Apples' not found in ontology."
# Initialise label rows
label_rows = {}
all_titles = [IMAGE_TITLE, IMG_GROUP_TITLE, IMG_SEQUENCE_TITLE, VIDEO_TITLE]
with project.create_bundle(bundle_size=BUNDLE_SIZE) as bundle:
for title in all_titles:
rows = project.list_label_rows_v2(data_title_eq=title)
assert isinstance(rows, list), f"Expected list for '{title}', got {type(rows)}"
if not rows:
print(f"Skipping: No label row found for {title}")
continue
lr = rows[0]
lr.initialise_labels(bundle=bundle)
assert lr.ontology_structure is not None, f"Ontology not initialized for '{title}'"
label_rows[title] = lr
# Prepare boolean masks with shape matching frame size
mask_a_arr = np.ones((FRAME_H, FRAME_W), dtype=bool)
assert mask_a_arr.shape == (FRAME_H, FRAME_W), "Mask dimensions must match 1080x1920"
mask_b_arr = np.zeros((FRAME_H, FRAME_W), dtype=bool)
mask_b_arr[0:FRAME_H//3, 0:FRAME_W//3] = True
assert mask_b_arr.shape == (FRAME_H, FRAME_W), "Mask dimensions must match 1080x1920"
mask_c_arr = np.zeros((FRAME_H, FRAME_W), dtype=bool)
mask_c_arr[FRAME_H//4:FRAME_H//2, FRAME_W//4:FRAME_W//2] = True
assert mask_c_arr.shape == (FRAME_H, FRAME_W), "Mask dimensions must match 1080x1920"
mask_a = BitmaskCoordinates(mask_a_arr)
mask_b = BitmaskCoordinates(mask_b_arr)
mask_c = BitmaskCoordinates(mask_c_arr)
# Create instances and attach to frames
label_rows_to_save = []
# 1. One image > annotate frame 0
image_lr = label_rows.get(IMAGE_TITLE)
if image_lr is not None:
inst: ObjectInstance = bitmask_ontology_object.create_instance()
inst.set_for_frames(coordinates=mask_a, frames=0, manual_annotation=True)
image_lr.add_object_instance(inst)
label_rows_to_save.append(image_lr)
# 2. One image group > annotate frame 0
img_group_lr = label_rows.get(IMG_GROUP_TITLE)
if img_group_lr is not None:
inst: ObjectInstance = bitmask_ontology_object.create_instance()
inst.set_for_frames(coordinates=mask_b, frames=0, manual_annotation=True)
img_group_lr.add_object_instance(inst)
label_rows_to_save.append(img_group_lr)
# 3. One image sequence > annotate frame 0
img_sequence_lr = label_rows.get(IMG_SEQUENCE_TITLE)
if img_sequence_lr is not None:
inst: ObjectInstance = bitmask_ontology_object.create_instance()
inst.set_for_frames(coordinates=mask_c, frames=0, manual_annotation=True)
img_sequence_lr.add_object_instance(inst)
label_rows_to_save.append(img_sequence_lr)
# 4. One video > reuse SAME instance across 3 consecutive frames (100, 101, 102)
video_lr = label_rows.get(VIDEO_TITLE)
if video_lr is not None:
inst: ObjectInstance = bitmask_ontology_object.create_instance()
for f, bm in zip([100, 101, 102], [mask_a, mask_b, mask_c]):
inst.set_for_frames(coordinates=bm, frames=f, manual_annotation=True)
video_lr.add_object_instance(inst)
label_rows_to_save.append(video_lr)
# Save label rows
with project.create_bundle(bundle_size=BUNDLE_SIZE) as bundle:
for lr in label_rows_to_save:
lr.save(bundle=bundle)
print(f"Saved label row for {lr.data_title}")
print("Done: created bitmasks on image, image group, image sequence, and 3 video frames for 'Apples'.")
Object Primitives
Object Primitives
Before you can import Object Primitive labels into Encord, the Object Primitive Template MUST exist in Encord. Use the UI to create the Object Primitive Template so you can visually inspect the Object Primitive.
- Single image labeling
- Image Group labeling
- Image Sequence labeling
- Video labeling
- Single image labeling
- Image Group labeling
- Image Sequence labeling
- Video labeling
- Radio button options
- Checklist options
- Text input
- Number input

Copy
from encord import EncordUserClient, Project
from encord.objects import Object, ObjectInstance
from encord.objects.coordinates import SkeletonCoordinate, SkeletonCoordinates
from encord.objects.skeleton_template import SkeletonTemplate
# User input
SSH_PATH = "/Users/chris-encord/ssh-private-key.txt" # Replace with the file path to your SSH private key
PROJECT_ID = "00000000-0000-0000-0000-000000000000" # Replace with the unique Project ID
BUNDLE_SIZE = 10
IMAGE_TITLE = "cherries-001.jpg"
IMG_GROUP_TITLE = "cherries-ig"
IMG_SEQUENCE_TITLE = "cherries-is"
VIDEO_TITLE = "cherries-vid-001.mp4"
# Authorize connection to Encord
user_client: EncordUserClient = EncordUserClient.create_with_ssh_private_key(
ssh_private_key_path=SSH_PATH,
# For US platform users use domain="https://api.us.encord.com"
domain="https://api.encord.com",
)
project: Project = user_client.get_project(PROJECT_ID)
# Ontology pieces
ontology = project.ontology_structure
skeleton_object: Object = ontology.get_child_by_title(title="Strawberries", type_=Object)
assert skeleton_object is not None, "Ontology object 'Strawberries' not found."
# The primitive template your object uses
assert "Triangle" in ontology.skeleton_templates, "Skeleton template 'Triangle' not found in ontology."
template: SkeletonTemplate = ontology.skeleton_templates["Triangle"]
# Grab the point ids defined by the template
point_ids = [pt.feature_hash for pt in template.skeleton.values()]
assert len(point_ids) >= 3, "Template 'Triangle' should have at least 3 points."
# Coordinate set
tri_coords = SkeletonCoordinates(
values=[
SkeletonCoordinate(x=0.30, y=0.30, name="point_0", color="#000000", value="point_0", feature_hash=point_ids[0]),
SkeletonCoordinate(x=0.45, y=0.30, name="point_1", color="#000000", value="point_1", feature_hash=point_ids[1]),
SkeletonCoordinate(x=0.35, y=0.45, name="point_2", color="#000000", value="point_2", feature_hash=point_ids[2]),
],
name="Triangle",
)
# Initialize label rows
label_rows = {}
with project.create_bundle(bundle_size=BUNDLE_SIZE) as bundle:
for title in [IMAGE_TITLE, IMG_GROUP_TITLE, IMG_SEQUENCE_TITLE, VIDEO_TITLE]:
rows = project.list_label_rows_v2(data_title_eq=title)
assert isinstance(rows, list), f"Expected list for '{title}', got {type(rows)}"
if not rows:
print(f"Skipping: No label row found for {title}")
continue
lr = rows[0]
lr.initialise_labels(bundle=bundle)
assert lr.ontology_structure is not None, f"Ontology not initialized for '{title}'"
label_rows[title] = lr
# Create one skeleton instance per data unit and assign frames
to_save = []
# 1. One image > frame 0
lr = label_rows.get(IMAGE_TITLE)
if lr:
inst: ObjectInstance = skeleton_object.create_instance()
inst.set_for_frames(coordinates=tri_coords, frames=0)
lr.add_object_instance(inst)
to_save.append(lr)
# 2. One image group > frame 0
lr = label_rows.get(IMG_GROUP_TITLE)
if lr:
inst: ObjectInstance = skeleton_object.create_instance()
inst.set_for_frames(coordinates=tri_coords, frames=0)
lr.add_object_instance(inst)
to_save.append(lr)
# 3. One image sequence > frame 0
lr = label_rows.get(IMG_SEQUENCE_TITLE)
if lr:
inst: ObjectInstance = skeleton_object.create_instance()
inst.set_for_frames(coordinates=tri_coords, frames=0)
lr.add_object_instance(inst)
to_save.append(lr)
# 4. One video > reuse same instance across 3 consecutive frames
lr = label_rows.get(VIDEO_TITLE)
if lr:
inst: ObjectInstance = skeleton_object.create_instance()
for f in [100, 101, 102]:
inst.set_for_frames(coordinates=tri_coords, frames=f)
lr.add_object_instance(inst)
to_save.append(lr)
# Save label rows
with project.create_bundle(bundle_size=BUNDLE_SIZE) as bundle:
for lr in to_save:
lr.save(bundle=bundle)
print(f"Saved label row for {lr.data_title}")
print("Done: placed a minimal 'Strawberries' skeleton (Triangle) on image, image group, image sequence, and 3 video frames.")
Classifications
Text Classification
Text Classification
The following example assumes the Ontology includes a text classification field named
Mood
. In this example, the text classification for the first label row (data unit) in the Project is set to Melancholy
on the first frame.- Replace
<private_key_path>
with the key to your private key for authentication. - Replace
<project_hash>
with the hash of your Project. - Replace the Classification names and answers to suit your needs.
Copy
# Import dependencies
from typing import List
from encord import EncordUserClient
from encord.objects import LabelRowV2, Classification, ClassificationInstance, OntologyStructure
# Instantiate Encord client by replacing <private_key_path> with the path to your private key
user_client = EncordUserClient.create_with_ssh_private_key(
ssh_private_key_path="<private_key_path>"
)
# Specify the Project. Replace <project_hash> with the hash of your Project
project = user_client.get_project("<project_hash>")
# For simplicity, get only the first label row
first_label_row: List[LabelRowV2] = project.list_label_rows_v2()[0]
# Download the existing labels
first_label_row.initialise_labels()
# Get Ontology Structure
ontology_structure: OntologyStructure = first_label_row.ontology_structure
# Assume that the following text classification exists in the Ontology.
text_ontology_classification: Classification = (
ontology_structure.get_child_by_title(
title="Mood", type_=Classification
)
)
text_classification_instance = text_ontology_classification.create_instance()
# Set the value of the classification instance
text_classification_instance.set_answer(answer="Melancholy")
# Select the frames where the classification instance is present
text_classification_instance.set_for_frames(frames=0)
# Add it to the label row
first_label_row.add_classification_instance(text_classification_instance)
# Save labels
first_label_row.save()
Text
Text
Example 1:Adds a Text classification to a specific data unit. Ensure you replace
<data-unit-name>
with the name of the data unit you want to add the classification to.Example 2:Adds a Text attribute to an arbitrary bounding box on a specific data unit. Ensure you replace <data-unit-name>
with the name of the data unit you want to add the classification to, and <project_id>
with the unique ID of the Project.Copy
from encord import EncordUserClient
from encord.objects import OntologyStructure, Classification
user_client = EncordUserClient.create_with_ssh_private_key(
ssh_private_key_path="<private_key_path>"
)
project = user_client.get_project("<project_id>")
label_row = project.list_label_rows_v2(
data_title_eq="<data-unit-name>"
)[0]
label_row.initialise_labels()
# Get Ontology Structure
ontology_structure: OntologyStructure = label_row.ontology_structure
# Assume that the following text classification exists in the Ontology.
text_ontology_classification: Classification = (
ontology_structure.get_child_by_title(
title="Name", type_=Classification
)
)
text_classification_instance = text_ontology_classification.create_instance()
# Set the value of the classification instance
text_classification_instance.set_answer(answer="Dexter")
# Select the frames where the classification instance is present
text_classification_instance.set_for_frames(frames=0)
# Add it to the label row
label_row.add_classification_instance(text_classification_instance)
# Save labels
label_row.save()
print('added classification instance')
Number
Number
Example 1:Adds a Number input to a specific data unit. Ensure you replace
<data-unit-name>
with the name of the data unit you want to add the classification to.Example 2:Adds a Number attribute to an arbitrary bounding box on a specific data unit. Ensure you replace <data-unit-name>
with the name of the data unit you want to add the classification to, and <project_id>
with the unique ID of the Project.Copy
from encord import EncordUserClient
from encord.objects import OntologyStructure, Classification
user_client = EncordUserClient.create_with_ssh_private_key(
ssh_private_key_path="<private_key_path>"
)
project = user_client.get_project("<project_id>")
label_row = project.list_label_rows_v2(
data_title_eq="<data-unit-name>"
)[0]
label_row.initialise_labels()
# Get Ontology Structure
ontology_structure: OntologyStructure = label_row.ontology_structure
# Assume that the following Number input exists in the Ontology.
number_ontology_classification: Classification = (
ontology_structure.get_child_by_title(
title="Score", type_=Classification
)
)
number_classification_instance = number_ontology_classification.create_instance()
# Set the value of the classification instance
number_classification_instance.set_answer(answer=2)
# Select the frames where the classification instance is present
number_classification_instance.set_for_frames(frames=0)
# Add it to the label row
label_row.add_classification_instance(number_classification_instance)
# Save labels
label_row.save()
print('added classification instance')
Radio Button
Radio Button
Example 1:Imports a Radio button options (
Blueberry or Cherry?
) to a single image (blueberry_003.jpg
).Example 2:Imports a Radio button options (Blueberry or Cherry?
) across a range of sequential frames (193 to 197) to a video (Blueberries_video.mp4
).Copy
#Import dependencies
from __future__ import annotations
from pathlib import Path
from encord import EncordUserClient, Project
from encord.objects import (
Classification,
)
from collections import defaultdict
from copy import deepcopy
from dataclasses import dataclass, field
from datetime import datetime
from typing import (
TYPE_CHECKING,
Any,
Dict,
Iterable,
List,
Optional,
Sequence,
Set,
Tuple,
Union,
)
from dateutil.parser import parse
from encord.constants.enums import DataType
from encord.exceptions import LabelRowError
from encord.objects import ChecklistAttribute, RadioAttribute, TextAttribute
from encord.objects.answers import (
Answer,
_get_static_answer_map,
get_default_answer_from_attribute,
)
from encord.objects.frames import (
Frames,
Ranges,
)
from encord.objects.internal_helpers import (
_infer_attribute_from_answer,
_search_child_attributes,
)
from encord.objects.ontology_object import Object
from encord.objects.options import Option
from encord.objects.utils import check_email, short_uuid_str
if TYPE_CHECKING:
from encord.objects.ontology_labels_impl import LabelRowV2
SSH_PATH = "<file-path-to-ssh-private-key>"
PROJECT_ID = "<project-unique-id>"
# Create user client using access key
user_client: EncordUserClient = EncordUserClient.create_with_ssh_private_key(
Path(SSH_PATH).read_text()
)
# Get project for which predictions are to be added.
project: Project = user_client.get_project(PROJECT_ID)
# Creating classification- START
# Specify the data unit to apply classification
label_row = project.list_label_rows_v2(
data_title_eq="<data-unit-name>"
)[0]
label_row.initialise_labels()
# Assume that the following radio classification exists in the ontology.
radio_ontology_classification: Classification = project.ontology_structure.get_child_by_title(
title="<classification-name>",
type_=Classification,
)
blueberry_option = radio_ontology_classification.get_child_by_title(
title="<radio-button-option-title>", type_=Option
)
radio_classification_instance = (
radio_ ontology_classification.create_instance()
)
radio_classification_instance.set_answer(
answer=<radio-button-option>
)
radio_classification_instance.set_for_frames(
# Add the classification to the image
frames=0,
# There are multiple additional fields that can be set optionally:
manual_annotation=True,
confidence=1.0,
)
label_row.add_classification_instance(radio_classification_instance)
label_row.save()
Checklist
Checklist
Example 1:Imports a Checklist options (
Many types of fruit?
) to a single image (apple_003.jpg
). The selected items from the list are apple
and kiwi
.Example 2:Imports a Checklist options (Many types of fruit?
) across a range of sequential frames: 193 to 197) to a video (Blueberries_video.mp4
). The selected items from the list are apple
and kiwi
.Copy
#Import dependencies
from __future__ import annotations
from pathlib import Path
from encord import EncordUserClient, Project
from encord.objects import (
Classification,
)
from collections import defaultdict
from copy import deepcopy
from dataclasses import dataclass, field
from datetime import datetime
from typing import (
TYPE_CHECKING,
Any,
Dict,
Iterable,
List,
Optional,
Sequence,
Set,
Tuple,
Union,
)
from dateutil.parser import parse
from encord.constants.enums import DataType
from encord.exceptions import LabelRowError
from encord.objects import ChecklistAttribute, RadioAttribute, TextAttribute
from encord.objects.answers import (
Answer,
_get_static_answer_map,
get_default_answer_from_attribute,
)
from encord.objects.frames import (
Frames,
Ranges,
)
from encord.objects.internal_helpers import (
_infer_attribute_from_answer,
_search_child_attributes,
)
from encord.objects.ontology_object import Object
from encord.objects.options import Option
from encord.objects.utils import check_email, short_uuid_str
if TYPE_CHECKING:
from encord.objects.ontology_labels_impl import LabelRowV2
SSH_PATH = "/Users/chris-encord/sdk-ssh-private-key.txt"
PROJECT_ID = "7d4ead9c-4087-4832-a301-eb2545e7d43b"
# Create user client using access key
user_client: EncordUserClient = EncordUserClient.create_with_ssh_private_key(
Path(SSH_PATH).read_text()
)
# Get project for which predictions are to be added.
project: Project = user_client.get_project(PROJECT_ID)
# Creating one polyline- START
label_row = project.list_label_rows_v2(
data_title_eq="Blueberries_video.mp4"
)[0]
label_row.initialise_labels()
# Assume that the following radio classification exists in the ontology.
checklist_ontology_classification: Classification = project.ontology_structure.get_child_by_title(
title="Many types of fruit?",
type_=Classification,
)
apple_option = checklist_ontology_classification.get_child_by_title(
title="Apple", type_=Option
)
kiwi_option = checklist_ontology_classification.get_child_by_title(
title="Kiwi", type_=Option
)
checklist_classification_instance = (
checklist_ontology_classification.create_instance()
)
checklist_classification_instance.set_answer(
[apple_option, kiwi_option]
)
checklist_classification_instance.set_for_frames(
# Add the classification to the image
frames=177,
# There are multiple additional fields that can be set optionally:
manual_annotation=True,
confidence=1.0,
)
label_row.add_classification_instance(checklist_classification_instance)
label_row.save()
Attributes
The following scripts assume that an object label calledWhale
has already been created. Each script retrieves the object instance and searches for the corresponding attribute within the Project’s Ontology. For radio buttons and checklists, the scripts also identify the relevant attribute options.
- Replace
<private_key_path>
with the key to your private key for authentication. - Replace
<project_hash>
with the hash of your Project. - Replace
Whale
with the name of your object. - Replace the attributes and attribute answers to suit your needs.
Copy
# Import dependencies
from typing import List
from encord import EncordUserClient
from encord.objects import LabelRowV2, OntologyStructure, Object, OntologyStructure
# Instantiate Encord client by replacing <private_key_path> with the path to your private key
user_client = EncordUserClient.create_with_ssh_private_key(
ssh_private_key_path="<private_key_path>"
)
# Specify the Project. Replace <project_hash> with the hash of your Project
project = user_client.get_project("<project_hash>")
# For simplicity, get only the first label row
first_label_row: List[LabelRowV2] = project.list_label_rows_v2()[0]
# Download the existing labels
first_label_row.initialise_labels()
# Get the Ontology structure
ontology_structure: OntologyStructure = first_label_row.ontology_structure
#Assume that the following text attribute exists in the Ontology.
object_label = ontology_structure.get_child_by_title(
title="Whale",
type_=Object
)
# Create object instance. We assume only 1 label
object_instance = first_label_row.get_object_instances()[0]
# Find the attribute name
attribute = object_label.get_child_by_title("Description")
# Set the answer for the attribute
object_instance.set_answer(attribute=attribute, answer="This is a picture of a whale")
# Save labels
first_label_row.save()
Nested Attributes
Radio button attributes can be nested. The following script assumes that an object label calledWhale
has already been created.
Nested Radio Attributes
Copy
# Import dependencies
from typing import List
from encord import EncordUserClient
from encord.objects import LabelRowV2, Option, Object, OntologyStructure
# Instantiate Encord client by replacing <private_key_path> with the path to your private key
user_client = EncordUserClient.create_with_ssh_private_key(
ssh_private_key_path="<private_key_path>"
)
# Specify the Project. Replace <project_hash> with the hash of your Project
project = user_client.get_project("<project_hash>")
# For simplicity, get only the first label row
first_label_row: List[LabelRowV2] = project.list_label_rows_v2()[0]
# Download the existing labels
first_label_row.initialise_labels()
# Get the ontology structure
ontology_structure: OntologyStructure = first_label_row.ontology_structure
# Find Object label
object_label = ontology_structure.get_child_by_title(
title="Whale",
type_=Object
)
# Create object instance. We assume only 1 label
object_instance = first_label_row.get_object_instances()[0]
# Find the attribute
object_attribute = object_label.get_child_by_title("Colour")
# Find the attribute option you want to set
attribute_option = object_attribute.get_child_by_title(
title="Blue",
type_=Option
)
# Set the attribute option
object_instance.set_answer(attribute_option)
# Assume that the following Radio button options exists in the Ontology.
nested_radio_ontology_attribute: Classification = (
ontology_structure.get_child_by_title(
title="Any Other Colors?", type_=RadioAttribute
)
)
# Assume the following radio button nested attribute exists in the Ontology
nested_radio_attribute_option = object_label.get_child_by_title(
title="Pink",
type_=Option
)
# Save labels
first_label_row.save()
Relation Attributes
Relation attributes work the exact same way as text attributes, except that when an attribute is marked as Relation the string#relation
is appended to the attribute name.
Learn more about relation attributes in Encord here.
Relation Attributes
Copy
# Import dependencies
from typing import List
from encord import EncordUserClient
from encord.objects import LabelRowV2, Object, OntologyStructure
# Instantiate Encord client by replacing <private_key_path> with the path to your private key
user_client = EncordUserClient.create_with_ssh_private_key(
ssh_private_key_path="<private_key_path>"
)
# Specify the Project. Replace <project_hash> with the hash of your Project
project = user_client.get_project("<project_hash>")
# For simplicity, get only the first label row
first_label_row: List[LabelRowV2] = project.list_label_rows_v2()[0]
# Download the existing labels
first_label_row.initialise_labels()
# Get the Ontology structure
ontology_structure: OntologyStructure = first_label_row.ontology_structure
# Assume that the following text attribute exists in the Ontology.
object_label = ontology_structure.get_child_by_title(
title="Whale",
type_=Object
)
# Create object instance. We assume only 1 label
object_instance = first_label_row.get_object_instances()[0]
# Find the attribute name
attribute = object_label.get_child_by_title("Description #relation")
# Set the answer for the attribute
object_instance.set_answer(attribute=attribute, answer="This is a picture of a whale")
# Save labels
first_label_row.save()
Dynamic Attributes
Dynamic attributes are attributes for object instances where the answer can change in each frame. You can read more about them here. The following example adds bounding boxes for the labelPerson
to three frames. It then sets the dynamic attribute Position
to Walking
and Standing
. Wherever you can set frames, you can either set a single integer, a Range, or a list of Ranges.
Copy
# Import dependencies
from typing import List
from encord import EncordUserClient
from encord.objects import LabelRowV2, Object, ObjectInstance, OntologyStructure
from encord.objects.coordinates import PolygonCoordinates, PointCoordinate
# Instantiate Encord client by replacing <private_key_path> with the path to your private key
user_client = EncordUserClient.create_with_ssh_private_key(
ssh_private_key_path="<private_key_path>"
)
# Specify the project. Replace <project_hash> with the hash of your Project
project = user_client.get_project("<project_hash>")
# For simplicity, get only the first label row
first_label_row: LabelRowV2 = project.list_label_rows_v2()[0]
# Download the existing labels
first_label_row.initialise_labels()
# Find the object in the Ontology
person_ontology_object: Object = ontology_structure.get_child_by_title(
"Person", type_=Object
)
# Find the dynamic attribute in the Ontology
position_attribute = person_ontology_object.get_child_by_title(
title="Position", # The options here are "Standing" or "Walking"
type_=RadioAttribute,
)
# Coordinates for bounding boxes on frames 3, 4, and 5
coordinates_per_frame = {
3: BoundingBoxCoordinates(
height=0.5,
width=0.5,
top_left_x=0.2,
top_left_y=0.2,
),
4: BoundingBoxCoordinates(
height=0.5,
width=0.5,
top_left_x=0.3,
top_left_y=0.3,
),
5: BoundingBoxCoordinates(
height=0.5,
width=0.5,
top_left_x=0.4,
top_left_y=0.4,
),
}
# Add the bounding box labels to the object instance for each frame
for frame_number, coordinates in coordinates_per_frame.items():
box_object_instance.set_for_frames(
coordinates=coordinates, frames=frame_number
)
# Link the object instance to the label row
first_label_row.add_object_instance(box_object_instance)
# Assume the person is standing in frame 1
person_object_instance.set_answer(
answer=position_attribute.get_child_by_title("Standing", type_=Option),
frames=0,
)
# Assume the person is walking in frames 2 and 3
person_object_instance.set_answer(
answer=position_attribute.get_child_by_title("Walking", type_=Option),
frames=Range(start=1, end=3),
)
# Save labels
first_label_row.save()
Import Labels in Bulk
When importing a large number of labels, here are some tips to improve your label import performance:-
A data unit is one image, one image group, one image sequence, one video, or one DICOM series. One data unit is equivalent to one label row. You only need to call the initialise_labels function and save the label row ONCE per data unit. It does not matter how many labels are added to the data unit between the
initialise_labels
function and saving the label row. -
Use the bundle function to significantly improve the import performance when you do any of the following:
- Import labels on a large number of individual images (NOT image groups, image sequences, videos, or DICOM sets).
- Import labels on a large number of data units at once.
In the following code, ensure you replace:
<private_key_path>
with the full path to your private key.<project-id>
with the unique ID of your Project.#Perform label row operation before in this loop
with the label row operations you want to perform.- Optionally, change the value of
BUNDLE_SIZE
to suit your needs. We strongly recommend NOT bundling more than 1000 operations at once, because bundling more than 1000 operations can reduce performance instead of improving performance.
Copy
# Import dependencies
from pathlib import Path
from encord import EncordUserClient, Project
from encord.objects import (
Object,
ObjectInstance,
OntologyStructure,
)
from encord.objects.coordinates import BoundingBoxCoordinates
SSH_PATH = "<private-key-path>"
PROJECT_HASH = "<project-unique-id>"
# Authenticate
user_client: EncordUserClient = EncordUserClient.create_with_ssh_private_key(ssh_private_key_path=SSH_PATH)
# Gets Project to export labels
project: Project = user_client.get_project(PROJECT_HASH)
label_rows = project.list_label_rows_v2()
BUNDLE_SIZE = 100
# Initialize label rows using bundles
with project.create_bundle(bundle_size=BUNDLE_SIZE) as bundle
for label_row in label_rows:
label_row.initialise_labels(bundle=bundle)
for label_row in label_rows:
# Write any label row operation here. For example import, or export label rows.
# Saving changes to label rows using bundles
with project.create_bundle(bundle_size=BUNDLE_SIZE) as bundle:
for label_row in label_rows:
label_row.save(bundle=bundle)