Once you have imported your local data or cloud data into Encord, you can import your labels/annotations for the data.
You MUST call the initialise_labels function (once per data unit) before trying to import your labels/annotations.
The process to import labels into Encord consists of the following:
  1. Import the dependencies.
  2. Authenticate your Encord client.
  3. Specify the Annotate Project with the data you want to label.
  4. Specify the label row you want to import your label to. This specifies the data unit (image, image group, image sequence, video, or DICOM series) you want to add your labels to.
  5. Use the initialise_labels function ONCE to prepare the row for your labels.
  6. Apply your labels to the label row.
  7. Save the label row.
One label row is equivalent to one data unit. You only need to use the initialise_labels function and save the label row ONCE per data unit, regardless of how many labels are added to the data unit. However, any future changes to a data unit need to be initialized and saved.

READ THIS FIRST

All the examples demonstrating the use of each label and classification type utilize the following Project and Ontology:
EntityName
ProjectBlueberries and Cherries PROJECT_HASH: 7d4ead9c-4087-4832-a301-eb2545e7d43b
OntologyBlueberries and Cherries Ontology
Bounding boxCherry
Rotatable bounding boxOther type of fruit
PolygonPersimmon
PolylineBranch
KeypointPedicel
BitmaskBlueberry
Object Primitive (Triangle)Strawberry
Radio classificationBlueberry or cherry?
Checklist classificationMany types of fruit?

Object Labels

Classifications


Attributes

The following scripts assume that an object label called 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.
  • Replace <private_key_path> with the key to your private key for authentication.
  • Replace <project_hash> with the hash of your Project.
  • Replace Whale with the name of your object.
  • Replace the attributes and attribute answers to suit your needs.
# 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()

Nested Attributes

Radio button attributes can be nested. The following script assumes that an object label called Whale has already been created.
Nested Radio Attributes
# 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 Attributes

Relation attributes work the exact same way as text attributes, except that when an attribute is marked as Relation the string #relation is appended to the attribute name.
Learn more about relation attributes in Encord here.
Relation Attributes
# 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()

Dynamic Attributes

Dynamic attributes are attributes for object instances where the answer can change in each frame. You can read more about them here. The following example adds bounding boxes for the label 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()

Import Labels in Bulk

When importing a large number of labels, here are some tips to improve your label import performance:
  • A data unit is one image, one image group, one image sequence, one video, or one DICOM series. One data unit is equivalent to one label row. You only need to call the initialise_labels function and save the label row ONCE per data unit. It does not matter how many labels are added to the data unit between the initialise_labels function and saving the label row.
  • Use the bundle function to significantly improve the import performance when you do any of the following:
    • Import labels on a large number of individual images (NOT image groups, image sequences, videos, or DICOM sets).
    • Import labels on a large number of data units at once.
In the following code, ensure you replace:
  • <private_key_path> with the full path to your private key.
  • <project-id> with the unique ID of your Project.
  • #Perform label row operation before in this loop with the label row operations you want to perform.
  • Optionally, change the value of BUNDLE_SIZE to suit your needs. We strongly recommend NOT bundling more than 1000 operations at once, because bundling more than 1000 operations can reduce performance instead of improving performance.

# 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)