Entity | Name |
---|---|
Project | Blueberries and Cherries PROJECT_HASH: 7d4ead9c-4087-4832-a301-eb2545e7d43b |
Ontology | Blueberries and Cherries Ontology |
Bounding box | Cherry |
Rotatable bounding box | Other type of fruit |
Polygon | Persimmon |
Polyline | Branch |
Keypoint | Pedicel |
Bitmask | Blueberry |
Object Primitive (Triangle) | Strawberry |
Radio classification | Blueberry or cherry? |
Checklist classification | Many types of fruit? |
Bounding Box
# Import dependencies
from encord import EncordUserClient, Project
from encord.objects import ChecklistAttribute, Object, ObjectInstance, Option, RadioAttribute, TextAttribute
from encord.objects.coordinates import BoundingBoxCoordinates
SSH_PATH = "/Users/chris-encord/ssh-private-key.txt"
# SSH_PATH = get_ssh_key() # replace it with ssh key
PROJECT_ID = "00000000-0000-0000-0000-000000000000"
BUNDLE_SIZE = 100
# Create user client using ssh 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)
# Create radio button attribute for cherry type
ontology_structure = project.ontology_structure
# Find a bounding box annotation object in the project ontology
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."
cherry_type_radio_attribute = ontology_structure.get_child_by_title(type_=RadioAttribute, title="Type?")
assert cherry_type_radio_attribute is not None, "Radio attribute 'Type?' not found in ontology."
# Create options for the radio buttons
bing_option = cherry_type_radio_attribute.get_child_by_title(type_=Option, title="Bing")
king_option = cherry_type_radio_attribute.get_child_by_title(type_=Option, title="King")
rainier_option = cherry_type_radio_attribute.get_child_by_title(type_=Option, title="Rainier")
other_cherry_option = cherry_type_radio_attribute.get_child_by_title(type_=Option, title="Other cherry type")
assert all([bing_option, king_option, rainier_option, other_cherry_option]), (
"One or more cherry type options are missing."
)
# Bing Qualities
bing_checklist_attribute = ontology_structure.get_child_by_title(type_=ChecklistAttribute, title="Bing Qualities?")
assert bing_checklist_attribute is not None, "Checklist attribute 'Bing Qualities?' not found."
bing_plump_option = bing_checklist_attribute.get_child_by_title(type_=Option, title="Plump")
bing_juicy_option = bing_checklist_attribute.get_child_by_title(type_=Option, title="Juicy")
bing_large_option = bing_checklist_attribute.get_child_by_title(type_=Option, title="Large")
assert all([bing_plump_option, bing_juicy_option, bing_large_option]), "One or more Bing quality options are missing."
# King Qualities
king_checklist_attribute = ontology_structure.get_child_by_title(type_=ChecklistAttribute, title="King Qualities?")
assert king_checklist_attribute is not None, "Checklist attribute 'King Qualities?' not found."
king_plump_option = king_checklist_attribute.get_child_by_title(type_=Option, title="Plump")
king_juicy_option = king_checklist_attribute.get_child_by_title(type_=Option, title="Juicy")
king_large_option = king_checklist_attribute.get_child_by_title(type_=Option, title="Large")
assert all([king_plump_option, king_juicy_option, king_large_option]), "One or more King quality options are missing."
# Rainier Qualities
rainier_checklist_attribute = ontology_structure.get_child_by_title(
type_=ChecklistAttribute, title="Rainier Qualities?"
)
assert rainier_checklist_attribute is not None, "Checklist attribute 'Rainier Qualities?' not found."
rainier_plump_option = rainier_checklist_attribute.get_child_by_title(type_=Option, title="Plump")
rainier_juicy_option = rainier_checklist_attribute.get_child_by_title(type_=Option, title="Juicy")
rainier_large_option = rainier_checklist_attribute.get_child_by_title(type_=Option, title="Large")
assert all([rainier_plump_option, rainier_juicy_option, rainier_large_option]), (
"One or more Rainier quality options are missing."
)
# Other Cherry Types
other_cherry_option_text_attribute = ontology_structure.get_child_by_title(
type_=TextAttribute, title="Specify cherry type"
)
assert other_cherry_option_text_attribute is not None, "Text attribute 'Specify cherry type' not found in ontology."
# Dictionary of labels per data unit and per frame with cherry type specified, including quality options
video_frame_labels = {
"cherries-001.jpg": {
0: {
"label_ref": "cherry_001",
"coordinates": BoundingBoxCoordinates(height=0.4, width=0.4, top_left_x=0.0, top_left_y=0.0),
"cherry_type": "Bing",
"bing_quality_options": "Plump, Juicy",
}
},
"cherries-010.jpg": {
0: [
{
"label_ref": "cherry_002",
"coordinates": BoundingBoxCoordinates(height=0.4, width=0.4, top_left_x=0.0, top_left_y=0.0),
"cherry_type": "King",
"king_quality_options": "Plump, Juicy, Large",
},
{
"label_ref": "cherry_003",
"coordinates": BoundingBoxCoordinates(height=0.2, width=0.1, top_left_x=0.5, top_left_y=0.0),
"cherry_type": "Rainier",
"rainier_quality_options": "Plump",
},
{
"label_ref": "cherry_004",
"coordinates": BoundingBoxCoordinates(height=0.2, width=0.1, top_left_x=0.7, top_left_y=0.0),
"cherry_type": "Other cherry type",
"Specify cherry type": "Morello",
},
],
},
"cherries-ig": {
0: {
"label_ref": "cherry_005",
"coordinates": BoundingBoxCoordinates(height=0.4, width=0.4, top_left_x=0.0, top_left_y=0.0),
"cherry_type": "Bing",
"bing_quality_options": "Plump, Juicy",
},
2: [
{
"label_ref": "cherry_006",
"coordinates": BoundingBoxCoordinates(height=0.1, width=0.2, top_left_x=0.5, top_left_y=0.0),
"cherry_type": "King",
"king_quality_options": "Large",
},
{
"label_ref": "cherry_007",
"coordinates": BoundingBoxCoordinates(height=0.1, width=0.2, top_left_x=0.0, top_left_y=0.5),
"cherry_type": "Rainier",
"rainier_quality_options": "Plump",
},
{
"label_ref": "cherry_008",
"coordinates": BoundingBoxCoordinates(height=0.2, width=0.1, top_left_x=0.8, top_left_y=0.0),
"cherry_type": "Other cherry type",
"Specify cherry type": "Queen Anne",
},
],
},
"cherries-is": {
0: {
"label_ref": "cherry_009",
"coordinates": BoundingBoxCoordinates(height=0.4, width=0.4, top_left_x=0.0, top_left_y=0.0),
"cherry_type": "Bing",
"bing_quality_options": "Plump",
},
3: [
{
"label_ref": "cherry_010",
"coordinates": BoundingBoxCoordinates(height=0.4, width=0.4, top_left_x=0.5, top_left_y=0.0),
"cherry_type": "King",
"king_quality_options": "Plump, Juicy, Large",
},
{
"label_ref": "cherry_011",
"coordinates": BoundingBoxCoordinates(height=0.3, width=0.3, top_left_x=0.0, top_left_y=0.5),
"cherry_type": "Rainier",
"rainier_quality_options": "Plump",
},
{
"label_ref": "cherry_012",
"coordinates": BoundingBoxCoordinates(height=0.2, width=0.1, top_left_x=0.9, top_left_y=0.0),
"cherry_type": "Other cherry type",
"Specify cherry type": "Lambert",
},
],
},
"cherries-vid-001.mp4": {
103: [
{
"label_ref": "cherry_013",
"coordinates": BoundingBoxCoordinates(height=0.5, width=0.5, top_left_x=0.0, top_left_y=0.0),
"cherry_type": "Rainier",
"rainier_quality_options": "Plump",
},
{
"label_ref": "cherry_014",
"coordinates": BoundingBoxCoordinates(height=0.2, width=0.2, top_left_x=0.6, top_left_y=0.0),
"cherry_type": "Bing",
"bing_quality_options": "Plump, Juicy, Large",
},
{
"label_ref": "cherry_015",
"coordinates": BoundingBoxCoordinates(height=0.2, width=0.1, top_left_x=0.8, top_left_y=0.6),
"cherry_type": "Other cherry type",
"Specify cherry type": "Sweetheart",
},
],
104: [
{
"label_ref": "cherry_016",
"coordinates": BoundingBoxCoordinates(height=0.5, width=0.5, top_left_x=0.0, top_left_y=0.0),
"cherry_type": "Rainier",
"rainier_quality_options": "Plump",
},
{
"label_ref": "cherry_014",
"coordinates": BoundingBoxCoordinates(height=0.2, width=0.2, top_left_x=0.6, top_left_y=0.0),
"cherry_type": "Bing",
"bing_quality_options": "Plump, Juicy, Large",
},
{
"label_ref": "cherry_017",
"coordinates": BoundingBoxCoordinates(height=0.2, width=0.1, top_left_x=0.8, top_left_y=0.6),
"cherry_type": "Other cherry type",
"Specify cherry type": "Sweetheart",
},
],
105: [
{
"label_ref": "cherry_016",
"coordinates": BoundingBoxCoordinates(height=0.5, width=0.5, top_left_x=0.0, top_left_y=0.0),
"cherry_type": "Rainier",
"rainier_quality_options": "Plump",
},
{
"label_ref": "cherry_014",
"coordinates": BoundingBoxCoordinates(height=0.2, width=0.2, top_left_x=0.6, top_left_y=0.0),
"cherry_type": "Bing",
"bing_quality_options": "Plump, Juicy, Large",
},
{
"label_ref": "cherry_017",
"coordinates": BoundingBoxCoordinates(height=0.2, width=0.1, top_left_x=0.8, top_left_y=0.6),
"cherry_type": "Other cherry type",
"Specify cherry type": "Sweetheart",
},
],
},
}
# Cache initialized label rows
label_row_map = {}
# Step 1: Initialize all label rows using a bundle
with project.create_bundle(bundle_size=BUNDLE_SIZE) as bundle:
for data_unit in video_frame_labels.keys():
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)}"
if not label_rows:
print(f"Skipping: No label row found for {data_unit}")
continue
label_row = label_rows[0]
label_row.initialise_labels(bundle=bundle)
assert label_row.ontology_structure is not None, f"Ontology not initialized for label row: {data_unit}"
label_row_map[data_unit] = label_row # Cache initialized label row for later use
# Step 2: Process all frames/annotations and prepare label rows to save
label_rows_to_save = []
for data_unit, frame_coordinates in video_frame_labels.items():
label_row = label_row_map.get(data_unit)
if not label_row:
print(f"Skipping: No initialized label row found for {data_unit}")
continue
object_instances_by_label_ref = {}
# Loop through the frames for the current 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):
items = [items]
for item in items:
label_ref = item["label_ref"]
coord = item["coordinates"]
cherry_type = item["cherry_type"]
assert cherry_type in {
"Bing",
"King",
"Rainier",
"Other cherry type",
}, f"Unexpected cherry type '{cherry_type}' in data unit '{data_unit}'"
# Check if label_ref already exists for reusability
if label_ref not in object_instances_by_label_ref:
box_object_instance: ObjectInstance = box_ontology_object.create_instance()
assert box_object_instance is not None, "Failed to create ObjectInstance"
object_instances_by_label_ref[label_ref] = box_object_instance
checklist_attribute = None
# Set cherry type attribute
if cherry_type == "Bing":
assert bing_option is not None, "Missing 'bing_option'"
box_object_instance.set_answer(attribute=cherry_type_radio_attribute, answer=bing_option)
checklist_attribute = bing_checklist_attribute
elif cherry_type == "King":
assert king_option is not None, "Missing 'king_option'"
box_object_instance.set_answer(attribute=cherry_type_radio_attribute, answer=king_option)
checklist_attribute = king_checklist_attribute
elif cherry_type == "Rainier":
assert rainier_option is not None, "Missing 'rainier_option'"
box_object_instance.set_answer(attribute=cherry_type_radio_attribute, answer=rainier_option)
checklist_attribute = rainier_checklist_attribute
elif cherry_type == "Other cherry type":
assert other_cherry_option is not None, "Missing 'other_cherry_option'"
box_object_instance.set_answer(attribute=cherry_type_radio_attribute, answer=other_cherry_option)
text_answer = item.get("Specify cherry type", "")
assert isinstance(text_answer, str), "'Specify cherry type' must be a string"
box_object_instance.set_answer(attribute=other_cherry_option_text_attribute, answer=text_answer)
# Set checklist attributes
checklist_answers = []
quality_key = f"{cherry_type.lower()}_quality_options"
quality_options = item.get(quality_key, "").split(", ")
for quality in quality_options:
if quality == "Plump":
checklist_answers.append(
bing_plump_option
if cherry_type == "Bing"
else king_plump_option
if cherry_type == "King"
else rainier_plump_option
)
elif quality == "Juicy":
checklist_answers.append(
bing_juicy_option
if cherry_type == "Bing"
else king_juicy_option
if cherry_type == "King"
else rainier_juicy_option
)
elif quality == "Large":
checklist_answers.append(
bing_large_option
if cherry_type == "Bing"
else king_large_option
if cherry_type == "King"
else rainier_large_option
)
if checklist_attribute and checklist_answers:
box_object_instance.set_answer(
attribute=checklist_attribute, answer=checklist_answers, overwrite=True
)
else:
# Reuse existing instance across frames
box_object_instance = object_instances_by_label_ref[label_ref]
# Assign the object to the frame and track it
box_object_instance.set_for_frames(coordinates=coord, frames=frame_number)
# Add object instances to label_row **only if they have frames assigned**
for box_object_instance in object_instances_by_label_ref.values():
assert isinstance(box_object_instance, ObjectInstance), "Expected ObjectInstance type"
if box_object_instance.get_annotation_frames(): # Ensures it has at least one frame
label_row.add_object_instance(box_object_instance)
label_rows_to_save.append(label_row)
# Step 3: Save all label rows using a bundle
with project.create_bundle(bundle_size=BUNDLE_SIZE) as bundle:
for label_row in label_rows_to_save:
assert label_row is not None, "Trying to save a None label row"
label_row.save(bundle=bundle)
print(f"Saved label row for {label_row.data_title}")
print("Labels with cherry type radio buttons, checklist attributes, and text labels added for all data units.")
Rotatable Bounding Box
# Import dependencies
from encord import EncordUserClient, Project
from encord.objects import ChecklistAttribute, Object, ObjectInstance, Option, RadioAttribute, TextAttribute
from encord.objects.coordinates import RotatableBoundingBoxCoordinates
# User input
SSH_PATH = "/Users/chris-encord/ssh-private-key.txt"
PROJECT_ID = "00000000-0000-0000-0000-000000000000"
BUNDLE_SIZE = 100
# Create user client using ssh 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"
# Create radio button attribute for persimmon type
ontology_structure = project.ontology_structure
assert ontology_structure is not None, "Ontology structure is missing from the project"
# Find a bounding box annotation object in the project ontology
rbbox_ontology_object: Object = ontology_structure.get_child_by_title(title="Persimmons", type_=Object)
assert rbbox_ontology_object is not None, "Object 'Persimmons' not found in ontology"
# Get radio attribute for persimmon type
persimmon_type_radio_attribute = ontology_structure.get_child_by_title(type_=RadioAttribute, title="Type?")
assert persimmon_type_radio_attribute is not None, "Radio attribute 'Type?' not found"
# Create radio options
hachiya_option = persimmon_type_radio_attribute.get_child_by_title(type_=Option, title="Hachiya")
assert hachiya_option is not None, "Option 'Hachiya' not found under 'Type?'"
fuyu_option = persimmon_type_radio_attribute.get_child_by_title(type_=Option, title="Fuyu")
assert fuyu_option is not None, "Option 'Fuyu' not found under 'Type?'"
rjb_option = persimmon_type_radio_attribute.get_child_by_title(type_=Option, title="Rojo Brilliante")
assert rjb_option is not None, "Option 'Rojo Brilliante' not found under 'Type?'"
other_persimmon_option = persimmon_type_radio_attribute.get_child_by_title(type_=Option, title="Other persimmon type")
assert other_persimmon_option is not None, "Option 'Other persimmon type' not found under 'Type?'"
# Hachiya Qualities
hachiya_checklist_attribute = ontology_structure.get_child_by_title(
type_=ChecklistAttribute, title="Hachiya Qualities?"
)
assert hachiya_checklist_attribute is not None, "Checklist attribute 'Hachiya Qualities?' not found"
hachiya_plump_option = hachiya_checklist_attribute.get_child_by_title(type_=Option, title="Plump")
assert hachiya_plump_option is not None, "Option 'Plump' not found under 'Hachiya Qualities?'"
hachiya_juicy_option = hachiya_checklist_attribute.get_child_by_title(type_=Option, title="Juicy")
assert hachiya_juicy_option is not None, "Option 'Juicy' not found under 'Hachiya Qualities?'"
hachiya_large_option = hachiya_checklist_attribute.get_child_by_title(type_=Option, title="Large")
assert hachiya_large_option is not None, "Option 'Large' not found under 'Hachiya Qualities?'"
# Fuyu Qualities
fuyu_checklist_attribute = ontology_structure.get_child_by_title(type_=ChecklistAttribute, title="Fuyu Qualities?")
assert fuyu_checklist_attribute is not None, "Checklist attribute 'Fuyu Qualities?' not found"
fuyu_plump_option = fuyu_checklist_attribute.get_child_by_title(type_=Option, title="Plump")
assert fuyu_plump_option is not None, "Option 'Plump' not found under 'Fuyu Qualities?'"
fuyu_juicy_option = fuyu_checklist_attribute.get_child_by_title(type_=Option, title="Juicy")
assert fuyu_juicy_option is not None, "Option 'Juicy' not found under 'Fuyu Qualities?'"
fuyu_large_option = fuyu_checklist_attribute.get_child_by_title(type_=Option, title="Large")
assert fuyu_large_option is not None, "Option 'Large' not found under 'Fuyu Qualities?'"
# Rojo Brilliante Qualities
rjb_checklist_attribute = ontology_structure.get_child_by_title(
type_=ChecklistAttribute, title="Rojo Brilliante Qualities?"
)
assert rjb_checklist_attribute is not None, "Checklist attribute 'Rojo Brilliante Qualities?' not found"
rjb_plump_option = rjb_checklist_attribute.get_child_by_title(type_=Option, title="Plump")
assert rjb_plump_option is not None, "Option 'Plump' not found under 'Rojo Brilliante Qualities?'"
rjb_juicy_option = rjb_checklist_attribute.get_child_by_title(type_=Option, title="Juicy")
assert rjb_juicy_option is not None, "Option 'Juicy' not found under 'Rojo Brilliante Qualities?'"
rjb_large_option = rjb_checklist_attribute.get_child_by_title(type_=Option, title="Large")
assert rjb_large_option is not None, "Option 'Large' not found under 'Rojo Brilliante Qualities?'"
# Other persimmon type text input
other_persimmon_option_text_attribute = ontology_structure.get_child_by_title(
type_=TextAttribute, title="Specify persimmon type"
)
assert other_persimmon_option_text_attribute is not None, "Text attribute 'Specify persimmon type' not found"
# Dictionary of labels per data unit and per frame with persimmon type specified, including quality options
video_frame_labels = {
"cherries-001.jpg": {
0: {
"label_ref": "persimmon_001",
"coordinates": RotatableBoundingBoxCoordinates(
height=0.4, width=0.4, top_left_x=0.05, top_left_y=0.55, theta=23
),
"persimmon_type": "Rojo Brilliante",
"rjb_quality_options": "Plump, Juicy",
},
},
"cherries-010.jpg": {
0: [
{
"label_ref": "persimmon_002",
"coordinates": RotatableBoundingBoxCoordinates(
height=0.4, width=0.4, top_left_x=0.05, top_left_y=0.55, theta=23
),
"persimmon_type": "Fuyu",
"fuyu_quality_options": "Plump, Juicy, Large",
},
{
"label_ref": "persimmon_003",
"coordinates": RotatableBoundingBoxCoordinates(
height=0.2, width=0.1, top_left_x=0.2, top_left_y=0.2, theta=25
),
"persimmon_type": "Rojo Brilliante",
"rjb_quality_options": "Plump",
},
{
"label_ref": "persimmon_004",
"coordinates": RotatableBoundingBoxCoordinates(
height=0.2, width=0.1, top_left_x=0.3, top_left_y=0.3, theta=27
),
"persimmon_type": "Other persimmon type",
"Specify persimmon type": "Triumph",
},
],
},
"cherries-ig": {
0: {
"label_ref": "persimmon_005",
"coordinates": RotatableBoundingBoxCoordinates(
height=0.4, width=0.4, top_left_x=0.05, top_left_y=0.55, theta=23
),
"persimmon_type": "Hachiya",
"hachiya_quality_options": "Plump, Juicy",
},
2: [
{
"label_ref": "persimmon_006",
"coordinates": RotatableBoundingBoxCoordinates(
height=0.1, width=0.2, top_left_x=0.2, top_left_y=0.2, theta=23
),
"persimmon_type": "Fuyu",
"fuyu_quality_options": "Large",
},
{
"label_ref": "persimmon_007",
"coordinates": RotatableBoundingBoxCoordinates(
height=0.1, width=0.2, top_left_x=0.4, top_left_y=0.2, theta=127
),
"persimmon_type": "Rojo Brilliante",
"rjb_quality_options": "Plump",
},
{
"label_ref": "persimmon_008",
"coordinates": RotatableBoundingBoxCoordinates(
height=0.2, width=0.1, top_left_x=0.6, top_left_y=0.3, theta=137
),
"persimmon_type": "Other persimmon type",
"Specify persimmon type": "Hiro",
},
],
},
"cherries-is": {
0: {
"label_ref": "persimmon_009",
"coordinates": RotatableBoundingBoxCoordinates(
height=0.4, width=0.4, top_left_x=0.05, top_left_y=0.55, theta=23
),
"persimmon_type": "Hachiya",
"hachiya_quality_options": "Plump",
},
3: [
{
"label_ref": "persimmon_010",
"coordinates": RotatableBoundingBoxCoordinates(
height=0.4, width=0.4, top_left_x=0.05, top_left_y=0.05, theta=23
),
"persimmon_type": "Fuyu",
"fuyu_quality_options": "Plump, Juicy, Large",
},
{
"label_ref": "persimmon_011",
"coordinates": RotatableBoundingBoxCoordinates(
height=0.3, width=0.3, top_left_x=0.5, top_left_y=0.05, theta=23
),
"persimmon_type": "Rojo Brilliante",
"rjb_quality_options": "Plump, Juicy",
},
{
"label_ref": "persimmon_012",
"coordinates": RotatableBoundingBoxCoordinates(
height=0.2, width=0.1, top_left_x=0.7, top_left_y=0.05, theta=23
),
"persimmon_type": "Other persimmon type",
"Specify persimmon type": "Maru",
},
],
},
"cherries-vid-001.mp4": {
103: [
{
"label_ref": "persimmon_013",
"coordinates": RotatableBoundingBoxCoordinates(
height=0.5, width=0.5, top_left_x=0.05, top_left_y=0.55, theta=23
),
"persimmon_type": "Rojo Brilliante",
"rjb_quality_options": "Plump",
},
{
"label_ref": "persimmon_014",
"coordinates": RotatableBoundingBoxCoordinates(
height=0.2, width=0.2, top_left_x=0.3, top_left_y=0.2, theta=23
),
"persimmon_type": "Hachiya",
"hachiya_quality_options": "Plump, Juicy, Large",
},
{
"label_ref": "persimmon_015",
"coordinates": RotatableBoundingBoxCoordinates(
height=0.2, width=0.1, top_left_x=0.6, top_left_y=0.2, theta=23
),
"persimmon_type": "Other persimmon type",
"Specify persimmon type": "Triumph",
},
],
104: [
{
"label_ref": "persimmon_016",
"coordinates": RotatableBoundingBoxCoordinates(
height=0.5, width=0.5, top_left_x=0.05, top_left_y=0.55, theta=23
),
"persimmon_type": "Rojo Brilliante",
"rjb_quality_options": "Plump",
},
{
"label_ref": "persimmon_014",
"coordinates": RotatableBoundingBoxCoordinates(
height=0.2, width=0.2, top_left_x=0.3, top_left_y=0.2, theta=23
),
"persimmon_type": "Hachiya",
"hachiya_quality_options": "Plump, Juicy, Large",
},
{
"label_ref": "persimmon_017",
"coordinates": RotatableBoundingBoxCoordinates(
height=0.2, width=0.1, top_left_x=0.6, top_left_y=0.2, theta=23
),
"persimmon_type": "Other persimmon type",
"Specify persimmon type": "Hiro",
},
],
105: [
{
"label_ref": "persimmon_016",
"coordinates": RotatableBoundingBoxCoordinates(
height=0.5, width=0.5, top_left_x=0.05, top_left_y=0.55, theta=23
),
"persimmon_type": "Rojo Brilliante",
"rjb_quality_options": "Plump",
},
{
"label_ref": "persimmon_014",
"coordinates": RotatableBoundingBoxCoordinates(
height=0.2, width=0.2, top_left_x=0.3, top_left_y=0.2, theta=23
),
"persimmon_type": "Hachiya",
"hachiya_quality_options": "Plump, Juicy, Large",
},
{
"label_ref": "persimmon_017",
"coordinates": RotatableBoundingBoxCoordinates(
height=0.2, width=0.1, top_left_x=0.6, top_left_y=0.2, theta=23
),
"persimmon_type": "Other persimmon type",
"Specify persimmon type": "Maru",
},
],
},
}
# Cache label rows after initialization
label_row_map = {}
# Step 1: Initialize all label rows with a bundle
with project.create_bundle(bundle_size=BUNDLE_SIZE) as bundle:
for data_unit in video_frame_labels.keys():
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 row found for {data_unit}"
label_row = label_rows[0]
assert label_row is not None, f"Label row is None for {data_unit}"
label_row.initialise_labels(bundle=bundle)
assert label_row.ontology_structure is not None, f"Ontology not initialized for label row: {data_unit}"
label_row_map[data_unit] = label_row # Cache it for processing later
# Step 2: Process labels and collect label rows to save
label_rows_to_save = []
for data_unit, frame_coordinates in video_frame_labels.items():
label_row = label_row_map.get(data_unit)
assert label_row is not None, f"Missing initialized label row for {data_unit}"
object_instances_by_label_ref = {}
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):
items = [items]
for item in items:
label_ref = item["label_ref"]
coord = item["coordinates"]
persimmon_type = item["persimmon_type"]
assert persimmon_type in {
"Hachiya",
"Fuyu",
"Rojo Brilliante",
"Other persimmon type",
}, f"Unexpected persimmon type '{persimmon_type}' in {data_unit}"
if label_ref not in object_instances_by_label_ref:
rbbox_object_instance: ObjectInstance = rbbox_ontology_object.create_instance()
assert rbbox_object_instance is not None, f"Failed to create ObjectInstance for {label_ref}"
checklist_attribute = None
quality_options = []
# Set persimmon type and checklist attributes
if persimmon_type == "Hachiya":
assert hachiya_option is not None, "Missing 'hachiya_option'"
rbbox_object_instance.set_answer(attribute=persimmon_type_radio_attribute, answer=hachiya_option)
checklist_attribute = hachiya_checklist_attribute
quality_options = item.get("hachiya_quality_options", "").split(", ")
elif persimmon_type == "Fuyu":
assert fuyu_option is not None, "Missing 'fuyu_option'"
rbbox_object_instance.set_answer(attribute=persimmon_type_radio_attribute, answer=fuyu_option)
checklist_attribute = fuyu_checklist_attribute
quality_options = item.get("fuyu_quality_options", "").split(", ")
elif persimmon_type == "Rojo Brilliante":
assert rjb_option is not None, "Missing 'rjb_option'"
rbbox_object_instance.set_answer(attribute=persimmon_type_radio_attribute, answer=rjb_option)
checklist_attribute = rjb_checklist_attribute
quality_options = item.get("rjb_quality_options", "").split(", ")
elif persimmon_type == "Other persimmon type":
assert other_persimmon_option is not None, "Missing 'other_persimmon_option'"
rbbox_object_instance.set_answer(
attribute=persimmon_type_radio_attribute, answer=other_persimmon_option
)
text_answer = item.get("Specify persimmon type", "")
assert isinstance(text_answer, str), "'Specify persimmon type' must be a string"
rbbox_object_instance.set_answer(
attribute=other_persimmon_option_text_attribute, answer=text_answer
)
quality_options = []
# Set checklist answers based on quality options
checklist_answers = []
for quality in quality_options:
option = None
if quality == "Plump":
option = (
hachiya_plump_option
if persimmon_type == "Hachiya"
else fuyu_plump_option
if persimmon_type == "Fuyu"
else rjb_plump_option
if persimmon_type == "Rojo Brilliante"
else None
)
elif quality == "Juicy":
option = (
hachiya_juicy_option
if persimmon_type == "Hachiya"
else fuyu_juicy_option
if persimmon_type == "Fuyu"
else rjb_juicy_option
if persimmon_type == "Rojo Brilliante"
else None
)
elif quality == "Large":
option = (
hachiya_large_option
if persimmon_type == "Hachiya"
else fuyu_large_option
if persimmon_type == "Fuyu"
else rjb_large_option
if persimmon_type == "Rojo Brilliante"
else None
)
if option:
checklist_answers.append(option)
else:
assert persimmon_type == "Other persimmon type", (
f"Invalid quality '{quality}' for persimmon type '{persimmon_type}'"
)
if checklist_attribute and checklist_answers:
rbbox_object_instance.set_answer(
attribute=checklist_attribute, answer=checklist_answers, overwrite=True
)
object_instances_by_label_ref[label_ref] = rbbox_object_instance
else:
rbbox_object_instance = object_instances_by_label_ref[label_ref]
# Assign coordinates for this frame
rbbox_object_instance.set_for_frames(coordinates=coord, frames=frame_number)
# Add object instances to label_row **only if they have frames assigned**
for rbbox_object_instance in object_instances_by_label_ref.values():
assert isinstance(rbbox_object_instance, ObjectInstance), "Expected ObjectInstance type"
if rbbox_object_instance.get_annotation_frames():
label_row.add_object_instance(rbbox_object_instance)
# Collect for saving in the next bundle
label_rows_to_save.append(label_row)
# Step 3: Save all label rows with a bundle
with project.create_bundle(bundle_size=BUNDLE_SIZE) as bundle:
for label_row in label_rows_to_save:
assert label_row is not None, "Trying to save a None label row"
label_row.save(bundle=bundle)
print(f"Saved label row for {label_row.data_title}")
print("Labels with persimmon type radio buttons, checklist attributes, and text labels added for all data units.")
Polygons (Advanced)
PolygonCoordinates(polygons=[[[PointCoordinate(x1, y1), PointCoordinate(x2, y2),...]]]
# 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
# User input
SSH_PATH = "/Users/chris-encord/ssh-private-key.txt"
# SSH_PATH = get_ssh_key() # replace it with ssh key
PROJECT_ID = "00000000-0000-0000-0000-000000000000"
BUNDLE_SIZE = 100
# Create user client using ssh 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"
# 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 = {
"cherries-001.jpg": {
0: {
"label_ref": "blueberry_001",
"coordinates": PolygonCoordinates(
polygons=[
[
[
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",
}
},
"cherries-010.jpg": {
0: [
{
"label_ref": "blueberry_002",
"coordinates": PolygonCoordinates(
polygons=[
[
[
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",
},
{
"label_ref": "blueberry_003",
"coordinates": PolygonCoordinates(
polygons=[
[
[
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(
polygons=[
[
[
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",
},
],
},
"cherries-ig": {
0: {
"label_ref": "blueberry_005",
"coordinates": PolygonCoordinates(
polygons=[
[
[
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",
},
2: [
{
"label_ref": "blueberry_006",
"coordinates": PolygonCoordinates(
polygons=[
[
[
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",
},
{
"label_ref": "blueberry_007",
"coordinates": PolygonCoordinates(
polygons=[
[
[
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_008",
"coordinates": PolygonCoordinates(
polygons=[
[
[
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",
},
],
},
"cherries-is": {
0: {
"label_ref": "blueberry_009",
"coordinates": PolygonCoordinates(
polygons=[
[
[
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",
},
3: [
{
"label_ref": "blueberry_010",
"coordinates": PolygonCoordinates(
polygons=[
[
[
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",
},
{
"label_ref": "blueberry_011",
"coordinates": PolygonCoordinates(
polygons=[
[
[
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_012",
"coordinates": PolygonCoordinates(
polygons=[
[
[
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",
},
],
},
"cherries-vid-001.mp4": {
103: [
{
"label_ref": "blueberry_013",
"coordinates": PolygonCoordinates(
polygons=[
[
[
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(
polygons=[
[
[
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",
},
{
"label_ref": "blueberry_015",
"coordinates": PolygonCoordinates(
polygons=[
[
[
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",
},
],
104: [
{
"label_ref": "blueberry_016",
"coordinates": PolygonCoordinates(
polygons=[
[
[
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(
polygons=[
[
[
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",
},
{
"label_ref": "blueberry_017",
"coordinates": PolygonCoordinates(
polygons=[
[
[
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",
},
],
105: [
{
"label_ref": "blueberry_016",
"coordinates": PolygonCoordinates(
polygons=[
[
[
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",
},
{
"label_ref": "blueberry_014",
"coordinates": PolygonCoordinates(
polygons=[
[
[
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",
},
{
"label_ref": "blueberry_017",
"coordinates": PolygonCoordinates(
polygons=[
[
[
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": "Highbush",
},
],
},
}
# 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"]
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 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, and text labels added for all data units.")
DEPRECATED - Polygons
# 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
# User input
SSH_PATH = "/Users/chris-encord/ssh-private-key.txt"
# SSH_PATH = get_ssh_key() # replace it with ssh key
PROJECT_ID = "00000000-0000-0000-0000-000000000000"
BUNDLE_SIZE = 100
# Create user client using ssh 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"
# 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 = {
"cherries-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",
}
},
"cherries-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",
},
{
"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",
},
],
},
"cherries-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",
},
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",
},
{
"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",
},
{
"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",
},
],
},
"cherries-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",
},
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",
},
{
"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",
},
{
"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",
},
],
},
"cherries-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",
},
{
"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",
},
{
"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",
},
],
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",
},
{
"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",
},
],
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",
},
{
"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",
},
{
"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",
},
],
},
}
# 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"]
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 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, and text labels added for all data units.")
Polyline
# 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, PolylineCoordinates
# User input
SSH_PATH = "/Users/chris-encord/ssh-private-key.txt"
# SSH_PATH = get_ssh_key() # replace it with ssh key
PROJECT_ID = "00000000-0000-0000-0000-000000000000"
BUNDLE_SIZE = 100
# Create user client using ssh 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"
# Get polyline object for branches
polyline_ontology_object: Object = ontology_structure.get_child_by_title(title="Branches", type_=Object)
assert polyline_ontology_object is not None, "Polyline object 'Branches' not found in ontology"
# Get radio attribute for branch type
branch_type_radio_attribute = ontology_structure.get_child_by_title(type_=RadioAttribute, title="Type?")
assert branch_type_radio_attribute is not None, "Radio attribute 'Type?' not found in ontology"
# Get radio options
fruiting_spur_option = branch_type_radio_attribute.get_child_by_title(type_=Option, title="Fruiting spur")
assert fruiting_spur_option is not None, "Option 'Fruiting spur' not found under radio attribute 'Type?'"
sucker_option = branch_type_radio_attribute.get_child_by_title(type_=Option, title="Sucker")
assert sucker_option is not None, "Option 'Sucker' not found under radio attribute 'Type?'"
side_shoot_option = branch_type_radio_attribute.get_child_by_title(type_=Option, title="Side shoot")
assert side_shoot_option is not None, "Option 'Side shoot' not found under radio attribute 'Type?'"
other_branch_option = branch_type_radio_attribute.get_child_by_title(type_=Option, title="Other branch type")
assert other_branch_option is not None, "Option 'Other branch type' not found under radio attribute 'Type?'"
# Fruiting spur Qualities
fruiting_spur_checklist_attribute = ontology_structure.get_child_by_title(
type_=ChecklistAttribute, title="Fruiting spur Qualities?"
)
assert fruiting_spur_checklist_attribute is not None, "Checklist attribute 'Fruiting spur Qualities?' not found"
fruiting_spur_short_length_option = fruiting_spur_checklist_attribute.get_child_by_title(
type_=Option, title="Short length"
)
assert fruiting_spur_short_length_option is not None, "Option 'Short length' not found under 'Fruiting spur Qualities?'"
fruiting_spur_high_bud_density_option = fruiting_spur_checklist_attribute.get_child_by_title(
type_=Option, title="High bud density"
)
assert fruiting_spur_high_bud_density_option is not None, (
"Option 'High bud density' not found under 'Fruiting spur Qualities?'"
)
fruiting_spur_healthy_option = fruiting_spur_checklist_attribute.get_child_by_title(type_=Option, title="Healthy")
assert fruiting_spur_healthy_option is not None, "Option 'Healthy' not found under 'Fruiting spur Qualities?'"
# Sucker Qualities
sucker_checklist_attribute = ontology_structure.get_child_by_title(type_=ChecklistAttribute, title="Sucker Qualities?")
assert sucker_checklist_attribute is not None, "Checklist attribute 'Sucker Qualities?' not found"
sucker_short_length_option = sucker_checklist_attribute.get_child_by_title(type_=Option, title="Short length")
assert sucker_short_length_option is not None, "Option 'Short length' not found under 'Sucker Qualities?'"
sucker_high_bud_density_option = sucker_checklist_attribute.get_child_by_title(type_=Option, title="High bud density")
assert sucker_high_bud_density_option is not None, "Option 'High bud density' not found under 'Sucker Qualities?'"
sucker_healthy_option = sucker_checklist_attribute.get_child_by_title(type_=Option, title="Healthy")
assert sucker_healthy_option is not None, "Option 'Healthy' not found under 'Sucker Qualities?'"
# Side shoot Qualities
side_shoot_checklist_attribute = ontology_structure.get_child_by_title(
type_=ChecklistAttribute, title="Side shoot Qualities?"
)
assert side_shoot_checklist_attribute is not None, "Checklist attribute 'Side shoot Qualities?' not found"
side_shoot_short_length_option = side_shoot_checklist_attribute.get_child_by_title(type_=Option, title="Short length")
assert side_shoot_short_length_option is not None, "Option 'Short length' not found under 'Side shoot Qualities?'"
side_shoot_high_bud_density_option = side_shoot_checklist_attribute.get_child_by_title(
type_=Option, title="High bud density"
)
assert side_shoot_high_bud_density_option is not None, (
"Option 'High bud density' not found under 'Side shoot Qualities?'"
)
side_shoot_healthy_option = side_shoot_checklist_attribute.get_child_by_title(type_=Option, title="Healthy")
assert side_shoot_healthy_option is not None, "Option 'Healthy' not found under 'Side shoot Qualities?'"
# Other branch type text attribute
other_branch_option_text_attribute = ontology_structure.get_child_by_title(
type_=TextAttribute, title="Specify branch type"
)
assert other_branch_option_text_attribute is not None, "Text attribute 'Specify branch type' not found"
# Dictionary of labels per data unit and per frame with branch type specified, including quality options
video_image_frame_labels = {
"cherries-001.jpg": {
0: {
"label_ref": "branch_001",
"coordinates": PolylineCoordinates(
[
PointCoordinate(0.013, 0.023),
PointCoordinate(0.033, 0.033),
PointCoordinate(0.053, 0.023),
PointCoordinate(0.043, 0.013),
]
),
"branch_type": "Fruiting spur",
"fruiting_spur_quality_options": "Short length, High bud density",
}
},
"cherries-010.jpg": {
0: [
{
"label_ref": "branch_002",
"coordinates": PolylineCoordinates(
[
PointCoordinate(0.03, 0.023),
PointCoordinate(0.033, 0.033),
PointCoordinate(0.053, 0.033),
PointCoordinate(0.043, 0.013),
]
),
"branch_type": "Sucker",
"sucker_quality_options": "Short length, High bud density, Healthy",
},
{
"label_ref": "branch_003",
"coordinates": PolylineCoordinates(
[
PointCoordinate(0.043, 0.053),
PointCoordinate(0.063, 0.063),
PointCoordinate(0.083, 0.053),
PointCoordinate(0.073, 0.043),
]
),
"branch_type": "Side shoot",
"side_shoot_quality_options": "Short length",
},
{
"label_ref": "branch_004",
"coordinates": PolylineCoordinates(
[
PointCoordinate(0.073, 0.023),
PointCoordinate(0.093, 0.033),
PointCoordinate(0.113, 0.023),
PointCoordinate(0.103, 0.013),
]
),
"branch_type": "Other branch type",
"Specify branch type": "Cane",
},
],
},
"cherries-ig": {
0: {
"label_ref": "branch_005",
"coordinates": PolylineCoordinates(
[
PointCoordinate(0.013, 0.023),
PointCoordinate(0.033, 0.033),
PointCoordinate(0.053, 0.023),
PointCoordinate(0.043, 0.013),
]
),
"branch_type": "Fruiting spur",
"fruiting_spur_quality_options": "Short length, High bud density",
},
2: [
{
"label_ref": "branch_006",
"coordinates": PolylineCoordinates(
[
PointCoordinate(0.013, 0.023),
PointCoordinate(0.033, 0.033),
PointCoordinate(0.053, 0.023),
PointCoordinate(0.043, 0.013),
]
),
"branch_type": "Sucker",
"sucker_quality_options": "Healthy",
},
{
"label_ref": "branch_007",
"coordinates": PolylineCoordinates(
[
PointCoordinate(0.043, 0.053),
PointCoordinate(0.063, 0.063),
PointCoordinate(0.083, 0.053),
PointCoordinate(0.073, 0.043),
]
),
"branch_type": "Side shoot",
"side_shoot_quality_options": "Short length",
},
{
"label_ref": "branch_008",
"coordinates": PolylineCoordinates(
[
PointCoordinate(0.073, 0.023),
PointCoordinate(0.093, 0.033),
PointCoordinate(0.113, 0.023),
PointCoordinate(0.103, 0.013),
]
),
"branch_type": "Other branch type",
"Specify branch type": "Cane",
},
],
},
"cherries-is": {
0: {
"label_ref": "branch_009",
"coordinates": PolylineCoordinates(
[
PointCoordinate(0.013, 0.023),
PointCoordinate(0.033, 0.033),
PointCoordinate(0.053, 0.023),
PointCoordinate(0.043, 0.013),
]
),
"branch_type": "Fruiting spur",
"fruiting_spur_quality_options": "Short length",
},
3: [
{
"label_ref": "branch_010",
"coordinates": PolylineCoordinates(
[
PointCoordinate(0.013, 0.023),
PointCoordinate(0.033, 0.033),
PointCoordinate(0.053, 0.023),
PointCoordinate(0.043, 0.013),
]
),
"branch_type": "Sucker",
"sucker_quality_options": "Short length, High bud density, Healthy",
},
{
"label_ref": "branch_011",
"coordinates": PolylineCoordinates(
[
PointCoordinate(0.043, 0.053),
PointCoordinate(0.063, 0.063),
PointCoordinate(0.083, 0.053),
PointCoordinate(0.073, 0.043),
]
),
"branch_type": "Side shoot",
"side_shoot_quality_options": "Short length",
},
{
"label_ref": "branch_012",
"coordinates": PolylineCoordinates(
[
PointCoordinate(0.073, 0.023),
PointCoordinate(0.093, 0.033),
PointCoordinate(0.113, 0.023),
PointCoordinate(0.103, 0.013),
]
),
"branch_type": "Other branch type",
"Specify branch type": "Cane",
},
],
},
"cherries-vid-001.mp4": {
103: [
{
"label_ref": "branch_013",
"coordinates": PolylineCoordinates(
[
PointCoordinate(0.013, 0.023),
PointCoordinate(0.033, 0.033),
PointCoordinate(0.053, 0.023),
PointCoordinate(0.043, 0.013),
]
),
"branch_type": "Side shoot",
"side_shoot_quality_options": "Short length",
},
{
"label_ref": "branch_014",
"coordinates": PolylineCoordinates(
[
PointCoordinate(0.043, 0.053),
PointCoordinate(0.063, 0.063),
PointCoordinate(0.083, 0.053),
PointCoordinate(0.073, 0.043),
]
),
"branch_type": "Fruiting spur",
"fruiting_spur_quality_options": "Short length, High bud density, Healthy",
},
{
"label_ref": "branch_015",
"coordinates": PolylineCoordinates(
[
PointCoordinate(0.073, 0.023),
PointCoordinate(0.093, 0.033),
PointCoordinate(0.113, 0.023),
PointCoordinate(0.103, 0.013),
]
),
"branch_type": "Other branch type",
"Specify branch type": "Cane",
},
],
104: [
{
"label_ref": "branch_016",
"coordinates": PolylineCoordinates(
[
PointCoordinate(0.013, 0.023),
PointCoordinate(0.033, 0.033),
PointCoordinate(0.053, 0.023),
PointCoordinate(0.043, 0.013),
]
),
"branch_type": "Side shoot",
"side_shoot_quality_options": "Short length",
},
{
"label_ref": "branch_014",
"coordinates": PolylineCoordinates(
[
PointCoordinate(0.0413, 0.0523),
PointCoordinate(0.0613, 0.0623),
PointCoordinate(0.0813, 0.0523),
PointCoordinate(0.0713, 0.0423),
]
),
"branch_type": "Fruiting spur",
"fruiting_spur_quality_options": "Short length, High bud density, Healthy",
},
{
"label_ref": "branch_017",
"coordinates": PolylineCoordinates(
[
PointCoordinate(0.073, 0.023),
PointCoordinate(0.093, 0.033),
PointCoordinate(0.113, 0.023),
PointCoordinate(0.103, 0.013),
]
),
"branch_type": "Other branch type",
"Specify branch type": "Cane",
},
],
105: [
{
"label_ref": "branch_016",
"coordinates": PolylineCoordinates(
[
PointCoordinate(0.0113, 0.0223),
PointCoordinate(0.0313, 0.0323),
PointCoordinate(0.0513, 0.0223),
PointCoordinate(0.0413, 0.0123),
]
),
"branch_type": "Side shoot",
"side_shoot_quality_options": "Short length",
},
{
"label_ref": "branch_014",
"coordinates": PolylineCoordinates(
[
PointCoordinate(0.0433, 0.0553),
PointCoordinate(0.0633, 0.0653),
PointCoordinate(0.0833, 0.0553),
PointCoordinate(0.0733, 0.0453),
]
),
"branch_type": "Fruiting spur",
"fruiting_spur_quality_options": "Short length, High bud density, Healthy",
},
{
"label_ref": "branch_017",
"coordinates": PolylineCoordinates(
[
PointCoordinate(0.0713, 0.0223),
PointCoordinate(0.0913, 0.0323),
PointCoordinate(0.1113, 0.0223),
PointCoordinate(0.1013, 0.0123),
]
),
"branch_type": "Other branch type",
"Specify branch type": "Cane",
},
],
},
}
# Cache label rows after initialization
label_row_map = {}
# Step 1: Initialize all label rows using a bundle
with project.create_bundle(bundle_size=BUNDLE_SIZE) as bundle:
for data_unit in video_image_frame_labels.keys():
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)}"
if not label_rows:
print(f"Skipping: No label row found for {data_unit}")
continue
label_row = label_rows[0]
label_row.initialise_labels(bundle=bundle)
assert label_row.ontology_structure is not None, f"Ontology not initialized for label row: {data_unit}"
label_row_map[data_unit] = label_row # Cache the initialized label row
# Step 2: Process all frame coordinates and prepare label rows for saving
label_rows_to_save = []
for data_unit, frame_coordinates in video_image_frame_labels.items():
label_row = label_row_map.get(data_unit)
assert label_row is not None, f"Label row not initialized for {data_unit}"
object_instances_by_label_ref = {}
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):
items = [items]
for item in items:
label_ref = item["label_ref"]
coord = item["coordinates"]
branch_type = item["branch_type"]
assert branch_type in {
"Fruiting spur",
"Sucker",
"Side shoot",
"Other branch type",
}, f"Unexpected branch type '{branch_type}' in {data_unit}"
if label_ref not in object_instances_by_label_ref:
polyline_object_instance: ObjectInstance = polyline_ontology_object.create_instance()
assert polyline_object_instance is not None, "Failed to create ObjectInstance"
checklist_attribute = None
quality_options = []
# Assign radio and checklist attributes based on branch type
if branch_type == "Fruiting spur":
assert fruiting_spur_option is not None, "Missing 'fruiting_spur_option'"
polyline_object_instance.set_answer(
attribute=branch_type_radio_attribute, answer=fruiting_spur_option
)
checklist_attribute = fruiting_spur_checklist_attribute
quality_options = item.get("fruiting_spur_quality_options", "").split(", ")
elif branch_type == "Sucker":
assert sucker_option is not None, "Missing 'sucker_option'"
polyline_object_instance.set_answer(attribute=branch_type_radio_attribute, answer=sucker_option)
checklist_attribute = sucker_checklist_attribute
quality_options = item.get("sucker_quality_options", "").split(", ")
elif branch_type == "Side shoot":
assert side_shoot_option is not None, "Missing 'side_shoot_option'"
polyline_object_instance.set_answer(attribute=branch_type_radio_attribute, answer=side_shoot_option)
checklist_attribute = side_shoot_checklist_attribute
quality_options = item.get("side_shoot_quality_options", "").split(", ")
elif branch_type == "Other branch type":
assert other_branch_option is not None, "Missing 'other_branch_option'"
polyline_object_instance.set_answer(
attribute=branch_type_radio_attribute, answer=other_branch_option
)
text_answer = item.get("Specify branch type", "")
assert isinstance(text_answer, str), "'Specify branch type' must be a string"
polyline_object_instance.set_answer(
attribute=other_branch_option_text_attribute, answer=text_answer
)
quality_options = []
# Process checklist options
checklist_answers = []
for quality in quality_options:
option = None
if quality == "Short length":
option = (
fruiting_spur_short_length_option
if branch_type == "Fruiting spur"
else sucker_short_length_option
if branch_type == "Sucker"
else side_shoot_short_length_option
if branch_type == "Side shoot"
else None
)
elif quality == "High bud density":
option = (
fruiting_spur_high_bud_density_option
if branch_type == "Fruiting spur"
else sucker_high_bud_density_option
if branch_type == "Sucker"
else side_shoot_high_bud_density_option
if branch_type == "Side shoot"
else None
)
elif quality == "Healthy":
option = (
fruiting_spur_healthy_option
if branch_type == "Fruiting spur"
else sucker_healthy_option
if branch_type == "Sucker"
else side_shoot_healthy_option
if branch_type == "Side shoot"
else None
)
if option:
checklist_answers.append(option)
else:
assert branch_type == "Other branch type", (
f"Invalid quality '{quality}' for branch type '{branch_type}'"
)
if checklist_attribute and checklist_answers:
polyline_object_instance.set_answer(
attribute=checklist_attribute, answer=checklist_answers, overwrite=True
)
object_instances_by_label_ref[label_ref] = polyline_object_instance
else:
polyline_object_instance = object_instances_by_label_ref[label_ref]
# Assign coordinates for this frame
polyline_object_instance.set_for_frames(coordinates=coord, frames=frame_number)
# Add object instances to the label row if they have frames assigned
for polyline_object_instance in object_instances_by_label_ref.values():
assert isinstance(polyline_object_instance, ObjectInstance), "Expected ObjectInstance type"
if polyline_object_instance.get_annotation_frames():
label_row.add_object_instance(polyline_object_instance)
label_rows_to_save.append(label_row)
# Step 3: Save all label rows using a bundle
with project.create_bundle(bundle_size=BUNDLE_SIZE) as bundle:
for label_row in label_rows_to_save:
assert label_row is not None, "Trying to save a None label row"
label_row.save(bundle=bundle)
print(f"Saved label row for {label_row.data_title}")
print("Labels with branch type radio buttons, checklist attributes, and text labels added for all data units.")
Keypoint
# 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
SSH_PATH = "/Users/chris-encord/ssh-private-key.txt"
# SSH_PATH = get_ssh_key() # replace it with ssh key
PROJECT_ID = "00000000-0000-0000-0000-000000000000"
BUNDLE_SIZE = 100
# Create user client using ssh 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"
# Get keypoint object for floral axis
keypoint_ontology_object: Object = ontology_structure.get_child_by_title(title="Floral axis", type_=Object)
assert keypoint_ontology_object is not None, "Keypoint object 'Floral axis' not found in ontology"
# Get radio attribute for floral axis type
floral_axis_type_radio_attribute = ontology_structure.get_child_by_title(type_=RadioAttribute, title="Type?")
assert floral_axis_type_radio_attribute is not None, "Radio attribute 'Type?' not found"
# Get radio options
pedicel_option = floral_axis_type_radio_attribute.get_child_by_title(type_=Option, title="Pedicel")
assert pedicel_option is not None, "Option 'Pedicel' not found under radio attribute 'Type?'"
peduncle_option = floral_axis_type_radio_attribute.get_child_by_title(type_=Option, title="Peduncle")
assert peduncle_option is not None, "Option 'Peduncle' not found under radio attribute 'Type?'"
other_floral_axis_option = floral_axis_type_radio_attribute.get_child_by_title(
type_=Option, title="Other floral axis type"
)
assert other_floral_axis_option is not None, "Option 'Other floral axis type' not found under radio attribute 'Type?'"
# Get checklist attributes and options for Pedicel
pedicel_checklist_attribute = ontology_structure.get_child_by_title(
type_=ChecklistAttribute, title="Pedicel Qualities?"
)
assert pedicel_checklist_attribute is not None, "Checklist attribute 'Pedicel Qualities?' not found"
pedicel_robust_option = pedicel_checklist_attribute.get_child_by_title(type_=Option, title="Robust")
assert pedicel_robust_option is not None, "Option 'Robust' not found under 'Pedicel Qualities?'"
pedicel_healthy_option = pedicel_checklist_attribute.get_child_by_title(type_=Option, title="Healthy")
assert pedicel_healthy_option is not None, "Option 'Healthy' not found under 'Pedicel Qualities?'"
pedicel_growth_alignment_option = pedicel_checklist_attribute.get_child_by_title(
type_=Option, title="Good Growth and Alignment"
)
assert pedicel_growth_alignment_option is not None, (
"Option 'Good Growth and Alignment' not found under 'Pedicel Qualities?'"
)
# Get checklist attributes and options for Peduncle
peduncle_checklist_attribute = ontology_structure.get_child_by_title(
type_=ChecklistAttribute, title="Peduncle Qualities?"
)
assert peduncle_checklist_attribute is not None, "Checklist attribute 'Peduncle Qualities?' not found"
peduncle_robust_option = peduncle_checklist_attribute.get_child_by_title(type_=Option, title="Robust")
assert peduncle_robust_option is not None, "Option 'Robust' not found under 'Peduncle Qualities?'"
peduncle_healthy_option = peduncle_checklist_attribute.get_child_by_title(type_=Option, title="Healthy")
assert peduncle_healthy_option is not None, "Option 'Healthy' not found under 'Peduncle Qualities?'"
peduncle_growth_alignment_option = peduncle_checklist_attribute.get_child_by_title(
type_=Option, title="Good Growth and Alignment"
)
assert peduncle_growth_alignment_option is not None, (
"Option 'Good Growth and Alignment' not found under 'Peduncle Qualities?'"
)
# Get text attribute for specifying other floral axis types
other_floral_axis_option_text_attribute = ontology_structure.get_child_by_title(
type_=TextAttribute, title="Specify floral axis type"
)
assert other_floral_axis_option_text_attribute is not None, "Text attribute 'Specify floral axis type' not found"
# Dictionary of labels per data unit and per frame with floral axis type specified, including quality options
video_image_frame_labels = {
"blueberries-001.jpg": {
0: {
"label_ref": "floral_axis_001",
"coordinates": PointCoordinate(x=0.01, y=0.02),
"floral_axis_type": "Pedicel",
"pedicel_quality_options": "Robust, Healthy",
}
},
"persimmons-010.jpg": {
0: [
{
"label_ref": "floral_axis_002",
"coordinates": PointCoordinate(x=0.03, y=0.03),
"floral_axis_type": "Peduncle",
"peduncle_quality_options": "Robust, Healthy, Good Growth and Alignment",
},
{
"label_ref": "floral_axis_003",
"coordinates": PointCoordinate(x=0.05, y=0.04),
"floral_axis_type": "Peduncle",
"peduncle_quality_options": "Robust",
},
{
"label_ref": "floral_axis_004",
"coordinates": PointCoordinate(x=0.09, y=0.03),
"floral_axis_type": "Other floral axis type",
"Specify floral axis type": "Calyx",
},
],
},
"blueberries-ig": {
0: {
"label_ref": "floral_axis_005",
"coordinates": PointCoordinate(x=0.05, y=0.02),
"floral_axis_type": "Pedicel",
"pedicel_quality_options": "Robust, Healthy",
},
2: [
{
"label_ref": "floral_axis_006",
"coordinates": PointCoordinate(x=0.03, y=0.03),
"floral_axis_type": "Pedicel",
"pedicel_quality_options": "Good Growth and Alignment",
},
{
"label_ref": "floral_axis_007",
"coordinates": PointCoordinate(x=0.04, y=0.05),
"floral_axis_type": "Pedicel",
"pedicel_quality_options": "Robust",
},
{
"label_ref": "floral_axis_008",
"coordinates": PointCoordinate(x=0.11, y=0.02),
"floral_axis_type": "Other floral axis type",
"Specify floral axis type": "Calyx",
},
],
},
"persimmons-is": {
0: {
"label_ref": "floral_axis_009",
"coordinates": PointCoordinate(x=0.01, y=0.02),
"floral_axis_type": "Peduncle",
"peduncle_quality_options": "Robust",
},
3: [
{
"label_ref": "floral_axis_010",
"coordinates": PointCoordinate(x=0.03, y=0.03),
"floral_axis_type": "Peduncle",
"peduncle_quality_options": "Robust, Healthy, Good Growth and Alignment",
},
{
"label_ref": "floral_axis_011",
"coordinates": PointCoordinate(x=0.08, y=0.05),
"floral_axis_type": "Peduncle",
"peduncle_quality_options": "Robust",
},
{
"label_ref": "floral_axis_012",
"coordinates": PointCoordinate(x=0.11, y=0.02),
"floral_axis_type": "Other floral axis type",
"Specify floral axis type": "Calyx",
},
],
},
"blueberries-vid-001.mp4": {
103: [
{
"label_ref": "floral_axis_013",
"coordinates": PointCoordinate(x=0.02, y=0.01),
"floral_axis_type": "Pedicel",
"pedicel_quality_options": "Robust",
},
{
"label_ref": "floral_axis_014",
"coordinates": PointCoordinate(x=0.06, y=0.06),
"floral_axis_type": "Pedicel",
"pedicel_quality_options": "Robust, Healthy, Good Growth and Alignment",
},
{
"label_ref": "floral_axis_015",
"coordinates": PointCoordinate(x=0.10, y=0.01),
"floral_axis_type": "Other floral axis type",
"Specify floral axis type": "Calyx",
},
],
104: [
{
"label_ref": "floral_axis_016",
"coordinates": PointCoordinate(x=0.04, y=0.01),
"floral_axis_type": "Pedicel",
"pedicel_quality_options": "Robust",
},
{
"label_ref": "floral_axis_014",
"coordinates": PointCoordinate(x=0.08, y=0.05),
"floral_axis_type": "Pedicel",
"pedicel_quality_options": "Robust, Healthy, Good Growth and Alignment",
},
{
"label_ref": "floral_axis_017",
"coordinates": PointCoordinate(x=0.11, y=0.02),
"floral_axis_type": "Other floral axis type",
"Specify floral axis type": "Calyx",
},
],
105: [
{
"label_ref": "floral_axis_016",
"coordinates": PointCoordinate(x=0.05, y=0.02),
"floral_axis_type": "Pedicel",
"pedicel_quality_options": "Robust",
},
{
"label_ref": "floral_axis_014",
"coordinates": PointCoordinate(x=0.07, y=0.04),
"floral_axis_type": "Pedicel",
"pedicel_quality_options": "Robust, Healthy, Good Growth and Alignment",
},
{
"label_ref": "floral_axis_017",
"coordinates": PointCoordinate(x=0.09, y=0.03),
"floral_axis_type": "Other floral axis type",
"Specify floral axis type": "Calyx",
},
],
},
}
# Cache initialized label rows
label_row_map = {}
# Step 1: Initialize all label rows using a bundle
with project.create_bundle(bundle_size=BUNDLE_SIZE) as bundle:
for data_unit in video_image_frame_labels.keys():
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)}"
if not label_rows:
print(f"Skipping: No label row found for {data_unit}")
continue
label_row = label_rows[0]
label_row.initialise_labels(bundle=bundle)
assert label_row.ontology_structure is not None, f"Ontology not initialized for label row: {data_unit}"
label_row_map[data_unit] = label_row # Cache initialized label row for later use
# Step 2: Process all frames/annotations and prepare label rows to save
label_rows_to_save = []
for data_unit, frame_coordinates in video_image_frame_labels.items():
label_row = label_row_map.get(data_unit)
if not label_row:
print(f"Skipping: No initialized label row found for {data_unit}")
continue
object_instances_by_label_ref = {}
# Loop through the frames for the current 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):
items = [items]
for item in items:
label_ref = item["label_ref"]
coord = item["coordinates"]
floral_axis_type = item["floral_axis_type"]
assert floral_axis_type in {
"Pedicel",
"Peduncle",
"Other floral axis type",
}, f"Unexpected floral axis type '{floral_axis_type}' in data unit '{data_unit}'"
# Check if label_ref already exists for reusability
if label_ref not in object_instances_by_label_ref:
keypoint_object_instance: ObjectInstance = keypoint_ontology_object.create_instance()
assert keypoint_object_instance is not None, "Failed to create ObjectInstance"
object_instances_by_label_ref[label_ref] = keypoint_object_instance
checklist_attribute = None
# Set floral axis type attribute
if floral_axis_type == "Pedicel":
assert pedicel_option is not None, "Missing 'pedicel_option'"
keypoint_object_instance.set_answer(
attribute=floral_axis_type_radio_attribute, answer=pedicel_option
)
checklist_attribute = pedicel_checklist_attribute
elif floral_axis_type == "Peduncle":
assert peduncle_option is not None, "Missing 'peduncle_option'"
keypoint_object_instance.set_answer(
attribute=floral_axis_type_radio_attribute, answer=peduncle_option
)
checklist_attribute = peduncle_checklist_attribute
elif floral_axis_type == "Other floral axis type":
assert other_floral_axis_option is not None, "Missing 'other_floral_axis_option'"
keypoint_object_instance.set_answer(
attribute=floral_axis_type_radio_attribute, answer=other_floral_axis_option
)
text_answer = item.get("Specify floral axis type", "")
assert isinstance(text_answer, str), "'Specify floral axis type' must be a string"
keypoint_object_instance.set_answer(
attribute=other_floral_axis_option_text_attribute,
answer=text_answer,
)
# Set checklist attributes
checklist_answers = []
quality_key = f"{floral_axis_type.lower()}_quality_options"
quality_options = item.get(quality_key, "").split(", ")
for quality in quality_options:
if quality == "Robust":
checklist_answers.append(
pedicel_robust_option if floral_axis_type == "Pedicel" else peduncle_robust_option
)
elif quality == "Healthy":
checklist_answers.append(
pedicel_healthy_option if floral_axis_type == "Pedicel" else peduncle_healthy_option
)
elif quality == "Good Growth and Alignment":
checklist_answers.append(
pedicel_growth_alignment_option
if floral_axis_type == "Pedicel"
else peduncle_growth_alignment_option
)
if checklist_attribute and checklist_answers:
keypoint_object_instance.set_answer(
attribute=checklist_attribute, answer=checklist_answers, overwrite=True
)
else:
# Reuse existing instance across frames
keypoint_object_instance = object_instances_by_label_ref[label_ref]
# Assign the object to the frame and track it
keypoint_object_instance.set_for_frames(coordinates=coord, frames=frame_number)
# Add object instances to label_row **only if they have frames assigned**
for keypoint_object_instance in object_instances_by_label_ref.values():
assert isinstance(keypoint_object_instance, ObjectInstance), "Expected ObjectInstance type"
if keypoint_object_instance.get_annotation_frames():
label_row.add_object_instance(keypoint_object_instance)
label_rows_to_save.append(label_row)
# Step 3: Save all label rows using a bundle
with project.create_bundle(bundle_size=BUNDLE_SIZE) as bundle:
for label_row in label_rows_to_save:
assert label_row is not None, "Trying to save a None label row"
label_row.save(bundle=bundle)
print(f"Saved label row for {label_row.data_title}")
print("Labels with floral axis type radio buttons, checklist attributes, and text labels added for all data units.")
Bitmask
# Import dependencies
import os
import numpy as np
from encord import EncordUserClient, Project
from encord.objects import ChecklistAttribute, Object, ObjectInstance, Option, RadioAttribute, TextAttribute
from encord.objects.coordinates import BitmaskCoordinates
# Prepare boolean mask with shape matching frame size
numpy_coordinates = np.ones((1080, 1920)).astype(bool)
assert numpy_coordinates.shape == (1080, 1920), "Mask dimensions must match 1080x1920"
# Paths and identifiers
SSH_PATH = "/Users/chris-encord/ssh-private-key.txt"
PROJECT_ID = "00000000-0000-0000-0000-000000000000"
BUNDLE_SIZE = 100
# Create user client using SSH 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",
)
# Load project
project: Project = user_client.get_project(PROJECT_ID)
assert project is not None, f"Project {PROJECT_ID} could not be loaded"
# Ontology lookup with assertions
ontology_structure = project.ontology_structure
assert ontology_structure, "Ontology structure not found"
bitmask_ontology_object = ontology_structure.get_child_by_title(title="Apples", type_=Object)
assert bitmask_ontology_object is not None, "Ontology object 'Apples' not found"
apple_type_radio_attribute = ontology_structure.get_child_by_title(type_=RadioAttribute, title="Type?")
assert apple_type_radio_attribute is not None, "Radio attribute 'Type?' not found"
sugar_bee_option = apple_type_radio_attribute.get_child_by_title(type_=Option, title="Sugar Bee")
granny_smith_option = apple_type_radio_attribute.get_child_by_title(type_=Option, title="Granny Smith")
honey_crisp_option = apple_type_radio_attribute.get_child_by_title(type_=Option, title="Honey Crisp")
other_apple_option = apple_type_radio_attribute.get_child_by_title(type_=Option, title="Other apple type")
assert all([sugar_bee_option, granny_smith_option, honey_crisp_option, other_apple_option]), "Missing radio options"
# Helper for checklist + options
def assert_checklist_and_options(title, *option_titles):
checklist = ontology_structure.get_child_by_title(type_=ChecklistAttribute, title=title)
assert checklist, f"Checklist '{title}' not found"
options = [checklist.get_child_by_title(type_=Option, title=o) for o in option_titles]
assert all(options), f"Missing options in checklist '{title}'"
return (checklist, *options)
sugar_bee_checklist_attribute, sugar_bee_plump_option, sugar_bee_juicy_option, sugar_bee_large_option = (
assert_checklist_and_options("Sugar Bee Qualities?", "Plump", "Juicy", "Large")
)
granny_smith_checklist_attribute, granny_smith_plump_option, granny_smith_juicy_option, granny_smith_large_option = (
assert_checklist_and_options("Granny Smith Qualities?", "Plump", "Juicy", "Large")
)
honey_crisp_checklist_attribute, honey_crisp_plump_option, honey_crisp_juicy_option, honey_crisp_large_option = (
assert_checklist_and_options("Honey Crisp Qualities?", "Plump", "Juicy", "Large")
)
other_apple_option_text_attribute = ontology_structure.get_child_by_title(
type_=TextAttribute, title="Specify apple type"
)
assert other_apple_option_text_attribute is not None, "TextAttribute 'Specify apple type' not found"
video_frame_labels = {
"cherries-001.jpg": {
0: {
"label_ref": "apple_001",
"coordinates": BitmaskCoordinates(numpy_coordinates),
"apple_type": "Sugar Bee",
"sugar_bee_quality_options": "Plump, Juicy",
}
},
"cherries-010.jpg": {
0: [
{
"label_ref": "apple_002",
"coordinates": BitmaskCoordinates(numpy_coordinates),
"apple_type": "Granny Smith",
"granny_smith_quality_options": "Plump, Juicy, Large",
},
{
"label_ref": "apple_003",
"coordinates": BitmaskCoordinates(numpy_coordinates),
"apple_type": "Honey Crisp",
"honey_crisp_quality_options": "Plump",
},
{
"label_ref": "apple_004",
"coordinates": BitmaskCoordinates(numpy_coordinates),
"apple_type": "Other apple type",
"Specify apple type": "Fuji",
},
],
},
"cherries-ig": {
0: {
"label_ref": "apple_005",
"coordinates": BitmaskCoordinates(numpy_coordinates),
"apple_type": "Sugar Bee",
"sugar_bee_quality_options": "Plump, Juicy",
},
2: [
{
"label_ref": "apple_006",
"coordinates": BitmaskCoordinates(numpy_coordinates),
"apple_type": "Granny Smith",
"granny_smith_quality_options": "Large",
},
{
"label_ref": "apple_007",
"coordinates": BitmaskCoordinates(numpy_coordinates),
"apple_type": "Honey Crisp",
"honey_crisp_quality_options": "Plump",
},
{
"label_ref": "apple_008",
"coordinates": BitmaskCoordinates(numpy_coordinates),
"apple_type": "Other apple type",
"Specify apple type": "Jazz",
},
],
},
"cherries-is": {
0: {
"label_ref": "apple_009",
"coordinates": BitmaskCoordinates(numpy_coordinates),
"apple_type": "Sugar Bee",
"sugar_bee_quality_options": "Plump",
},
3: [
{
"label_ref": "apple_010",
"coordinates": BitmaskCoordinates(numpy_coordinates),
"apple_type": "Granny Smith",
"granny_smith_quality_options": "Plump, Juicy, Large",
},
{
"label_ref": "apple_011",
"coordinates": BitmaskCoordinates(numpy_coordinates),
"apple_type": "Honey Crisp",
"honey_crisp_quality_options": "Plump",
},
{
"label_ref": "apple_012",
"coordinates": BitmaskCoordinates(numpy_coordinates),
"apple_type": "Other apple type",
"Specify apple type": "Red Delicious",
},
],
},
"cherries-vid-001.mp4": {
103: [
{
"label_ref": "apple_013",
"coordinates": BitmaskCoordinates(numpy_coordinates),
"apple_type": "Honey Crisp",
"honey_crisp_quality_options": "Plump",
},
{
"label_ref": "apple_014",
"coordinates": BitmaskCoordinates(numpy_coordinates),
"apple_type": "Sugar Bee",
"sugar_bee_quality_options": "Plump, Juicy, Large",
},
{
"label_ref": "apple_015",
"coordinates": BitmaskCoordinates(numpy_coordinates),
"apple_type": "Other apple type",
"Specify apple type": "Jazz",
},
],
104: [
{
"label_ref": "apple_016",
"coordinates": BitmaskCoordinates(numpy_coordinates),
"apple_type": "Honey Crisp",
"honey_crisp_quality_options": "Plump",
},
{
"label_ref": "apple_014",
"coordinates": BitmaskCoordinates(numpy_coordinates),
"apple_type": "Sugar Bee",
"sugar_bee_quality_options": "Plump, Juicy, Large",
},
{
"label_ref": "apple_017",
"coordinates": BitmaskCoordinates(numpy_coordinates),
"apple_type": "Other apple type",
"Specify apple type": "Fuji",
},
],
105: [
{
"label_ref": "apple_016",
"coordinates": BitmaskCoordinates(numpy_coordinates),
"apple_type": "Honey Crisp",
"honey_crisp_quality_options": "Plump",
},
{
"label_ref": "apple_014",
"coordinates": BitmaskCoordinates(numpy_coordinates),
"apple_type": "Sugar Bee",
"sugar_bee_quality_options": "Plump, Juicy, Large",
},
{
"label_ref": "apple_017",
"coordinates": BitmaskCoordinates(numpy_coordinates),
"apple_type": "Other apple type",
"Specify apple type": "Red Delicious",
},
],
},
}
# Cache initialized label rows
label_row_map = {}
# Step 1: Initialize all label rows
with project.create_bundle(bundle_size=BUNDLE_SIZE) as bundle:
for data_unit in video_frame_labels.keys():
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}"
if not label_rows:
print(f"Skipping: No label row found for {data_unit}")
continue
label_row = label_rows[0]
label_row.initialise_labels(bundle=bundle)
label_row_map[data_unit] = label_row
label_rows_to_save = []
for data_unit, frame_coordinates in video_frame_labels.items():
label_row = label_row_map.get(data_unit)
if not label_row:
print(f"⚠️ Skipping: No initialized label row found for {data_unit}")
continue
object_instances_by_label_ref = {}
for frame_number, items in frame_coordinates.items():
if not isinstance(items, list):
items = [items]
for item in items:
label_ref = item["label_ref"]
coord = item["coordinates"]
apple_type = item["apple_type"]
assert isinstance(coord, BitmaskCoordinates), f"Invalid coordinates for {label_ref}"
# Reuse instance if already created
if label_ref not in object_instances_by_label_ref:
bitmask_object_instance: ObjectInstance = bitmask_ontology_object.create_instance()
object_instances_by_label_ref[label_ref] = bitmask_object_instance
checklist_attribute = None
# Set radio attribute (apple type)
if apple_type == "Sugar Bee":
bitmask_object_instance.set_answer(attribute=apple_type_radio_attribute, answer=sugar_bee_option)
checklist_attribute = sugar_bee_checklist_attribute
elif apple_type == "Granny Smith":
bitmask_object_instance.set_answer(attribute=apple_type_radio_attribute, answer=granny_smith_option)
checklist_attribute = granny_smith_checklist_attribute
elif apple_type == "Honey Crisp":
bitmask_object_instance.set_answer(attribute=apple_type_radio_attribute, answer=honey_crisp_option)
checklist_attribute = honey_crisp_checklist_attribute
elif apple_type == "Other apple type":
bitmask_object_instance.set_answer(attribute=apple_type_radio_attribute, answer=other_apple_option)
text_value = item.get("Specify apple type", "").strip()
assert text_value, f"Missing text answer for 'Other apple type' in {label_ref}"
bitmask_object_instance.set_answer(attribute=other_apple_option_text_attribute, answer=text_value)
# Set checklist answers
checklist_answers = []
quality_key = f"{apple_type.lower()}_quality_options"
quality_list = item.get(quality_key, "")
qualities = [q.strip() for q in quality_list.split(",") if q.strip()]
for quality in qualities:
if quality == "Plump":
checklist_answers.append(
sugar_bee_plump_option
if apple_type == "Sugar Bee"
else granny_smith_plump_option
if apple_type == "Granny Smith"
else honey_crisp_plump_option
)
elif quality == "Juicy":
checklist_answers.append(
sugar_bee_juicy_option
if apple_type == "Sugar Bee"
else granny_smith_juicy_option
if apple_type == "Granny Smith"
else honey_crisp_juicy_option
)
elif quality == "Large":
checklist_answers.append(
sugar_bee_large_option
if apple_type == "Sugar Bee"
else granny_smith_large_option
if apple_type == "Granny Smith"
else honey_crisp_large_option
)
if checklist_attribute and checklist_answers:
bitmask_object_instance.set_answer(
attribute=checklist_attribute, answer=checklist_answers, overwrite=True
)
else:
bitmask_object_instance = object_instances_by_label_ref[label_ref]
# Assign coordinates for this frame
bitmask_object_instance.set_for_frames(coordinates=coord, frames=frame_number)
# Add valid instances to label row
for bitmask_object_instance in object_instances_by_label_ref.values():
assert bitmask_object_instance.get_annotation_frames(), f"No frames set for instance {bitmask_object_instance}"
label_row.add_object_instance(bitmask_object_instance)
label_rows_to_save.append(label_row)
with project.create_bundle(bundle_size=BUNDLE_SIZE) as bundle:
for label_row in label_rows_to_save:
label_row.save(bundle=bundle)
print(f"Saved label row for: {label_row.data_title}")
print("\n🎉 Done! Labels with radio buttons, checklist attributes, and text answers have been added.")
import numpy as np
from encord import EncordUserClient
from encord.objects import Object, OntologyStructure
from encord.objects.coordinates import BitmaskCoordinates
# Prepare the mask
# For simplicity, mask the whole image
# Tthe size of the mask must be identical to the size of the image
numpy_coordinates = np.ones((512, 512))
# Make sure that the image is in boolean format
numpy_coordinates = numpy_coordinates.astype(bool)
# Now we can upload it with the following steps
# Instantiate Encord client and get a project using project hash
user_client = EncordUserClient.create_with_ssh_private_key("<your_private_key>")
project = user_client.get_project("<project_hash>")
# Obtain labels for the media of interest
# In this case, just a first image of the project
label_row = project.list_label_rows_v2()[0]
label_row.initialise_labels()
# Find a bitmask annotation object in the project ontology
ontology_structure: OntologyStructure = label_row.ontology_structure
bitmask_ontology_object: Object = ontology_structure.get_child_by_title(
title="My bitmask feature", type_=Object
)
# Create the instance of this object - actual annotation
bitmask_ontology_object_instance = bitmask_ontology_object.create_instance()
# Set the bitmask as coordinates for the annotation
bitmask_ontology_object_instance.set_for_frames(
# Create coordinates from provided numpy bitmask
coordinates=BitmaskCoordinates(numpy_coordinates),
# Add the bounding box to the first frame
frames=0,
# There are multiple additional fields that can be set optionally:
manual_annotation=True,
)
# And assign the object instance to the label row
label_row.add_object_instance(bitmask_ontology_object_instance)
label_row.save()
Object Primitives
# 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 SkeletonCoordinate, SkeletonCoordinates
from encord.objects.skeleton_template import SkeletonTemplate
# User input
SSH_PATH = "/Users/chris-encord/ssh-private-key.txt"
# SSH_PATH = get_ssh_key() # replace it with ssh key
PROJECT_ID = "00000000-0000-0000-0000-000000000000"
BUNDLE_SIZE = 100
# Create user client using ssh 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 from the project"
# Get the skeleton annotation object
skeleton_ontology_object: Object = ontology_structure.get_child_by_title(title="Strawberries", type_=Object)
assert skeleton_ontology_object is not None, "Object 'Strawberries' not found in ontology"
# Get skeleton template
assert "Triangle" in project.ontology_structure.skeleton_templates, "Skeleton template 'Triangle' not found"
skeleton_template: SkeletonTemplate = project.ontology_structure.skeleton_templates["Triangle"]
assert skeleton_template is not None, "Skeleton template 'Triangle' is None"
# Get skeleton point IDs
skeleton_ids = [coord.feature_hash for coord in skeleton_template.skeleton.values()]
assert skeleton_ids, "Skeleton template 'Triangle' has no keypoints"
# Get radio attribute for strawberry type
strawberry_type_radio_attribute = ontology_structure.get_child_by_title(type_=RadioAttribute, title="Type?")
assert strawberry_type_radio_attribute is not None, "Radio attribute 'Type?' not found"
# Get radio options
albion_option = strawberry_type_radio_attribute.get_child_by_title(type_=Option, title="Albion")
assert albion_option is not None, "Option 'Albion' not found under 'Type?'"
redcoat_option = strawberry_type_radio_attribute.get_child_by_title(type_=Option, title="Redcoat")
assert redcoat_option is not None, "Option 'Redcoat' not found under 'Type?'"
sweet_kiss_option = strawberry_type_radio_attribute.get_child_by_title(type_=Option, title="Sweet Kiss")
assert sweet_kiss_option is not None, "Option 'Sweet Kiss' not found under 'Type?'"
other_strawberry_option = strawberry_type_radio_attribute.get_child_by_title(
type_=Option, title="Other strawberry type"
)
assert other_strawberry_option is not None, "Option 'Other strawberry type' not found under 'Type?'"
# Albion Qualities
albion_checklist_attribute = ontology_structure.get_child_by_title(type_=ChecklistAttribute, title="Albion Qualities?")
assert albion_checklist_attribute is not None, "Checklist attribute 'Albion Qualities?' not found"
albion_plump_option = albion_checklist_attribute.get_child_by_title(type_=Option, title="Plump")
assert albion_plump_option is not None, "Option 'Plump' not found under 'Albion Qualities?'"
albion_juicy_option = albion_checklist_attribute.get_child_by_title(type_=Option, title="Juicy")
assert albion_juicy_option is not None, "Option 'Juicy' not found under 'Albion Qualities?'"
albion_large_option = albion_checklist_attribute.get_child_by_title(type_=Option, title="Large")
assert albion_large_option is not None, "Option 'Large' not found under 'Albion Qualities?'"
# Redcoat Qualities
redcoat_checklist_attribute = ontology_structure.get_child_by_title(
type_=ChecklistAttribute, title="Redcoat Qualities?"
)
assert redcoat_checklist_attribute is not None, "Checklist attribute 'Redcoat Qualities?' not found"
redcoat_plump_option = redcoat_checklist_attribute.get_child_by_title(type_=Option, title="Plump")
assert redcoat_plump_option is not None, "Option 'Plump' not found under 'Redcoat Qualities?'"
redcoat_juicy_option = redcoat_checklist_attribute.get_child_by_title(type_=Option, title="Juicy")
assert redcoat_juicy_option is not None, "Option 'Juicy' not found under 'Redcoat Qualities?'"
redcoat_large_option = redcoat_checklist_attribute.get_child_by_title(type_=Option, title="Large")
assert redcoat_large_option is not None, "Option 'Large' not found under 'Redcoat Qualities?'"
# Sweet Kiss Qualities
sweet_kiss_checklist_attribute = ontology_structure.get_child_by_title(
type_=ChecklistAttribute, title="Sweet Kiss Qualities?"
)
assert sweet_kiss_checklist_attribute is not None, "Checklist attribute 'Sweet Kiss Qualities?' not found"
sweet_kiss_plump_option = sweet_kiss_checklist_attribute.get_child_by_title(type_=Option, title="Plump")
assert sweet_kiss_plump_option is not None, "Option 'Plump' not found under 'Sweet Kiss Qualities?'"
sweet_kiss_juicy_option = sweet_kiss_checklist_attribute.get_child_by_title(type_=Option, title="Juicy")
assert sweet_kiss_juicy_option is not None, "Option 'Juicy' not found under 'Sweet Kiss Qualities?'"
sweet_kiss_large_option = sweet_kiss_checklist_attribute.get_child_by_title(type_=Option, title="Large")
assert sweet_kiss_large_option is not None, "Option 'Large' not found under 'Sweet Kiss Qualities?'"
# Other strawberry type (text input)
other_strawberry_option_text_attribute = ontology_structure.get_child_by_title(
type_=TextAttribute, title="Specify strawberry type"
)
assert other_strawberry_option_text_attribute is not None, "Text attribute 'Specify strawberry type' not found"
# Dictionary of labels per data unit and per frame with strawberry type specified, including quality options
video_frame_labels = {
"cherries-001.jpg": {
0: {
"label_ref": "strawberry_001",
"coordinates": SkeletonCoordinates(
values=[
SkeletonCoordinate(
x=0.25, y=0.25, name="point_0", color="#000000", value="point_0", feature_hash=skeleton_ids[0]
),
SkeletonCoordinate(
x=0.35, y=0.25, name="point_1", color="#000000", value="point_1", feature_hash=skeleton_ids[1]
),
SkeletonCoordinate(
x=0.25, y=0.35, name="point_2", color="#000000", value="point_2", feature_hash=skeleton_ids[2]
),
],
name="Triangle",
),
"strawberry_type": "Albion",
"albion_quality_options": "Plump, Juicy",
}
},
"cherries-010.jpg": {
0: [
{
"label_ref": "strawberry_002",
"coordinates": SkeletonCoordinates(
values=[
SkeletonCoordinate(
x=0.25,
y=0.25,
name="point_0",
color="#000000",
value="point_0",
feature_hash=skeleton_ids[0],
),
SkeletonCoordinate(
x=0.35,
y=0.25,
name="point_1",
color="#000000",
value="point_1",
feature_hash=skeleton_ids[1],
),
SkeletonCoordinate(
x=0.25,
y=0.35,
name="point_2",
color="#000000",
value="point_2",
feature_hash=skeleton_ids[2],
),
],
name="Triangle",
),
"strawberry_type": "Redcoat",
"redcoat_quality_options": "Plump, Juicy, Large",
},
{
"label_ref": "strawberry_003",
"coordinates": SkeletonCoordinates(
values=[
SkeletonCoordinate(
x=0.45,
y=0.45,
name="point_0",
color="#000000",
value="point_0",
feature_hash=skeleton_ids[0],
),
SkeletonCoordinate(
x=0.55,
y=0.45,
name="point_1",
color="#000000",
value="point_1",
feature_hash=skeleton_ids[1],
),
SkeletonCoordinate(
x=0.45,
y=0.55,
name="point_2",
color="#000000",
value="point_2",
feature_hash=skeleton_ids[2],
),
],
name="Triangle",
),
"strawberry_type": "Sweet Kiss",
"sweet_kiss_quality_options": "Plump",
},
{
"label_ref": "strawberry_004",
"coordinates": SkeletonCoordinates(
values=[
SkeletonCoordinate(
x=0.65,
y=0.65,
name="point_0",
color="#000000",
value="point_0",
feature_hash=skeleton_ids[0],
),
SkeletonCoordinate(
x=0.75,
y=0.65,
name="point_1",
color="#000000",
value="point_1",
feature_hash=skeleton_ids[1],
),
SkeletonCoordinate(
x=0.65,
y=0.75,
name="point_2",
color="#000000",
value="point_2",
feature_hash=skeleton_ids[2],
),
],
name="Triangle",
),
"strawberry_type": "Other strawberry type",
"Specify strawberry type": "Pineberry",
},
],
},
"cherries-ig": {
0: {
"label_ref": "strawberry_005",
"coordinates": SkeletonCoordinates(
values=[
SkeletonCoordinate(
x=0.25, y=0.25, name="point_0", color="#000000", value="point_0", feature_hash=skeleton_ids[0]
),
SkeletonCoordinate(
x=0.35, y=0.25, name="point_1", color="#000000", value="point_1", feature_hash=skeleton_ids[1]
),
SkeletonCoordinate(
x=0.25, y=0.35, name="point_2", color="#000000", value="point_2", feature_hash=skeleton_ids[2]
),
],
name="Triangle",
),
"strawberry_type": "Albion",
"albion_quality_options": "Plump, Juicy",
},
2: [
{
"label_ref": "strawberry_006",
"coordinates": SkeletonCoordinates(
values=[
SkeletonCoordinate(
x=0.25,
y=0.25,
name="point_0",
color="#000000",
value="point_0",
feature_hash=skeleton_ids[0],
),
SkeletonCoordinate(
x=0.35,
y=0.25,
name="point_1",
color="#000000",
value="point_1",
feature_hash=skeleton_ids[1],
),
SkeletonCoordinate(
x=0.25,
y=0.35,
name="point_2",
color="#000000",
value="point_2",
feature_hash=skeleton_ids[2],
),
],
name="Triangle",
),
"strawberry_type": "Redcoat",
"redcoat_quality_options": "Large",
},
{
"label_ref": "strawberry_007",
"coordinates": SkeletonCoordinates(
values=[
SkeletonCoordinate(
x=0.45,
y=0.45,
name="point_0",
color="#000000",
value="point_0",
feature_hash=skeleton_ids[0],
),
SkeletonCoordinate(
x=0.55,
y=0.45,
name="point_1",
color="#000000",
value="point_1",
feature_hash=skeleton_ids[1],
),
SkeletonCoordinate(
x=0.45,
y=0.55,
name="point_2",
color="#000000",
value="point_2",
feature_hash=skeleton_ids[2],
),
],
name="Triangle",
),
"strawberry_type": "Sweet Kiss",
"sweet_kiss_quality_options": "Plump",
},
{
"label_ref": "strawberry_008",
"coordinates": SkeletonCoordinates(
values=[
SkeletonCoordinate(
x=0.65,
y=0.65,
name="point_0",
color="#000000",
value="point_0",
feature_hash=skeleton_ids[0],
),
SkeletonCoordinate(
x=0.75,
y=0.65,
name="point_1",
color="#000000",
value="point_1",
feature_hash=skeleton_ids[1],
),
SkeletonCoordinate(
x=0.65,
y=0.75,
name="point_2",
color="#000000",
value="point_2",
feature_hash=skeleton_ids[2],
),
],
name="Triangle",
),
"strawberry_type": "Other strawberry type",
"Specify strawberry type": "Pineberry",
},
],
},
"cherries-is": {
0: {
"label_ref": "strawberry_009",
"coordinates": SkeletonCoordinates(
values=[
SkeletonCoordinate(
x=0.25, y=0.25, name="point_0", color="#000000", value="point_0", feature_hash=skeleton_ids[0]
),
SkeletonCoordinate(
x=0.35, y=0.25, name="point_1", color="#000000", value="point_1", feature_hash=skeleton_ids[1]
),
SkeletonCoordinate(
x=0.25, y=0.35, name="point_2", color="#000000", value="point_2", feature_hash=skeleton_ids[2]
),
],
name="Triangle",
),
"strawberry_type": "Albion",
"albion_quality_options": "Plump",
},
3: [
{
"label_ref": "strawberry_010",
"coordinates": SkeletonCoordinates(
values=[
SkeletonCoordinate(
x=0.25,
y=0.25,
name="point_0",
color="#000000",
value="point_0",
feature_hash=skeleton_ids[0],
),
SkeletonCoordinate(
x=0.35,
y=0.25,
name="point_1",
color="#000000",
value="point_1",
feature_hash=skeleton_ids[1],
),
SkeletonCoordinate(
x=0.25,
y=0.35,
name="point_2",
color="#000000",
value="point_2",
feature_hash=skeleton_ids[2],
),
],
name="Triangle",
),
"strawberry_type": "Redcoat",
"redcoat_quality_options": "Plump, Juicy, Large",
},
{
"label_ref": "strawberry_011",
"coordinates": SkeletonCoordinates(
values=[
SkeletonCoordinate(
x=0.45,
y=0.45,
name="point_0",
color="#000000",
value="point_0",
feature_hash=skeleton_ids[0],
),
SkeletonCoordinate(
x=0.55,
y=0.45,
name="point_1",
color="#000000",
value="point_1",
feature_hash=skeleton_ids[1],
),
SkeletonCoordinate(
x=0.45,
y=0.55,
name="point_2",
color="#000000",
value="point_2",
feature_hash=skeleton_ids[2],
),
],
name="Triangle",
),
"strawberry_type": "Sweet Kiss",
"sweet_kiss_quality_options": "Plump",
},
{
"label_ref": "strawberry_012",
"coordinates": SkeletonCoordinates(
values=[
SkeletonCoordinate(
x=0.65,
y=0.65,
name="point_0",
color="#000000",
value="point_0",
feature_hash=skeleton_ids[0],
),
SkeletonCoordinate(
x=0.75,
y=0.65,
name="point_1",
color="#000000",
value="point_1",
feature_hash=skeleton_ids[1],
),
SkeletonCoordinate(
x=0.65,
y=0.75,
name="point_2",
color="#000000",
value="point_2",
feature_hash=skeleton_ids[2],
),
],
name="Triangle",
),
"strawberry_type": "Other strawberry type",
"Specify strawberry type": "Pineberry",
},
],
},
"cherries-vid-001.mp4": {
103: [
{
"label_ref": "strawberry_013",
"coordinates": SkeletonCoordinates(
values=[
SkeletonCoordinate(
x=0.25,
y=0.25,
name="point_0",
color="#000000",
value="point_0",
feature_hash=skeleton_ids[0],
),
SkeletonCoordinate(
x=0.35,
y=0.25,
name="point_1",
color="#000000",
value="point_1",
feature_hash=skeleton_ids[1],
),
SkeletonCoordinate(
x=0.25,
y=0.35,
name="point_2",
color="#000000",
value="point_2",
feature_hash=skeleton_ids[2],
),
],
name="Triangle",
),
"strawberry_type": "Sweet Kiss",
"sweet_kiss_quality_options": "Plump",
},
{
"label_ref": "strawberry_014",
"coordinates": SkeletonCoordinates(
values=[
SkeletonCoordinate(
x=0.45,
y=0.45,
name="point_0",
color="#000000",
value="point_0",
feature_hash=skeleton_ids[0],
),
SkeletonCoordinate(
x=0.55,
y=0.45,
name="point_1",
color="#000000",
value="point_1",
feature_hash=skeleton_ids[1],
),
SkeletonCoordinate(
x=0.45,
y=0.55,
name="point_2",
color="#000000",
value="point_2",
feature_hash=skeleton_ids[2],
),
],
name="Triangle",
),
"strawberry_type": "Albion",
"albion_quality_options": "Plump, Juicy, Large",
},
{
"label_ref": "strawberry_015",
"coordinates": SkeletonCoordinates(
values=[
SkeletonCoordinate(
x=0.65,
y=0.65,
name="point_0",
color="#000000",
value="point_0",
feature_hash=skeleton_ids[0],
),
SkeletonCoordinate(
x=0.75,
y=0.65,
name="point_1",
color="#000000",
value="point_1",
feature_hash=skeleton_ids[1],
),
SkeletonCoordinate(
x=0.65,
y=0.75,
name="point_2",
color="#000000",
value="point_2",
feature_hash=skeleton_ids[2],
),
],
name="Triangle",
),
"strawberry_type": "Other strawberry type",
"Specify strawberry type": "Pineberry",
},
],
104: [
{
"label_ref": "strawberry_016",
"coordinates": SkeletonCoordinates(
values=[
SkeletonCoordinate(
x=0.15,
y=0.15,
name="point_0",
color="#000000",
value="point_0",
feature_hash=skeleton_ids[0],
),
SkeletonCoordinate(
x=0.25,
y=0.25,
name="point_1",
color="#000000",
value="point_1",
feature_hash=skeleton_ids[1],
),
SkeletonCoordinate(
x=0.15,
y=0.15,
name="point_2",
color="#000000",
value="point_2",
feature_hash=skeleton_ids[2],
),
],
name="Triangle",
),
"strawberry_type": "Sweet Kiss",
"sweet_kiss_quality_options": "Plump",
},
{
"label_ref": "strawberry_014",
"coordinates": SkeletonCoordinates(
values=[
SkeletonCoordinate(
x=0.35,
y=0.35,
name="point_0",
color="#000000",
value="point_0",
feature_hash=skeleton_ids[0],
),
SkeletonCoordinate(
x=0.45,
y=0.35,
name="point_1",
color="#000000",
value="point_1",
feature_hash=skeleton_ids[1],
),
SkeletonCoordinate(
x=0.35,
y=0.45,
name="point_2",
color="#000000",
value="point_2",
feature_hash=skeleton_ids[2],
),
],
name="Triangle",
),
"strawberry_type": "Albion",
"albion_quality_options": "Plump, Juicy, Large",
},
{
"label_ref": "strawberry_017",
"coordinates": SkeletonCoordinates(
values=[
SkeletonCoordinate(
x=0.55,
y=0.55,
name="point_0",
color="#000000",
value="point_0",
feature_hash=skeleton_ids[0],
),
SkeletonCoordinate(
x=0.65,
y=0.55,
name="point_1",
color="#000000",
value="point_1",
feature_hash=skeleton_ids[1],
),
SkeletonCoordinate(
x=0.55,
y=0.65,
name="point_2",
color="#000000",
value="point_2",
feature_hash=skeleton_ids[2],
),
],
name="Triangle",
),
"strawberry_type": "Other strawberry type",
"Specify strawberry type": "Pineberry",
},
],
105: [
{
"label_ref": "strawberry_016",
"coordinates": SkeletonCoordinates(
values=[
SkeletonCoordinate(
x=0.25,
y=0.25,
name="point_0",
color="#000000",
value="point_0",
feature_hash=skeleton_ids[0],
),
SkeletonCoordinate(
x=0.35,
y=0.25,
name="point_1",
color="#000000",
value="point_1",
feature_hash=skeleton_ids[1],
),
SkeletonCoordinate(
x=0.25,
y=0.35,
name="point_2",
color="#000000",
value="point_2",
feature_hash=skeleton_ids[2],
),
],
name="Triangle",
),
"strawberry_type": "Sweet Kiss",
"sweet_kiss_quality_options": "Plump",
},
{
"label_ref": "strawberry_014",
"coordinates": SkeletonCoordinates(
values=[
SkeletonCoordinate(
x=0.45,
y=0.45,
name="point_0",
color="#000000",
value="point_0",
feature_hash=skeleton_ids[0],
),
SkeletonCoordinate(
x=0.55,
y=0.45,
name="point_1",
color="#000000",
value="point_1",
feature_hash=skeleton_ids[1],
),
SkeletonCoordinate(
x=0.45,
y=0.55,
name="point_2",
color="#000000",
value="point_2",
feature_hash=skeleton_ids[2],
),
],
name="Triangle",
),
"strawberry_type": "Albion",
"albion_quality_options": "Plump, Juicy, Large",
},
{
"label_ref": "strawberry_017",
"coordinates": SkeletonCoordinates(
values=[
SkeletonCoordinate(
x=0.75,
y=0.75,
name="point_0",
color="#000000",
value="point_0",
feature_hash=skeleton_ids[0],
),
SkeletonCoordinate(
x=0.65,
y=0.75,
name="point_1",
color="#000000",
value="point_1",
feature_hash=skeleton_ids[1],
),
SkeletonCoordinate(
x=0.75,
y=0.65,
name="point_2",
color="#000000",
value="point_2",
feature_hash=skeleton_ids[2],
),
],
name="Triangle",
),
"strawberry_type": "Other strawberry type",
"Specify strawberry type": "Pineberry",
},
],
},
}
# 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 row 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):
items = [items]
for item in items:
label_ref = item["label_ref"]
coord = item["coordinates"]
strawberry_type = item["strawberry_type"]
assert strawberry_type in {
"Albion",
"Redcoat",
"Sweet Kiss",
"Other strawberry type",
}, f"Unexpected strawberry type '{strawberry_type}' in data unit '{data_unit}'"
if label_ref not in object_instances_by_label_ref:
skeleton_object_instance: ObjectInstance = skeleton_ontology_object.create_instance()
assert skeleton_object_instance is not None, f"Failed to create ObjectInstance for {label_ref}"
object_instances_by_label_ref[label_ref] = skeleton_object_instance
checklist_attribute = None
# Set strawberry type radio attribute
if strawberry_type == "Albion":
assert albion_option is not None, "Missing 'albion_option'"
skeleton_object_instance.set_answer(
attribute=strawberry_type_radio_attribute, answer=albion_option
)
checklist_attribute = albion_checklist_attribute
elif strawberry_type == "Redcoat":
assert redcoat_option is not None, "Missing 'redcoat_option'"
skeleton_object_instance.set_answer(
attribute=strawberry_type_radio_attribute, answer=redcoat_option
)
checklist_attribute = redcoat_checklist_attribute
elif strawberry_type == "Sweet Kiss":
assert sweet_kiss_option is not None, "Missing 'sweet_kiss_option'"
skeleton_object_instance.set_answer(
attribute=strawberry_type_radio_attribute, answer=sweet_kiss_option
)
checklist_attribute = sweet_kiss_checklist_attribute
elif strawberry_type == "Other strawberry type":
assert other_strawberry_option is not None, "Missing 'other_strawberry_option'"
skeleton_object_instance.set_answer(
attribute=strawberry_type_radio_attribute, answer=other_strawberry_option
)
text_answer = item.get("Specify strawberry type", "")
assert isinstance(text_answer, str), "'Specify strawberry type' must be a string"
skeleton_object_instance.set_answer(
attribute=other_strawberry_option_text_attribute,
answer=text_answer,
)
# Set checklist attributes
checklist_answers = []
quality_key = f"{strawberry_type.lower().replace(' ', '_')}_quality_options"
quality_options = item.get(quality_key, "").split(", ")
for quality in quality_options:
option = None
if quality == "Plump":
option = (
albion_plump_option
if strawberry_type == "Albion"
else redcoat_plump_option
if strawberry_type == "Redcoat"
else sweet_kiss_plump_option
if strawberry_type == "Sweet Kiss"
else None
)
elif quality == "Juicy":
option = (
albion_juicy_option
if strawberry_type == "Albion"
else redcoat_juicy_option
if strawberry_type == "Redcoat"
else sweet_kiss_juicy_option
if strawberry_type == "Sweet Kiss"
else None
)
elif quality == "Large":
option = (
albion_large_option
if strawberry_type == "Albion"
else redcoat_large_option
if strawberry_type == "Redcoat"
else sweet_kiss_large_option
if strawberry_type == "Sweet Kiss"
else None
)
if option:
checklist_answers.append(option)
else:
assert strawberry_type == "Other strawberry type", (
f"Invalid quality '{quality}' for strawberry type '{strawberry_type}'"
)
if checklist_attribute and checklist_answers:
skeleton_object_instance.set_answer(
attribute=checklist_attribute, answer=checklist_answers, overwrite=True
)
else:
skeleton_object_instance = object_instances_by_label_ref[label_ref]
# Assign the object to the frame and track it
skeleton_object_instance.set_for_frames(coordinates=coord, frames=frame_number)
# Add object instances to label_row **only if they have frames assigned**
for skeleton_object_instance in object_instances_by_label_ref.values():
assert isinstance(skeleton_object_instance, ObjectInstance), "Expected ObjectInstance type"
if skeleton_object_instance.get_annotation_frames():
label_row.add_object_instance(skeleton_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 strawberry type radio buttons, checklist attributes, and text labels added for all data units.")
Text Classification
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.<private_key_path>
with the key to your private key for authentication.<project_hash>
with the hash of your Project.# 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()
Radio Button
Blueberry or Cherry?
) to a single image (blueberry_003.jpg
).Example 2:Imports a radio button classification (Blueberry or Cherry?
) across a range of sequential frames: 193 to 197) to a video (Blueberries_video.mp4
).#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 ssh 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
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 classification (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
.#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 ssh 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()
Whale
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.
<private_key_path>
with the key to your private key for authentication.<project_hash>
with the hash of your Project.Whale
with the name of your object.# Import dependencies
from typing import List
from encord import EncordUserClient
from encord.objects import LabelRowV2, Classification, ClassificationInstance, Option
# 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()
Whale
has already been created.
# Import dependencies
from typing import List
from encord import EncordUserClient
from encord.objects import LabelRowV2, Classification, ClassificationInstance, Option
# 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 classification exists in the Ontology.
nested_radio_ontology_attribute: Classification = (
ontology_structure.get_child_by_title(
title="Any Other Colours?", 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
is appended to the attribute name.
# Import dependencies
from typing import List
from encord import EncordUserClient
from encord.objects import LabelRowV2, Classification, ClassificationInstance, Option
# 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()
Person
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.
# 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()
initialise_labels
function and saving the label row.
<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.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.
# 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)
Was this page helpful?