> ## Documentation Index
> Fetch the complete documentation index at: https://docs.encord.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Export Labels

The Encord SDK is designed to offer a versatile and targeted approach to accessing label information. This approach allows for a more customized handling of label information, catering to various needs and scenarios in data processing.

The following table describes all values exported by the scripts on this page.

| Key                          | Description                                                                                                                        |
| ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| objectHash                   | The unique ID of the object instance. Two instances of the same object have different object hashes                                |
| Object name                  | The name of the object as defined in the Ontology. For example "Chicken".                                                          |
| featureHash                  | The unique ID of the Ontology element. For example, the object "Chicken" in the Ontology. All instances have the same featureHash. |
| uid                          | The unique identifier for the object instance. Two instances of the same object have different uids.                               |
| Object color                 | The color used to label the object, as defined in the Ontology and seen in the Encord platform.                                    |
| Ontology shape               | The shape used to label the object, as defined in the Ontology. For example, polygon.                                              |
| Classification name          | The name of the Classification, as defined in the Ontology. For example "Day or night?"                                            |
| Classification answer        | The value of the Classification, as defined in the Ontology. For example "Day"                                                     |
| classificationHash           | The unique identifier for the Classification instance.                                                                             |
| Classification answer hash   | The unique identifier for the Classification value                                                                                 |
| Attribute name               | The name of the attribute, as defined in the Ontology. For example "Standing or sitting?"                                          |
| Attribute answer             | The name of the attribute value, as defined in the Ontology. For example "Sitting"                                                 |
| Attribute answer featureHash | The unique identifier for the attribute value.                                                                                     |

***

## Export Labels as JSON

The following script prints a JSON file containing all the labels in your Project.

<Note>
  * Adding `include_all_label_branches=True` to `list_label_rows_v2()` includes all labels from all branches in Consensus Projects.
</Note>

<Warning>
  DEPRECATED @v186: For Data Groups, adding `include_children=True` to `list_label_rows_v2()` includes all labels from Data Groups.
</Warning>

