A Bitmask is a type of annotation on the Encord platform that allows for pixel-wise segmentation of an image, which can be useful when bounding boxes and polygons don’t provide enough precision, or when topologically separate regions belonging to the same class need to be labeled.
1. Downloading bitmask annotations from Encord#
The Encord UI allows the creation of Bitmask annotations. After labelling is complete, it is possible to download these annotations using the SDK. The following code example illustrates how to download and save bitmask labels:
import cv2 import numpy as np from encord import EncordUserClient # 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 label_row = project.list_label_rows_v2() 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() # Get a bitmask annotation # In this example, it is a first annotation on the object bitmask_annotation = object_with_bitmask_annotation.get_annotations() # 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)
2. Uploading bitmask annotations to Encord#
If there are pre-existing bitmask annotations, previously created in Encord or any other software, they can be uploaded to Encord using the SDK. The following code example illustrates how to read a bitmask from a file, and upload it:
import numpy as np from encord import EncordUserClient from encord.objects import Object, OntologyStructure from encord.objects.coordinates import BitmaskCoordinates # Firstly, we need to prepare the mask itself. # For simplicity, we can just mask the whole image # Note, that the size of the mask must be identical to the size of the image numpy_coordinates = np.ones((512, 512)) # we also need to 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() 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()