<Tip>
  We recommend using [`bundle`](/sdk-documentation/sdk-references/http.bundle#bundle-objects) in your scripts to improve performance. Keep bundle sizes under 1000 operations. Bundles of more than 1000 operations can degrade performance rather than improve performance.

  The optimal bundle size depends on your use case. For example, for videos with a large number of labels, start with 20 operations and adjust up or down based on performance.
</Tip>

```python Export labels to JSON expandable theme={"dark"}

# Import dependencies
import json
import os

from encord import EncordUserClient

SSH_PATH = "/Users/chris-encord/ssh-private-key.txt" # Replace with file path to your SSH private key
PROJECT_ID = "00000000-0000-0000-0000-000000000000" # Replace with Project unique ID
BUNDLE_SIZE = 100  # Customize as needed
OUTPUT_JSON = "/Users/chris-encord/export-label-rows.json" # Replace with file path to save JSON output file

# Create user client using access key
user_client: EncordUserClient = EncordUserClient.create_with_ssh_private_key(
    ssh_private_key_path=SSH_PATH,
    # For US platform users use "https://api.us.encord.com"
    domain="https://api.encord.com",
)

# Specify Project
project = user_client.get_project(PROJECT_ID)
assert project is not None, f"Project with ID {PROJECT_ID} could not be loaded"

# Get label rows for your Project
label_rows = project.list_label_rows_v2()
assert label_rows, f"No label rows found in project {PROJECT_ID}"

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

# Collect all label row data
all_label_rows = [label_row.to_encord_dict() for label_row in label_rows]
assert all_label_rows, "No label row data collected for export"

# Save the collected label rows data to a JSON file
output_file = OUTPUT_JSON
assert output_file.endswith(".json"), "Output file must be a .json file"

with open(output_file, "w") as file:
    json.dump(all_label_rows, file, indent=4)

print(f"Label rows have been saved to {output_file}.")

```

***

## Export Attributes

The following scripts get the attributes for all labels in a Project, as well as the frames that the attributes appear on. Single images only have a single frame.

<Info>
  We recommend using the script for exporting all attributes if the Project uses
  an Ontology with nested attributes.{" "}
</Info>

<CodeGroup>
  ```python Text attributes expandable theme={"dark"}

  # Import dependencies
  import json

  from encord import EncordUserClient
  from encord.objects import ObjectInstance
  from encord.objects.attributes import Attribute, TextAttribute

  # User input
  SSH_PATH = "/Users/chris-encord/ssh-private-key.txt"
  PROJECT_ID = "00000000-0000-0000-0000-000000000000"
  DATA_UNIT = "cherries-is"
  OUTPUT_FILE_PATH = "/Users/chris-encord/text_attributes_output.json"
  BUNDLE_SIZE = 100

  # Create user client using access key
  user_client: EncordUserClient = EncordUserClient.create_with_ssh_private_key(
      ssh_private_key_path=SSH_PATH,
      # For US platform users use "https://api.us.encord.com"
      domain="https://api.encord.com",
  )

  # Specify Project
  project = user_client.get_project(PROJECT_ID)
  assert project is not None, f"Project with ID {PROJECT_ID} could not be loaded"

  # Filter label rows for a specific data title
  label_rows = project.list_label_rows_v2(data_title_eq=DATA_UNIT)
  assert label_rows, f"No label rows found for data title '{DATA_UNIT}'"

  # Initialize labels using bundle
  with project.create_bundle(bundle_size=BUNDLE_SIZE) as bundle:
      for label_row in label_rows:
          label_row.initialise_labels(bundle=bundle)


  # Function to extract text attributes and store in structured format
  def extract_text_attributes(attribute: Attribute, object_instance: ObjectInstance, frame_number: int):
      if isinstance(attribute, TextAttribute):
          text_answer = object_instance.get_answer(attribute)
          return {
              "frame": frame_number + 1,
              "attribute_name": attribute.title,
              "attribute_hash": attribute.feature_node_hash,
              "text_answer": text_answer,
          }
      return None


  # Collect results for saving
  results = []

  # Iterate through all object instances and collect text attribute data
  for label_row in label_rows:
      object_instances = label_row.get_object_instances()
      assert object_instances, f"No object instances found in label row {label_row.uid}"

      for object_instance in object_instances:
          annotations = object_instance.get_annotations()
          assert annotations, f"No annotations found for object instance {object_instance.object_hash}"

          ontology_item = object_instance.ontology_item
          assert ontology_item and ontology_item.attributes, (
              f"Missing ontology item or attributes for object {object_instance.object_hash}"
          )

          for annotation in annotations:
              for attribute in ontology_item.attributes:
                  attr_data = extract_text_attributes(attribute, object_instance, annotation.frame)
                  if attr_data:
                      results.append(attr_data)
                      # Optional: also print to console
                      print(f"Frame {attr_data['frame']}:")
                      print(f"Text Attribute name: {attr_data['attribute_name']}")
                      print(f"Text Attribute hash: {attr_data['attribute_hash']}")
                      print(f"Text Attribute Answer: {attr_data['text_answer']}")

  # Save results to JSON
  assert OUTPUT_FILE_PATH.endswith(".json"), "Output file path must end with .json"

  with open(OUTPUT_FILE_PATH, "w") as f:
      json.dump(results, f, indent=4)

  print(f"\nText attribute data saved to: {OUTPUT_FILE_PATH}")

  ```

  ```python Radio buttons expandable theme={"dark"}

  # Import dependencies
  import json
  import os

  from encord import EncordUserClient
  from encord.objects import ObjectInstance
  from encord.objects.attributes import Attribute, RadioAttribute

  # User input
  SSH_PATH = "/Users/chris-encord/ssh-private-key.txt"
  PROJECT_ID = "00000000-0000-0000-0000-000000000000"
  DATA_UNIT = "cherries-010.jpg"
  OUTPUT_FILE_PATH = "/Users/chris-encord/radio_attribute_output.json"
  BUNDLE_SIZE = 100

  # Create user client using access key
  user_client: EncordUserClient = EncordUserClient.create_with_ssh_private_key(
      ssh_private_key_path=SSH_PATH,
      # For US platform users use "https://api.us.encord.com"
      domain="https://api.encord.com",
  )

  # Get project and label rows
  project = user_client.get_project(PROJECT_ID)
  assert project is not None, f"Project with ID {PROJECT_ID} could not be loaded"

  label_rows = project.list_label_rows_v2(data_title_eq=DATA_UNIT)
  assert label_rows, f"No label rows found for data unit: {DATA_UNIT}"

  # Initialize label rows using bundle
  with project.create_bundle(bundle_size=BUNDLE_SIZE) as bundle:
      for label_row in label_rows:
          label_row.initialise_labels(bundle=bundle)

  # Prepare data structure to collect all results
  output_data = []


  # Function to extract info from RadioAttribute (recursively if nested)
  def extract_attributes(attribute: Attribute, object_instance: ObjectInstance, frame_number: int):
      frame_data = []

      if isinstance(attribute, RadioAttribute):
          attribute_answers = object_instance.get_answer(attribute)
          if not isinstance(attribute_answers, list):
              attribute_answers = [attribute_answers]

          for answer in attribute_answers:
              if answer is None:
                  continue  # Skip empty answers

              answer_data = {
                  "frame": frame_number + 1,
                  "attribute_name": attribute.title,
                  "attribute_hash": attribute.feature_node_hash,
                  "answer_title": answer.title,
                  "answer_hash": answer.feature_node_hash,
                  "nested_attributes": [],
              }

              if hasattr(answer, "attributes") and answer.attributes:
                  for nested_attribute in answer.attributes:
                      nested_data = extract_attributes(nested_attribute, object_instance, frame_number)
                      if nested_data:
                          answer_data["nested_attributes"].extend(nested_data)

              frame_data.append(answer_data)

      return frame_data


  # Loop through label rows and extract attribute data
  for label_row in label_rows:
      object_instances = label_row.get_object_instances()
      assert object_instances, f"No object instances found in label row {label_row.uid}"

      for object_instance in object_instances:
          annotations = object_instance.get_annotations()
          assert annotations, f"No annotations found for object instance {object_instance.object_hash}"

          ontology_item = object_instance.ontology_item
          assert ontology_item and ontology_item.attributes, (
              f"No ontology item or attributes found for object {object_instance.object_hash}"
          )

          for annotation in annotations:
              for attribute in ontology_item.attributes:
                  attr_data = extract_attributes(attribute, object_instance, annotation.frame)
                  if attr_data:
                      output_data.extend(attr_data)

  # Save results to JSON
  assert OUTPUT_FILE_PATH.endswith(".json"), "Output file path must end with .json"

  with open(OUTPUT_FILE_PATH, "w") as f:
      json.dump(output_data, f, indent=4)

  print(f"Radio attribute data saved to {OUTPUT_FILE_PATH}")

  ```

  ```python Checklist attributes expandable theme={"dark"}

  # Import dependencies
  import json
  import os

  from encord import EncordUserClient
  from encord.objects import ObjectInstance
  from encord.objects.attributes import Attribute, ChecklistAttribute

  # User input
  SSH_PATH = "/Users/chris-encord/ssh-private-key.txt"
  PROJECT_ID = "00000000-0000-0000-0000-000000000000"
  DATA_UNIT = "cherries-010.jpg"
  OUTPUT_FILE_PATH = "/Users/chris-encord/checklist_attributes_output.json"
  BUNDLE_SIZE = 100

  # Create user client using access key
  user_client: EncordUserClient = EncordUserClient.create_with_ssh_private_key(
      ssh_private_key_path=SSH_PATH,
      # For US platform users use "https://api.us.encord.com"
      domain="https://api.encord.com",
  )

  # Load the project and filter label rows
  project = user_client.get_project(PROJECT_ID)
  assert project is not None, f"Project with ID {PROJECT_ID} could not be loaded"

  label_rows = project.list_label_rows_v2(data_title_eq=DATA_UNIT)
  assert label_rows, f"No label rows found for data unit: {DATA_UNIT}"

  # Initialize label rows using bundle
  with project.create_bundle(bundle_size=BUNDLE_SIZE) as bundle:
      for label_row in label_rows:
          label_row.initialise_labels(bundle=bundle)


  # Function to extract checklist attributes in structured format
  def extract_attributes(attribute: Attribute, object_instance: ObjectInstance, frame_number: int):
      if isinstance(attribute, ChecklistAttribute):
          attribute_answers = object_instance.get_answer(attribute)
          if not isinstance(attribute_answers, list):
              attribute_answers = [attribute_answers]

          return {
              "frame": frame_number + 1,
              "attribute_name": attribute.title,
              "attribute_hash": attribute.feature_node_hash,
              "answers": [
                  {
                      "title": answer.title,
                      "hash": answer.feature_node_hash,
                  }
                  for answer in attribute_answers
                  if answer
              ],
          }
      return None


  # Collect data for saving
  results = []

  # Iterate through label rows and extract checklist attribute data
  for label_row in label_rows:
      object_instances = label_row.get_object_instances()
      assert object_instances, f"No object instances found in label row {label_row.uid}"

      for object_instance in object_instances:
          annotations = object_instance.get_annotations()
          assert annotations, f"No annotations found for object instance {object_instance.object_hash}"

          ontology_item = object_instance.ontology_item
          assert ontology_item and ontology_item.attributes, (
              f"No ontology item or attributes found for object {object_instance.object_hash}"
          )

          for annotation in annotations:
              for attribute in ontology_item.attributes:
                  attr_data = extract_attributes(attribute, object_instance, annotation.frame)
                  if attr_data:
                      results.append(attr_data)
                      print(f"Frame {attr_data['frame']}:")
                      print(f"Checklist Attribute name: {attr_data['attribute_name']}")
                      for answer in attr_data["answers"]:
                          print(f"Checklist answer: {answer['title']}")
                          print(f"Checklist answer hash: {answer['hash']}")

  # Save to JSON
  assert OUTPUT_FILE_PATH.endswith(".json"), "Output file path must end with .json"

  with open(OUTPUT_FILE_PATH, "w") as f:
      json.dump(results, f, indent=4)

  print(f"\nChecklist attribute data saved to: {OUTPUT_FILE_PATH}")

  ```

  ```python All attributes theme={"dark"}

  # Import dependencies
  import json
  from collections.abc import Iterable

  from encord import EncordUserClient
  from encord.objects import ObjectInstance
  from encord.objects.attributes import Attribute, ChecklistAttribute, RadioAttribute, TextAttribute

  # User input
  SSH_PATH = "/Users/chris-encord/ssh-private-key.txt"
  # SSH_PATH = get_ssh_key() # replace it with access key
  PROJECT_ID = "00000000-0000-0000-0000-000000000000"
  DATA_UNIT = "cherries-010.jpg"
  OUTPUT_FILE_PATH = "/Users/chris-encord/all_attributes_output.json"
  BUNDLE_SIZE = 100

  # Create user client using access key
  user_client: EncordUserClient = EncordUserClient.create_with_ssh_private_key(
      ssh_private_key_path=SSH_PATH,
      # For US platform users use "https://api.us.encord.com"
      domain="https://api.encord.com",
  )

  # Load project and label rows
  project = user_client.get_project(PROJECT_ID)
  assert project is not None, f"Project with ID {PROJECT_ID} could not be loaded"

  label_rows = project.list_label_rows_v2(data_title_eq=DATA_UNIT)
  assert label_rows, f"No label rows found for data unit: {DATA_UNIT}"

  # Initialize label rows using bundle
  with project.create_bundle(bundle_size=BUNDLE_SIZE) as bundle:
      for label_row in label_rows:
          label_row.initialise_labels(bundle=bundle)

  # Container for structured results
  results = []


  # Function to collect and print attributes
  def extract_and_print_attributes(attribute: Attribute, object_instance: ObjectInstance, frame_number: int):
      attr_data = {
          "frame": frame_number + 1,
          "attribute_name": attribute.title,
          "attribute_hash": attribute.feature_node_hash,
          "attribute_type": None,
          "answers": [],
      }

      if isinstance(attribute, TextAttribute):
          attr_data["attribute_type"] = "TextAttribute"
          text_answer = object_instance.get_answer(attribute)
          attr_data["answers"].append({"text": text_answer or "No attribute answer"})

      elif isinstance(attribute, RadioAttribute):
          attr_data["attribute_type"] = "RadioAttribute"
          answer = object_instance.get_answer(attribute)
          if answer:
              answer_data = {"title": answer.title, "hash": answer.feature_node_hash, "nested_attributes": []}

              if hasattr(answer, "attributes") and answer.attributes:
                  for nested_attribute in answer.attributes:
                      nested_result = extract_and_print_attributes(nested_attribute, object_instance, frame_number)
                      if nested_result:
                          answer_data["nested_attributes"].append(nested_result)

              attr_data["answers"].append(answer_data)
          else:
              attr_data["answers"].append({"note": "No attribute answer"})

      elif isinstance(attribute, ChecklistAttribute):
          attr_data["attribute_type"] = "ChecklistAttribute"
          answers = object_instance.get_answer(attribute)
          if answers:
              if not isinstance(answers, Iterable):
                  answers = [answers]
              for answer in answers:
                  attr_data["answers"].append({"title": answer.title, "hash": answer.feature_node_hash})
          else:
              attr_data["answers"].append({"note": "No attribute answer"})

      # Print the same info (optional)
      print(f"Frame {attr_data['frame']}: {attr_data['attribute_type']} name: {attr_data['attribute_name']}")
      for answer in attr_data["answers"]:
          if "title" in answer:
              print(f"Answer: {answer['title']}")
              print(f"Answer hash: {answer['hash']}")
          elif "text" in answer:
              print(f"Answer: {answer['text']}")
          elif "note" in answer:
              print(f"Note: {answer['note']}")
          if "nested_attributes" in answer:
              for nested in answer["nested_attributes"]:
                  print(f"Nested attribute: {nested['attribute_name']} ({nested['attribute_hash']})")

      return attr_data


  # Process all label rows
  for label_row in label_rows:
      object_instances = label_row.get_object_instances()
      assert object_instances, f"No object instances found in label row {label_row.uid}"

      for object_instance in object_instances:
          annotations = object_instance.get_annotations()
          assert annotations, f"No annotations found for object instance {object_instance.object_hash}"

          assert object_instance.ontology_item and object_instance.ontology_item.attributes, (
              f"No attributes found for object {object_instance.object_hash}"
          )

          for annotation in annotations:
              for attribute in object_instance.ontology_item.attributes:
                  extracted = extract_and_print_attributes(attribute, object_instance, annotation.frame)
                  if extracted:
                      results.append(extracted)

  # Save to JSON
  assert OUTPUT_FILE_PATH.endswith(".json"), "Output file path must be a JSON file"

  with open(OUTPUT_FILE_PATH, "w") as f:
      json.dump(results, f, indent=4)

  print(f"\nAll attribute data saved to: {OUTPUT_FILE_PATH}")

  ```
</CodeGroup>

***

## Export Objects and Classifications

<Warning>
  The following scripts do not support Ontologies with text classifications, or
  nested classifications. The scripts serve as a template for exporting object
  labels only.{" "}
</Warning>

The following script shows how to access and print essential label information for all object and classification instances, and all attributes in a Project. The example for videos, image groups, image sequences and DICOM outputs the frame numbers of each object, classification and attribute.

Make sure you substitute:

* The `<private_key_path>` with the full path to your private key.
* The `<project_id>` with the ID of your Project.

<CodeGroup>
  ```python Videos / Image Groups / Image sequences / DICOM theme={"dark"}
  # Import dependencies
  from encord import EncordUserClient
  from encord.objects.ontology_element import OntologyElement
  from encord.objects.attributes import Attribute
  from encord.objects import ObjectInstance

  # Instantiate Encord client by substituting the path to your private key
  user_client = EncordUserClient.create_with_ssh_private_key(
      ssh_private_key_path="<private_key_path>"
  )

  # Replace <project_id> with the hash of your Project
  project = user_client.get_project("<project_id>")

  # A function to extract and print essential information for all attributes
  def print_attributes(attribute: Attribute, object_instance: ObjectInstance):
      print(f"Attribute name: {attribute.title}")
      print(f"Attribute hash: {attribute.feature_node_hash}")
      for answer_for_frames in object_instance.get_answer(attribute):
          print(f"Attribute answer \"{answer_for_frames.answer.title}\" is present on frames {answer_for_frames.ranges}")
          print ("Attribute answer hash " + answer_for_frames.answer.feature_node_hash)
          for attribute in answer_for_frames.answer.attributes:
              print(f"Attribute answer \"{answer_for_frames.answer.title}\" has nested attribute \"{attribute.title}\"")
              print_attributes(attribute, object_instance)

  # Initialize label rows using bundles
  label_rows = project.list_label_rows_v2()
  with project.create_bundle() as bundle:
      for label_row in label_rows:
          label_row.initialise_labels(bundle=bundle)

  for label_row in label_rows:
      # Print essential label information for all objects
      for object_instance in label_row.get_object_instances():
          print ("objectHash: " + object_instance.object_hash)
          print ("Object name: " + object_instance.object_name)
          print ("featureHash: " + object_instance.feature_hash)
          print ("uid: " + str(object_instance.ontology_item.uid))
          print ("Object color: " + object_instance.ontology_item.color)
          print ("Ontology shape: " + object_instance.ontology_item.shape)

          # Print the frame number and the location of the object on the frame
          for annotation in object_instance.get_annotations():
              print(f"Frame {annotation.frame} -> {annotation.coordinates}")

          # Print all attributes
          for attribute in object_instance.ontology_item.attributes:
              print_attributes(attribute, object_instance)

      # Print all essential classification information
      for classification_instance in label_row.get_classification_instances():
          print ("classificationHash: " + classification_instance.classification_hash)
          print ("Classification name: " + classification_instance.classification_name)
          print ("featureHash: " + classification_instance.feature_hash)
          print ("Classification answer: " + classification_instance.get_answer().value)
          print ("Classification answer hash: " + classification_instance.get_answer().feature_node_hash)

          # Print the frame number(s) that a classification appears on
          for annotation in classification_instance.get_annotations():
              print("Classification appears on frame " + str(annotation.frame))
  ```

  ```python Single images theme={"dark"}
  from encord import EncordUserClient
  from encord.objects.ontology_element import OntologyElement
  from encord.objects.attributes import Attribute
  from encord.objects import ObjectInstance

  # Instantiate Encord client by substituting the path to your private key
  user_client = EncordUserClient.create_with_ssh_private_key(
      ssh_private_key_path="<private_key_path>"
  )

  # Replace <project_id> with the ID of your Project
  project = user_client.get_project("<project_id>")

  # Print essential info for all attributes
  def print_attributes(attribute: Attribute, object_instance: ObjectInstance):
      print(f"Attribute name: {attribute.title}")
      print(f"Attribute hash: {attribute.feature_node_hash}")
      for attribute_answer in object_instance.get_answer(attribute):
          print(f"Attribute answer: {attribute_answer.answer.title}")
          print ("Attribute answer hash " + attribute_answer.answer.feature_node_hash)
          for attribute in attribute_answer.answer.attributes:
              print(f"Attribute answer \"{attribute_answer.answer.title}\" has nested attribute \"{attribute.title}\"")
              print ("Attribute answer hash " + attribute_answer.answer.feature_node_hash)
              print_attributes(attribute, object_instance)

  # Initialize label rows using bundles
  label_rows = project.list_label_rows_v2()
  with project.create_bundle() as bundle:
      for label_row in label_rows:
          label_row.initialise_labels(bundle=bundle)

  for label_row in label_rows:
      # Print essential label information for all objects
      for object_instance in label_row.get_object_instances():
          print ("objectHash: " + object_instance.object_hash)
          print ("Object name: " + object_instance.object_name)
          print ("featureHash: " + object_instance.feature_hash)
          print ("uid: " + str(object_instance.ontology_item.uid))
          print ("Object color: " + object_instance.ontology_item.color)
          print ("Ontology shape: " + object_instance.ontology_item.shape)

          for annotation in object_instance.get_annotations():
              print(f"Frame {annotation.frame} -> {annotation.coordinates}")

          for attribute in object_instance.ontology_item.attributes:
              print_attributes(attribute, object_instance)

      for classification_instance in label_row.get_classification_instances():
          print ("classificationHash: " + classification_instance.classification_hash)
          print ("Classification name: " + classification_instance.classification_name)
          print ("featureHash: " + classification_instance.feature_hash)

          for annotation in classification_instance.get_annotations():
              print("Classification on frame " + str(annotation.frame))

  ```

  ```python Example Output theme={"dark"}
  objectHash: HI5408US
  Object name: Chicken
  featureHash: p6T5NeQ4
  uid: 1
  Object color: #D33115
  Ontology Shape: bounding_box
  Frame 101 -> BoundingBoxCoordinates(height=0.526, width=0.2514, top_left_x=0.5826, top_left_y=0.2431)
  Frame 102 -> BoundingBoxCoordinates(height=0.5365, width=0.256, top_left_x=0.578, top_left_y=0.2413)
  Frame 103 -> BoundingBoxCoordinates(height=0.5469, width=0.2615, top_left_x=0.5752, top_left_y=0.2378)
  Frame 104 -> BoundingBoxCoordinates(height=0.5365, width=0.256, top_left_x=0.5798, top_left_y=0.2396)
  Frame 105 -> BoundingBoxCoordinates(height=0.5365, width=0.256, top_left_x=0.5661, top_left_y=0.2396)
  Frame 106 -> BoundingBoxCoordinates(height=0.5469, width=0.2615, top_left_x=0.5633, top_left_y=0.2361)
  Frame 107 -> BoundingBoxCoordinates(height=0.5365, width=0.256, top_left_x=0.5532, top_left_y=0.2361)
  Frame 108 -> BoundingBoxCoordinates(height=0.526, width=0.2514, top_left_x=0.556, top_left_y=0.2413)
  Attribute name: Walking or Sitting?
  featureHash: pHXXPbuc
  Attribute answer "Walking" is present on frames [(101:104)]
  Attribute answer featureHash: 6qeufh3l
  Attribute answer "Sitting" is present on frames [(105:108)]
  Attribute answer featureHash: hkInN4Sd
  classificationHash: gffOkg9l
  Classification name: Day or Night?
  featureHash: FA6pAde3
  Classification answer: Day
  Classification answer hash: gasjasd
  Classification appears on frame 352
  ```
</CodeGroup>

## Export Objects, Classifications, and Attributes by Frame

<Warning>
  Videos with [variable frame
  rates](/platform-documentation/General/general-supported-data#frame-synchronization-issues)
  can result in misplaced labels.{" "}
</Warning>

### Range of Consecutive Frames

The following scripts download and print the labels for a specified range of frames in videos.

<Tip>To export labels for a single frame, make the \<start\_frame\_number> the same as the \<end\_frame\_number>. For example, to export labels on the 13th frame set \<start\_frame\_number>  = 13, and \<end\_frame\_number> = 13.</Tip>

<CodeGroup>
  ```python Frame range for a specific task expandable theme={"dark"}

  # Import dependencies
  import json

  from encord import EncordUserClient
  from encord.objects import ObjectInstance
  from encord.objects.attributes import Attribute

  # User input
  SSH_PATH = "/Users/chris-encord/ssh-private-key.txt"
  PROJECT_ID = "00000000-0000-0000-0000-000000000000"
  DATA_UNIT = "cherries-is"
  OUTPUT_FILE_PATH = "/Users/chris-encord/frame_range_output.json"
  START_FRAME_NUMBER = 0
  END_FRAME_NUMBER = 35
  BUNDLE_SIZE = 100

  # Create user client using access key
  user_client: EncordUserClient = EncordUserClient.create_with_ssh_private_key(
      ssh_private_key_path=SSH_PATH,
      # For US platform users use "https://api.us.encord.com"
      domain="https://api.encord.com",
  )

  # Load the project
  project = user_client.get_project(PROJECT_ID)
  assert project is not None, f"Project with ID {PROJECT_ID} could not be loaded"

  # Get filtered label rows
  label_rows = project.list_label_rows_v2(data_title_eq=DATA_UNIT)
  assert label_rows, f"No label rows found for data unit: {DATA_UNIT}"

  # Initialize labels using bundles
  with project.create_bundle(bundle_size=BUNDLE_SIZE) as bundle:
      for label_row in label_rows:
          label_row.initialise_labels(bundle=bundle)


  # Function to extract attributes in a structured format
  def extract_attributes(attribute: Attribute, object_instance: ObjectInstance):
      try:
          answer = object_instance.get_answer(attribute)
      except Exception:
          answer = None
      return {
          "attribute_name": attribute.title,
          "attribute_hash": attribute.feature_node_hash,
          "attribute_answer": str(answer),
      }


  # Result collection
  results = []

  # Loop over label rows
  for label_row in label_rows:
      row_data = {
          "label_row_hash": label_row.label_hash,
          "data_title": label_row.data_title,
          "objects": [],
          "classifications": [],
      }

      # Process object annotations
      object_instances = label_row.get_object_instances()
      assert object_instances, f"No object instances found in label row {label_row.uid}"

      for object_instance in object_instances:
          annotations = object_instance.get_annotations()
          assert annotations, f"No annotations found for object instance {object_instance.object_hash}"

          assert object_instance.ontology_item and object_instance.ontology_item.attributes, (
              f"No attributes found for object {object_instance.object_hash}"
          )

          for annotation in annotations:
              if START_FRAME_NUMBER <= annotation.frame <= END_FRAME_NUMBER:
                  obj_info = {
                      "frame": annotation.frame,
                      "object_hash": object_instance.object_hash,
                      "object_name": object_instance.object_name,
                      "feature_hash": object_instance.feature_hash,
                      "uid": str(object_instance.ontology_item.uid),
                      "color": object_instance.ontology_item.color,
                      "shape": object_instance.ontology_item.shape,
                      "label_location": str(annotation.coordinates),
                      "attributes": [],
                  }

                  print("Frame:", annotation.frame)
                  print("objectHash:", object_instance.object_hash)
                  print("Object name:", object_instance.object_name)
                  print("featureHash:", object_instance.feature_hash)
                  print("uid:", obj_info["uid"])
                  print("Object color:", object_instance.ontology_item.color)
                  print("Ontology shape:", object_instance.ontology_item.shape)
                  print(f"Label location: {annotation.coordinates}")

                  for attribute in object_instance.ontology_item.attributes:
                      attr_data = extract_attributes(attribute, object_instance)
                      obj_info["attributes"].append(attr_data)

                      print(f"Attribute name: {attr_data['attribute_name']}")
                      print(f"Attribute hash: {attr_data['attribute_hash']}")
                      print(f"Attribute answer: {attr_data['attribute_answer']}")

                  row_data["objects"].append(obj_info)

      # Process classification annotations
      classification_instances = label_row.get_classification_instances()
      assert classification_instances is not None, f"No classification instances found in label row {label_row.uid}"

      for classification_instance in classification_instances:
          annotations = classification_instance.get_annotations()
          assert annotations, (
              f"No annotations found for classification instance {classification_instance.classification_hash}"
          )

          for annotation in annotations:
              if START_FRAME_NUMBER <= annotation.frame <= END_FRAME_NUMBER:
                  try:
                      answer = classification_instance.get_answer()
                      answer_value = answer.value
                      answer_hash = answer.feature_node_hash
                  except Exception:
                      answer_value = None
                      answer_hash = None

                  classification_info = {
                      "frame": annotation.frame,
                      "classification_hash": classification_instance.classification_hash,
                      "classification_name": classification_instance.classification_name,
                      "feature_hash": classification_instance.feature_hash,
                      "value": answer_value,
                      "answer_hash": answer_hash,
                  }

                  print("Classification hash:", classification_info["classification_hash"])
                  print("Classification name:", classification_info["classification_name"])
                  print("Feature hash:", classification_info["feature_hash"])
                  print("Classification value:", classification_info["value"])
                  print("Classification answer hash:", classification_info["answer_hash"])

                  row_data["classifications"].append(classification_info)

      results.append(row_data)

  # Save to JSON
  assert OUTPUT_FILE_PATH.endswith(".json"), "Output file path must be a JSON file"

  with open(OUTPUT_FILE_PATH, "w") as f:
      json.dump(results, f, indent=4)

  print(f"\nData saved to: {OUTPUT_FILE_PATH}")

  ```

  ```python Frame range for all tasks expandable theme={"dark"}

  # Import dependencies
  import json
  from collections.abc import Iterable

  from encord import EncordUserClient
  from encord.objects import ObjectInstance
  from encord.objects.attributes import Attribute
  from encord.objects.ontology_element import OntologyElement

  # User input
  SSH_PATH = "/Users/chris-encord/ssh-private-key.txt"
  PROJECT_ID = "00000000-0000-0000-0000-000000000000"
  OUTPUT_FILE_PATH = "/Users/chris-encord/frame_range_output.json"
  START_FRAME_NUMBER = 0
  END_FRAME_NUMBER = 2
  BUNDLE_SIZE = 100

  # Create user client using access key
  user_client: EncordUserClient = EncordUserClient.create_with_ssh_private_key(
      ssh_private_key_path=SSH_PATH,
      # For US platform users use "https://api.us.encord.com"
      domain="https://api.encord.com",
  )

  # Load project
  project = user_client.get_project(PROJECT_ID)
  assert project is not None, f"Project with ID {PROJECT_ID} could not be loaded"

  # Retrieve all label rows
  label_rows = project.list_label_rows_v2()
  assert label_rows, "No label rows returned from the project"

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


  # Function to extract attribute info
  def extract_attributes(attribute: Attribute, object_instance: ObjectInstance):
      try:
          answer = object_instance.get_answer(attribute)
      except Exception:
          answer = None
      return {
          "attribute_name": attribute.title,
          "attribute_hash": attribute.feature_node_hash,
          "attribute_answer": str(answer),
      }


  # Store results here
  results = []

  # Iterate over label rows
  for label_row in label_rows:
      row_data = {
          "label_row_hash": label_row.label_hash,
          "data_title": label_row.data_title,
          "objects": [],
          "classifications": [],
      }

      # Process object annotations
      object_instances = label_row.get_object_instances()

      for object_instance in object_instances:
          annotations = object_instance.get_annotations()
          assert annotations, f"No annotations found for object instance {object_instance.object_hash}"

          ontology_item = object_instance.ontology_item
          assert ontology_item and ontology_item.attributes, (
              f"Ontology item or attributes missing for object {object_instance.object_hash}"
          )

          for annotation in annotations:
              if START_FRAME_NUMBER <= annotation.frame <= END_FRAME_NUMBER:
                  obj_info = {
                      "frame": annotation.frame,
                      "object_hash": object_instance.object_hash,
                      "object_name": object_instance.object_name,
                      "feature_hash": object_instance.feature_hash,
                      "uid": str(ontology_item.uid),
                      "color": ontology_item.color,
                      "shape": ontology_item.shape,
                      "label_location": str(annotation.coordinates),
                      "attributes": [],
                  }

                  print("Frame:", annotation.frame)
                  print("objectHash:", object_instance.object_hash)
                  print("Object name:", object_instance.object_name)
                  print("featureHash:", object_instance.feature_hash)
                  print("uid:", obj_info["uid"])
                  print("Object color:", obj_info["color"])
                  print("Ontology shape:", obj_info["shape"])
                  print(f"Label location: {annotation.coordinates}")

                  for attribute in ontology_item.attributes:
                      attr_data = extract_attributes(attribute, object_instance)
                      obj_info["attributes"].append(attr_data)

                      print(f"Attribute name: {attr_data['attribute_name']}")
                      print(f"Attribute hash: {attr_data['attribute_hash']}")
                      print(f"Attribute answer: {attr_data['attribute_answer']}")

                  row_data["objects"].append(obj_info)

      # Process classification annotations
      classification_instances = label_row.get_classification_instances()
      assert classification_instances is not None, f"No classification instances found in label row {label_row.uid}"

      for classification_instance in classification_instances:
          annotations = classification_instance.get_annotations()
          assert annotations, (
              f"No annotations found for classification instance {classification_instance.classification_hash}"
          )

          for annotation in annotations:
              if START_FRAME_NUMBER <= annotation.frame <= END_FRAME_NUMBER:
                  try:
                      answer = classification_instance.get_answer()
                      value = answer.value
                      answer_hash = answer.feature_node_hash
                  except Exception:
                      value = None
                      answer_hash = None

                  classification_info = {
                      "frame": annotation.frame,
                      "classification_hash": classification_instance.classification_hash,
                      "classification_name": classification_instance.classification_name,
                      "feature_hash": classification_instance.feature_hash,
                      "value": value,
                      "answer_hash": answer_hash,
                  }

                  print("Classification hash:", classification_info["classification_hash"])
                  print("Classification name:", classification_info["classification_name"])
                  print("Feature hash:", classification_info["feature_hash"])
                  print("Classification value:", classification_info["value"])
                  print("Classification answer hash:", classification_info["answer_hash"])

                  row_data["classifications"].append(classification_info)

      results.append(row_data)

  # Save everything to JSON
  assert OUTPUT_FILE_PATH.endswith(".json"), "Output file path must end with .json"

  with open(OUTPUT_FILE_PATH, "w") as f:
      json.dump(results, f, indent=4)

  print(f"\nAnnotation data saved to: {OUTPUT_FILE_PATH}")

  ```

  ```Example Output theme={"dark"}
  Frame: 0
  objectHash: U88+HXj4
  Object name: Person
  featureHash: AaaPMAgE
  uid: 1
  Object color: #15d3bc
  Ontology shape: bounding_box
  Label location: BoundingBoxCoordinates(height=0.519561557605036, width=0.15380023056653513, top_left_x=0.43242033102766797, top_left_y=0.0028114478114478862)
  Attribute name: Man or woman
  Attribute hash: X0Xhz9ip
  Attribute answer: NestableOption(feature_node_hash='MN57hMep', uid=[1, 1, 1], label='Man', value='Man', nested_options=[])
  Frame: 44
  objectHash: nZWuD66O
  Object name: Person
  featureHash: AaaPMAgE
  uid: 1
  Object color: #15d3bc
  Ontology shape: bounding_box
  Label location: BoundingBoxCoordinates(height=0.46671424388815697, width=0.1688282279314888, top_left_x=0.37747550230566534, top_left_y=0.07887095593617346)
  Attribute name: Man or woman
  Attribute hash: X0Xhz9ip
  Attribute answer: None
  Classification hash: biZZZov4
  Classification name: Day or Night?
  Feature hash: T+P+wwjw
  Classification value: Day
  Classification answer hash: t+QtqkFp
  ```
</CodeGroup>

### List of non-consecutive frames

The following scripts download and print the labels for specific frames in videos.

Make sure you substitute:

* The \<private\_key\_path> with the full path to your private key.
* The \<project\_hash> with the hash of your Project.
* The \<task\_name> with the name of the file (in Encord) you want to export labels for (if using the task-specific script).
* Replace the numbers in the list `[10, 20, 30, 40]` with the frames you want to export labels for.

<CodeGroup>
  ```python For a specific task theme={"dark"}
  # Import dependencies
  from encord import EncordUserClient
  from encord.objects.ontology_element import OntologyElement
  from encord.objects.attributes import Attribute, Option
  from encord.objects import ObjectInstance
  from collections.abc import Iterable

  # Instantiate Encord client
  user_client = EncordUserClient.create_with_ssh_private_key(
      ssh_private_key_path="<private_key_path>"
  )

  # Replace with the hash of your Project
  project = user_client.get_project("<project_hash>")

  # Function to extract and print essential information for all attributes
  def print_attributes(attribute: Attribute, object_instance: ObjectInstance):
      print(f"Attribute name: {attribute.title}")
      print(f"Attribute hash: {attribute.feature_node_hash}")
      print(f"Attribute answer: {object_instance.get_answer(attribute)}")

  # List of specific frames to be exported
  specific_frames = [10, 20, 30, 40]  # Replace with your specific frame numbers

  # Initialize label rows using bundles
  label_rows = project.list_label_rows_v2()
  with project.create_bundle() as bundle:
      for label_row in label_rows:
          label_row.initialise_labels(bundle=bundle)

  for label_row in label_rows:
      # Print essential label information for all objects
      for object_instance in label_row.get_object_instances():
          for annotation in object_instance.get_annotations():
              if annotation.frame in specific_frames:
                  print("Frame: " + str(annotation.frame))
                  print("objectHash: " + object_instance.object_hash)
                  print("Object name: " + object_instance.object_name)
                  print("featureHash: " + object_instance.feature_hash)
                  print("uid: " + str(object_instance.ontology_item.uid))
                  print("Object color: " + object_instance.ontology_item.color)
                  print("Ontology shape: " + object_instance.ontology_item.shape)
                  print(f"Label location: {annotation.coordinates}")

                  # Print all attributes
                  for attribute in object_instance.ontology_item.attributes:
                      print_attributes(attribute, object_instance)

      # Print essential classification information on specified frames
      for classification_instance in label_row.get_classification_instances():
          for annotation in classification_instance.get_annotations():
              if annotation.frame in specific_frames:
                  print("Classification hash: " + classification_instance.classification_hash)
                  print("Classification name: " + classification_instance.classification_name)
                  print("Feature hash: " + classification_instance.feature_hash)
                  print("Classification value: " + classification_instance.get_answer().value)
                  print("Classification answer hash: " + classification_instance.get_answer().feature_node_hash)

  ```

  ```python For all tasks theme={"dark"}
  # Import dependencies
  from encord import EncordUserClient
  from encord.objects.ontology_element import OntologyElement
  from encord.objects.attributes import Attribute, Option
  from encord.objects import ObjectInstance
  from collections.abc import Iterable

  # Instantiate Encord client
  user_client = EncordUserClient.create_with_ssh_private_key(
      ssh_private_key_path="<private_key_path>"
  )

  # Replace with the hash of your Project
  project = user_client.get_project("<project_hash>")

  # Function to extract and print essential information for all attributes
  def print_attributes(attribute: Attribute, object_instance: ObjectInstance):
      print(f"Attribute name: {attribute.title}")
      print(f"Attribute hash: {attribute.feature_node_hash}")
      print(f"Attribute answer: {object_instance.get_answer(attribute)}")

  # List of specific frames
  specific_frames = [10, 20, 30, 40]  # Replace with your specific frame numbers

  # Initialize label rows using bundles
  label_rows = project.list_label_rows_v2()
  with project.create_bundle() as bundle:
      for label_row in label_rows:
          label_row.initialise_labels(bundle=bundle)

  for label_row in label_rows:
      # Print essential label information for all objects
      for object_instance in label_row.get_object_instances():
          for annotation in object_instance.get_annotations():
              if annotation.frame in specific_frames:
                  print("Frame: " + str(annotation.frame))
                  print("objectHash: " + object_instance.object_hash)
                  print("Object name: " + object_instance.object_name)
                  print("featureHash: " + object_instance.feature_hash)
                  print("uid: " + str(object_instance.ontology_item.uid))
                  print("Object color: " + object_instance.ontology_item.color)
                  print("Ontology shape: " + object_instance.ontology_item.shape)
                  print(f"Label location: {annotation.coordinates}")

                  # Print all attributes
                  for attribute in object_instance.ontology_item.attributes:
                      print_attributes(attribute, object_instance)

      # Print essential classification information on specified frames
      for classification_instance in label_row.get_classification_instances():
          for annotation in classification_instance.get_annotations():
              if annotation.frame in specific_frames:
                  print("Classification hash: " + classification_instance.classification_hash)
                  print("Classification name: " + classification_instance.classification_name)
                  print("Feature hash: " + classification_instance.feature_hash)
                  print("Classification value: " + classification_instance.get_answer().value)
                  print("Classification answer hash: " + classification_instance.get_answer().feature_node_hash)
  ```

  ```python Example Output theme={"dark"}
  Frame: 10
  objectHash: U88+HXj4
  Object name: Person
  featureHash: AaaPMAgE
  uid: 1
  Object color: #15d3bc
  Ontology shape: bounding_box
  Label location: BoundingBoxCoordinates(height=0.519561557605036, width=0.15380023056653513, top_left_x=0.43242033102766797, top_left_y=0.0028114478114478862)
  Attribute name: Man or woman
  Attribute hash: X0Xhz9ip
  Attribute answer: NestableOption(feature_node_hash='MN57hMep', uid=[1, 1, 1], label='Man', value='Man', nested_options=[])
  Frame: 20
  objectHash: nZWuD66O
  Object name: Person
  featureHash: AaaPMAgE
  uid: 1
  Object color: #15d3bc
  Ontology shape: bounding_box
  Label location: BoundingBoxCoordinates(height=0.46671424388815697, width=0.1688282279314888, top_left_x=0.37747550230566534, top_left_y=0.07887095593617346)
  Attribute name: Man or woman
  Attribute hash: X0Xhz9ip
  Attribute answer: None
  Classification hash: biZZZov4
  Classification name: Day or Night?
  Feature hash: T+P+wwjw
  Classification value: Day
  Classification answer hash: t+QtqkFp
  ```
</CodeGroup>

## Saving Frames with Labels

`ffmpeg` can be used to save all frames with labels as an image, to be used in machine learning applications. The script below shows how this is done when exporting a list of non-consecutive frames from a specific video.

<Note>
  [ffmpeg](https://ffmpeg.org/) must be installed for this script to work.
</Note>

Make sure you substitute:

* The `<output_folder_path>` with the full path to the output folder you want the output image files to be saved.
* The `<private_key_path>` with the full path to your private key.
* The `<project_id>` with the ID of your Project.
* The `<task_name>` with the name of the file in Encord you want to export labels for.
* The `<path_to_your_video_file>` with the full path to the video file you are exporting labels for.
* The `def get_video_path` function to return your actual video path corresponding to the label row.
* Replace the numbers in the list `[10, 20, 30, 40]` with the frames you want to export labels for.

<CodeGroup>
  ```python theme={"dark"}
  # Import dependencies
  from encord import EncordUserClient
  from encord.objects.ontology_element import OntologyElement
  from encord.objects.attributes import Attribute, Option
  from encord.objects import ObjectInstance
  from collections.abc import Iterable
  import subprocess
  import os

  # Specify the output folder path. Replace with your desired folder path
  output_folder = "<output_folder_path>"

  # Create the output folder if it doesn't exist
  if not os.path.exists(output_folder):
      os.makedirs(output_folder)

  def extract_frame_to_image(video_file, frame_number, output_file):
      """
      Uses FFmpeg to extract a specific frame from a video and saves it as an image.
      """
      ffmpeg_command = [
          'ffmpeg', '-i', video_file, '-vf', f'select=eq(n\,{frame_number})',
          '-vframes', '1', output_file
      ]
      subprocess.run(ffmpeg_command, check=True)

  # Instantiate Encord client
  user_client = EncordUserClient.create_with_ssh_private_key(
      ssh_private_key_path="<private_key_path>"
  )

  # Replace with the ID of your Project
  project = user_client.get_project("<project_id>")

  # Function to extract and print essential information for all attributes
  def print_attributes(attribute: Attribute, object_instance: ObjectInstance):
      print(f"Attribute name: {attribute.title}")
      print(f"Attribute hash: {attribute.feature_node_hash}")
      print(f"Attribute answer: {object_instance.get_answer(attribute)}")

  # List of specific frames to be exported. Replace with your specific frame numbers
  specific_frames = [10, 20, 30, 40]

  # Path to the video file you are exporting labels for
  def get_video_path(label_row)
      return "<path_to_your_video_file>"

  # Initialize label rows using bundles
  label_rows = project.list_label_rows_v2()
  with project.create_bundle() as bundle:
      for label_row in label_rows:
          label_row.initialise_labels(bundle=bundle)

  for label_row in label_rows:
      # Print essential label information for all objects
      video_path = get_video_path(label_row)
      for object_instance in label_row.get_object_instances():
          for annotation in object_instance.get_annotations():
              if annotation.frame in specific_frames:
                  print("Frame: " + str(annotation.frame))
                  print("objectHash: " + object_instance.object_hash)
                  print("Object name: " + object_instance.object_name)
                  print("featureHash: " + object_instance.feature_hash)
                  print("uid: " + str(object_instance.ontology_item.uid))
                  print("Object color: " + object_instance.ontology_item.color)
                  print("Ontology shape: " + object_instance.ontology_item.shape)
                  print(f"Label location: {annotation.coordinates}")

                  # Define the output path for the image
                  output_image_path = os.path.join(output_folder, f"frame_{annotation.frame}.png")

                  # Extract and save the specific frame as an image
                  extract_frame_to_image(video_path, annotation.frame, output_image_path)

                  # Print all attributes
                  for attribute in object_instance.ontology_item.attributes:
                      print_attributes(attribute, object_instance)

      # Print essential classification information on specified frames
      for classification_instance in label_row.get_classification_instances():
          for annotation in classification_instance.get_annotations():
              if annotation.frame in specific_frames:
                  print("Classification hash: " + classification_instance.classification_hash)
                  print("Classification name: " + classification_instance.classification_name)
                  print("Feature hash: " + classification_instance.feature_hash)
                  print("Classification value: " + classification_instance.get_answer().value)
                  print("Classification answer hash: " + classification_instance.get_answer().feature_node_hash)
  ```
</CodeGroup>

## Label Editor Coordinates

All label locations are exported as normalized coordinates ranging from 0 to 1. This means that the corners of the frame or image correspond to the coordinates (1,1), (1,0), (0,0), (0,1) regardless of frame dimensions.

To get the pixel values of any normalized coordinates, multiply them by the width or height of the label (given in pixels).

<div class="flex justify-center">
  <img src="https://storage.googleapis.com/docs-media.encord.com/static/img/real-pixel-value-formula.png" />
</div>

* "x" and "h" coordinates of a label should be multiplied by the pixel width.
* "y" and "w" coordinates of a label should be multiplied by the pixel height.

## Export Labels from Specific Workflow Stages

<CodeGroup>
  ```python Export from specific stage expandable theme={"dark"}
  from encord import EncordUserClient

  # User input

  SSH_PATH = "/Users/chris-encord/ssh-private-key.txt" # Replace with file path to your SSH private key
  PROJECT_ID = "00000000-0000-0000-0000-000000000000" # Replace with the unique Project ID
  WORKFLOW_STAGE = "Annotation" # Replace with the name of the Workflow stage

  # Authentic
  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 = user_client.get_project(PROJECT_ID)

  # Fetch label rows in Annotation stage
  label_rows = project.list_label_rows_v2(
      workflow_graph_node_title_eq=WORKFLOW_STAGE
  )

  # Initialise labels
  with project.create_bundle() as bundle:
      for label_row in label_rows:
          label_row.initialise_labels(bundle=bundle)

  # Export rows
  for label_row in label_rows:
      print(label_row.data_title)
      print(label_row.to_encord_dict())
  ```

  ```python Export from any Review stage expandable theme={"dark"}
  from encord import EncordUserClient

  SSH_PATH = "/Users/chris-encord/ssh-private-key.txt" # Replace with file path to your SSH private key
  PROJECT_ID = "00000000-0000-0000-0000-000000000000" # Replace with the unique Project ID
  WORKFLOW_STAGE = "Review%" # Replace with the name of the Workflow stage


  # Authenticate
  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 = user_client.get_project(PROJECT_ID)

  # Fetch rows matching Review*
  label_rows = project.list_label_rows_v2(
      workflow_graph_node_title_like=WORKFLOW_STAGE
  )

  # Initialise labels
  with project.create_bundle() as bundle:
      for label_row in label_rows:
          label_row.initialise_labels(bundle=bundle)

  # Export rows
  for label_row in label_rows:
      stage = label_row.workflow_graph_node.title
      print(f"{label_row.data_title} is in stage: {stage}")
      print(label_row.to_encord_dict())
  ```

  ```python Export all labels expandable theme={"dark"}

  from encord import EncordUserClient

  SSH_PATH = "/Users/chris-encord/ssh-private-key.txt" # Replace with file path to your SSH private key
  PROJECT_ID = "00000000-0000-0000-0000-000000000000" # Replace with the unique Project ID
  WORKFLOW_STAGE = "Review%" # Replace with the name of the Workflow stage


  # Authenticate
  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 = user_client.get_project(PROJECT_ID)

  # Fetch all label rows
  label_rows = project.list_label_rows_v2()

  # Initialise labels
  with project.create_bundle() as bundle:
      for label_row in label_rows:
          label_row.initialise_labels(bundle=bundle)

  # Process depending on stage
  for label_row in label_rows:
      stage = label_row.workflow_graph_node.title if label_row.workflow_graph_node else None

      print(f"{label_row.data_title} is in stage: {stage}")

      if stage == "Annotation":
          print("Processing annotation row")
          print(label_row.to_encord_dict())

      elif stage == "Review":
          print("Processing review row")
          print(label_row.to_encord_dict())

  ```
</CodeGroup>

## Export all Consensus labels

[Consensus Projects](/platform-documentation/Annotate/annotate-projects/annotate-workflows-consensus) introduce the concept of BRANCHES within the task workflow. A Consensus annotation task consists of a MAIN branch and one sub-branch for each Annotator. Each time an annotator saves or submits a task, the annotator creates their own branch on a task. The MAIN branch remains empty of labels until a reviewer specifies that a task is in consensus. When consensus is reached, the labels that are the best representative set move to the MAIN branch. To export all labels (labels generated for every branch on every data unit) from your Consensus Project, use `include_all_branches=True`.

Make sure you:

* Substitute the `<private_key_path>` with the full path to your private key.
* Substitute the `<project_id>` with the ID of your Project.
* If you only want to export the MAIN branch, remove `include_all_label_branches=True`.

<Note>
  - Adding `include_all_label_branches=True` to `list_label_rows_v2()` includes all labels from all branches in Consensus Projects.
</Note>

<Warning>
  DEPRECATED @v186: For Data Groups, adding `include_children=True` to `list_label_rows_v2()` includes all labels from Data Groups.
</Warning>

<CodeGroup>
  ```python All labels all branches expandable theme={"dark"}

  import json

  from encord import EncordUserClient

  # User input
  SSH_PATH = "/Users/chris-encord/ssh-private-key.txt"
  PROJECT_ID = "00000000-0000-0000-0000-000000000000"
  OUTPUT_FILE_PATH = "/Users/chris-encord/frame_range_output.json"
  BUNDLE_SIZE = 100

  # Create user client using access key
  user_client: EncordUserClient = EncordUserClient.create_with_ssh_private_key(
      ssh_private_key_path=SSH_PATH,
      # For US platform users use "https://api.us.encord.com"
      domain="https://api.encord.com",
  )

  # Specify Project. Replace <project_id> with the ID of the Project you want to export labels for.
  project = user_client.get_project(PROJECT_ID)

  # Downloads a local copy of all the labels
  # Without the include_all_label_branches flag only the MAIN branch labels export
  label_rows = project.list_label_rows_v2(include_children=True, include_all_label_branches=True)

  output_data = []  # This will hold the output data to be saved as JSON

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

  # Collecting data for JSON output
  for label_row in label_rows:
      label_row_data = {
          "title": label_row.data_title,
          "branch": label_row.branch_name,
          "objects": [],
          "classifications": [],
      }

      # Collect object instances
      for object_instance in label_row.get_object_instances():
          object_data = {
              "object_hash": object_instance.object_hash,
              "object_name": object_instance.object_name,
              "feature_hash": object_instance.feature_hash,
              "ontology_item": {
                  "uid": object_instance.ontology_item.uid,
                  "color": object_instance.ontology_item.color,
                  "shape": object_instance.ontology_item.shape,
                  "attributes": [
                      {"name": attribute.name, "value": attribute.value}
                      for attribute in object_instance.ontology_item.attributes
                  ],
              },
              "annotations": [
                  {"frame": annotation.frame, "coordinates": annotation.coordinates}
                  for annotation in object_instance.get_annotations()
              ],
          }
          label_row_data["objects"].append(object_data)

      # Collect classification instances
      for classification_instance in label_row.get_classification_instances():
          classification_data = {
              "classification_hash": classification_instance.classification_hash,
              "classification_name": classification_instance.classification_name,
              "feature_hash": classification_instance.feature_hash,
              "classification_answer": {
                  "value": classification_instance.get_answer().value,
                  "hash": classification_instance.get_answer().feature_node_hash,
              },
              "annotations": [{"frame": annotation.frame} for annotation in classification_instance.get_annotations()],
          }
          label_row_data["classifications"].append(classification_data)

      # Add label row data to the output list
      output_data.append(label_row_data)

  # Saving to JSON file
  output_file_path = OUTPUT_FILE_PATH  # Replace with the desired file path
  with open(output_file_path, "w") as json_file:
      json.dump(output_data, json_file, indent=4)

  print(f"Output saved to {output_file_path}")

  ```
</CodeGroup>

***

## Export all Data Group labels

<Note>
  * Adding `include_all_label_branches=True` to `list_label_rows_v2()` includes all labels from all branches in Consensus Projects.
</Note>

<Warning>
  DEPRECATED @v186: Adding `include_children=True` to `list_label_rows_v2()` includes all labels from Data Groups.
</Warning>

<CodeGroup>
  ```python Export labels to JSON expandable theme={"dark"}

  # Import dependencies
  import json
  import os

  from encord import EncordUserClient

  SSH_PATH = "/Users/chris-encord/ssh-private-key.txt" # Replace with file path to your SSH private key
  PROJECT_ID = "00000000-0000-0000-0000-000000000000" # Replace with Project unique ID
  BUNDLE_SIZE = 100  # Customize as needed
  OUTPUT_JSON = "/Users/chris-encord/export-label-rows.json" # Replace with file path to save JSON output file

  # Create user client using access key
  user_client: EncordUserClient = EncordUserClient.create_with_ssh_private_key(
      ssh_private_key_path=SSH_PATH,
      # For US platform users use "https://api.us.encord.com"
      domain="https://api.encord.com",
  )

  # Specify Project
  project = user_client.get_project(PROJECT_ID)
  assert project is not None, f"Project with ID {PROJECT_ID} could not be loaded"

  # Get label rows for your Project
  label_rows = project.list_label_rows_v2()
  assert label_rows, f"No label rows found in project {PROJECT_ID}"

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

  # Collect all label row data
  all_label_rows = [label_row.to_encord_dict() for label_row in label_rows]
  assert all_label_rows, "No label row data collected for export"

  # Save the collected label rows data to a JSON file
  output_file = OUTPUT_JSON
  assert output_file.endswith(".json"), "Output file must be a .json file"

  with open(output_file, "w") as file:
      json.dump(all_label_rows, file, indent=4)

  print(f"Label rows have been saved to {output_file}.")
  ```

  ```python DEPRECATED: Export labels to JSON expandable theme={"dark"}

  # Import dependencies
  import json
  import os

  from encord import EncordUserClient

  SSH_PATH = "/Users/chris-encord/ssh-private-key.txt" # Replace with file path to your SSH private key
  PROJECT_ID = "00000000-0000-0000-0000-000000000000" # Replace with Project unique ID
  BUNDLE_SIZE = 100  # Customize as needed
  OUTPUT_JSON = "/Users/chris-encord/export-label-rows.json" # Replace with file path to save JSON output file

  # Create user client using access key
  user_client: EncordUserClient = EncordUserClient.create_with_ssh_private_key(
      ssh_private_key_path=SSH_PATH,
      # For US platform users use "https://api.us.encord.com"
      domain="https://api.encord.com",
  )

  # Specify Project
  project = user_client.get_project(PROJECT_ID)
  assert project is not None, f"Project with ID {PROJECT_ID} could not be loaded"

  # Get label rows for your Project
  label_rows = project.list_label_rows_v2(include_children=True)
  assert label_rows, f"No label rows found in project {PROJECT_ID}"

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

  # Collect all label row data
  all_label_rows = [label_row.to_encord_dict() for label_row in label_rows]
  assert all_label_rows, "No label row data collected for export"

  # Save the collected label rows data to a JSON file
  output_file = OUTPUT_JSON
  assert output_file.endswith(".json"), "Output file must be a .json file"

  with open(output_file, "w") as file:
      json.dump(all_label_rows, file, indent=4)

  print(f"Label rows have been saved to {output_file}.")

  ```
</CodeGroup>

***

## Export Bitmasks

The following code example illustrates how to download / export and save Bitmask labels:

```python theme={"dark"}
import cv2
import numpy as np
from encord import EncordUserClient

# Instantiate Encord client by substituting the path to your private key
user_client = EncordUserClient.create_with_ssh_private_key(
    ssh_private_key_path="<private_key_path>"
)

# Specify a project using project hash
project = user_client.get_project("<project_hash>")

# Obtain labels for the media of interest
label_row = project.list_label_rows_v2()[0]
label_row.initialise_labels()

# Find annotation
# In this example, it is just a first object on a first frame
object_with_bitmask_annotation = label_row.get_frame_views()[
    0
].get_object_instances()[0]

# Get a bitmask annotation
# In this example, it is a first annotation on the object
bitmask_annotation = object_with_bitmask_annotation.get_annotations()[0]

# Convert bitmask to a numpy array
# Obtained array is a binary mask, so to work with it as an image,
# it is necessary to convert it to a different datatype and scale
bitmask = bitmask_annotation.coordinates.to_numpy_array().astype(np.uint8)

bitmask[bitmask == 1] = 255

# And now we can save the mask as a grayscale image
cv2.imwrite("./mask_as_an_image.png", bitmask)
```

## Decode Bitmask Labels

Bitmask labels exported from Encord as JSON or COCO are encoded as an `rleString`. This `rleString` can be converted to an image or a binary array.

<Info>
  Use the [COCO API](https://github.com/cocodataset/cocoapi) to decode Bitmasks when using the COCO export format.
</Info>

<AccordionGroup>
  <Accordion title="Create Bitmask Image">
    <CodeGroup>
      ```python JSON Format theme={"dark"}
      # Import dependencies
      import json
      from pathlib import Path
      import numpy as np
      from encord.objects.coordinates import BitmaskCoordinates
      from PIL import Image

      # Read the JSON file.
      # Replace labels.json with the path to the JSON file containing your Bitmask
      labels = json.loads(Path("labels.json").read_text())
      output_folder = Path("output")
      output_folder.mkdir(parents=True, exist_ok=True)

      # Finds the rleString and saves it to a .png image
      found_any = False
      for label_row in labels:
          for du in label_row["data_units"].values():
              slice_nums = list(du["labels"].keys())
              for slice_num in slice_nums:
                  for obj in du["labels"][slice_num]["objects"]:
                      bmc = BitmaskCoordinates.from_dict(obj)
                      nparr = np.array(bmc)
                      img = Image.fromarray(nparr)
                      # img.show()
                      # Replace example.png with the name of the output file
                      img.save(output_folder / f"mask_{int(slice_num):05d}_{obj['objectHash']}.png")
      print("Decoding complete.")
      ```

      ```python COCO Format theme={"dark"}
      from pycocotools.coco import COCO
      import numpy as np
      from pycocotools import mask as maskUtils
      from PIL import Image
      import json


      # Read the COCO file. Replace 'labels.json' with the path to your COCO format annotations file
      coco_annotations_path = 'labels.json'
      coco = COCO(coco_annotations_path)

      # Get all annotation IDs (you might want to filter or select specific ones)
      annIds = coco.getAnnIds()
      anns = coco.loadAnns(annIds)

      # Decode each rleString and save as a .png image
      for i, ann in enumerate(anns):
          if 'segmentation' in ann and isinstance(ann['segmentation'], dict):

              rle = ann['segmentation']
              
              mask = maskUtils.decode(rle)

              img = Image.fromarray(mask * 255).convert('L')  # Convert to grayscale

      # Replace example.png with the name of the output file
              img.save("example.png")

      print("Decoding complete.")
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Create Binary Array">
    The `rleString`can be converted into an array of 1's and 0's using the script below.

    ```python theme={"dark"}
    from encord.objects.coordinates import BitmaskCoordinates

    # Create a numpy array
    np_mask = BitmaskCoordinates.from_dict(obj).to_numpy_array() 
    print(np_mask.astype(int))

    ```
  </Accordion>
</AccordionGroup>

***

## Bulk Export Labels

Use the [bundle](/sdk-documentation/sdk-references/http.bundle#bundle) function to significantly improve export performance.

<Info>
  We strongly recommend NOT bundling more than 1000 operations at once, because
  bundling more than 1000 operations can reduce performance instead of improving
  performance.
</Info>

<Warning>
  In the following code, ensure you replace:

  * `<private_key_path>` with the full path to your private key.
  * `<project-id>` with the ID of the Project you want to export labels for.
  * `#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.
</Warning>

<CodeGroup>
  ```python theme={"dark"}

  # 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_ID = "<project-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_ID)

  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)

  ```
</CodeGroup>

## COCO Format Export

Use the following script to bulk export labels in the COCO format.

Ensure that you replace:

* `<private-key-path>` with the full path to your private key for authentication.
* `<project-id>` with the ID of the Project for which you want to export labels.

```python COCO Export theme={"dark"}
from encord import EncordUserClient
import json


SSH_PATH = "/Users/chris-encord/ssh-private-key.txt" # Replace with the access key
PROJECT_ID = "00000000-0000-0000-0000-000000000000" # Replace with the unique ID for the Project

# Create user client using access key
user_client: EncordUserClient = EncordUserClient.create_with_ssh_private_key(
    ssh_private_key_path=SSH_PATH,
    # For US platform users use "https://api.us.encord.com"
    domain="https://api.encord.com",
)

project = user_client.get_project(PROJECT_ID)
coco_labels = project.export_coco_labels()

# Save the coco_labels dictionary to a .json file
with open("coco_labels.json", "w") as json_file:
    json.dump(coco_labels, json_file)

```
