In this tutorial we will focus on working with images using Supervisely SDK.
You will learn how to:
- upload images from local directory to Supervisely dataset.
- upload images to Supervisely as NumPy matrix.
- get information about images by id or name.
- download images from Supervisely to local directory.
- download images from Supervisely as NumPy matrix.
- get and update image metadata
- remove images from Supervisely.
- custom image sorting for Image Labeling Toolbox
đź“— Everything you need to reproduce this tutorial is on GitHub: source code and demo data.
Step 1. Prepare ~/supervisely.env
file with credentials. Learn more here.
Step 2. Clone repository with source code and demo data and create Virtual Environment.
git clone https://github.com/supervisely-ecosystem/tutorial-image.git
cd tutorial-image
./create_venv.sh
Step 3. Open repository directory in Visual Studio Code.
code -r .
Step 4. Change workspace ID in local.env
file by copying the ID from the context menu of the workspace.
WORKSPACE_ID=654 # ⬅️ change value
Step 5. Start debugging src/main.py
.
import os
from dotenv import load_dotenv
import supervisely as sly
First, we load environment variables with credentials and init API for communicating with Supervisely Instance.
if sly.is_development():
load_dotenv("local.env")
load_dotenv(os.path.expanduser("~/supervisely.env"))
api = sly.Api()
In this tutorial, you will need an workspace ID that you can get from environment variables. Learn more here
workspace_id = sly.env.workspace_id()
Create new project.
Source code:
project = api.project.create(workspace_id, "Fruits", change_name_if_conflict=True)
print(f"Project ID: {project.id}")
Output:
# Project ID: 15599
Create new dataset.
Source code:
dataset = api.dataset.create(project.id, "Fruits ds1")
print(f"Dataset ID: {dataset.id}")
Output:
# Dataset ID: 53465
Source code:
original_dir = "src/images/original"
path = os.path.join(original_dir, "lemons.jpg")
meta = {"my-field-1": "my-value-1", "my-field-2": "my-value-2"}
image = api.image.upload_path(
dataset.id,
name="Lemons",
path=path,
meta=meta # optional
)
print(f'Image "{image.name}" uploaded to Supervisely with ID:{image.id}')
Output:
# Image "Lemons.jpeg" uploaded to Supervisely platform with ID:17539453
âś… Supervisely API allows uploading multiple images in a single request. The code sample below sends fewer requests and it leads to a significant speed-up of our original code.
Source code:
names = [
"grapes-1.jpg",
"grapes-2.jpg",
"oranges-2.jpg",
"oranges-1.jpg",
]
paths = [os.path.join(original_dir, name) for name in names]
upload_info = api.image.upload_paths(dataset.id, names, paths)
print(f"{len(upload_info)} images successfully uploaded to Supervisely platform")
Output:
# 4 images successfully uploaded to Supervisely platform
Source code:
img_np = sly.image.read(path)
np_image_info = api.image.upload_np(dataset.id, name="Lemons-np.jpeg", img=img_np)
print(f"Image successfully uploaded as NumPy matrix to Supervisely (ID: {np_image_info.id})")
Output:
# Image successfully uploaded as NumPy matrix to Supervisely (ID: 17539458)
Source code:
names_np = [f"np-{name}" for name in names]
images_np = [sly.image.read(img_path) for img_path in paths]
np_images_info = api.image.upload_nps(dataset.id, names_np, images_np)
print(f"{len(images_np)} images successfully uploaded to platform as NumPy matrix")
Output:
# 4 images successfully uploaded to platform as NumPy matrix
Get information about image from Supervisely by id.
Source code:
image_info = api.image.get_info_by_id(image.id)
print(image_info)
Output:
# ImageInfo(
# id=17539453,
# name='Lemons.jpeg',
# link=None,
# hash='0jirgXvKGTJ8Yi0I9nCdf9MllQ9jP3Les1fD7/dt+Zk=',
# mime='image/jpeg',
# ext='jpeg',
# size=66066,
# width=640,
# height=427,
# labels_count=0,
# dataset_id=54008,
# created_at='2022-12-23T15:57:35.707Z',
# updated_at='2022-12-23T15:57:35.707Z',
# meta={},
# path_original='nAXBxaxQJRARr0Ljkj6FfREj1Fq89.jpg',
# full_storage_url='https://dev.supervisely.com/h5unublic/images/original/3/e/OK/d8Y7NnEj1Fq89.jpg',
# tags=[]
# )
You can also get information about image from Supervisely by name.
Source code:
image_name = get_file_name(image.name)
image_info_by_name = api.image.get_info_by_name(dataset.id, image_name)
print(f"image name - {image_info_by_name.name}")
Output:
# image name - Lemons.jpeg
Get information about image from Supervisely by id.
Source code:
image_info_list = api.image.get_list(dataset.id)
print(f"{len(image_info_list)} images information received.")
Output:
# 10 images information received.
Download image from Supervisely to local directory by id.
Source code:
save_path = os.path.join(result_dir, image_info.name)
api.image.download_path(image_info.id, save_path)
print(f"Image has been successfully downloaded to '{save_path}'")
Output:
# Image has been successfully downloaded to 'src/images/result/Lemons.jpeg'
Download list of images from Supervisely to local directory by ids.
Source code:
image_ids = [img.id for img in image_info_list]
image_names = [img.name for img in image_info_list]
save_paths = [os.path.join(result_dir, img_name) for img_name in image_names]
api.image.download_paths(dataset.id, image_ids, save_paths)
print(f"{len(image_info_list)} images has been successfully downloaded.")
Output:
# 10 images has been successfully downloaded.
Download image from Supervisely to local directory by id.
Source code:
image_np = api.image.download_np(image_info.id)
print(f"Image downloaded as RGB NumPy matrix. Image shape: {image_np.shape}")
Output:
# Image downloaded as RGB NumPy matrix. Image shape: (427, 640, 3)
Download list of images from Supervisely to local directory by ids.
Source code:
image_np = api.image.download_nps(dataset.id, image_ids)
print(f"{len(image_np)} images downloaded in RGB NumPy matrix.")
Output:
# 10 images downloaded in RGB NumPy matrix.
Source code:
image_info = api.image.get_info_by_id(image.id)
meta = image_info.meta
print(meta)
Output:
# {'my-field-1': 'my-value-1', 'my-field-2': 'my-value-2'}
Source code:
new_meta = {"my-field-3": "my-value-3", "my-field-4": "my-value-4"}
new_image_info = api.image.update_meta(id=image.id, meta=new_meta)
print(new_image_info["meta"])
Output:
# {'my-field-3': 'my-value-3', 'my-field-4': 'my-value-4'}
You can also get image metadata in Image labeling toolbox interface
Remove image from Supervisely by id
Source code:
api.image.remove(image.id)
print(f"Image (ID: {image.id}) successfully removed")
Output:
# Image (ID: 17539453) successfully removed
Remove list of images from Supervisely by ids.
Source code:
images_to_remove = api.image.get_list(dataset.id)
remove_ids = [img.id for img in images_to_remove]
api.image.remove_batch(remove_ids)
print(f"{len(remove_ids)} images successfully removed.")
Output:
# 9 images successfully removed.
To enhance the usability of working with images in the Image Labeling Toolbox, a custom sorting parameter can be added for project images. This parameter will define the order of images in the interface list.
- Sort button
- Sorting parameter
The best and fastest way to accomplish this is to use context manager ImageApi.add_custom_sort
This context manager allows you to set the sort_by
attribute of ImageApi
object for the duration of the context, then delete it.
If nested functions support this functionality, each image they process will automatically receive a custom sorting parameter based on the available meta object.
Currently, almost all image uploading methods support this functionality. Methods that support it have a corresponding description in the docstring.
Source code:
original_dir = "src/images/original"
names = ["Oranges 1", "Oranges 2"]
paths = [os.path.join(original_dir, "oranges-1.jpg"), os.path.join(original_dir, "oranges-2.jpg")]
metas = [{"key-1": "a", "my-key": "b"}, {"key-1": "c", "my-key": "f"}]
with api.image.add_custom_sort(key="my-key"):
image_infos = api.image.upload_paths(
dataset.id,
names=names,
paths=paths,
metas=metas
)
for i in image_infos:
print(f"{i.name}: {i.meta}")
Output:
# Oranges 1.jpeg: {'key-1': 'a', 'my-key': 'b', 'customSort': 'b'}
# Oranges 2.jpeg: {'key-1': 'c', 'my-key': 'f', 'customSort': 'f'}
It is also recommended to use a context manager for uploading the entire project. The only difference from the previous point is that there is no need to pass meta in dictionaries. It can be stored either in image info files or in meta files within the project structure. To learn more about the project structure and its files, see the Project Structure section.
Source code:
from supervisely.project.upload import upload
project_dir = "src/images_project"
project_name = "Project with Sorting"
with api.image.add_custom_sort(key="my-key"):
upload(project_dir, api, workspace_id, project_name)
project_info = api.project.get_info_by_name(workspace_id, project_name)
dataset_info = api.dataset.get_list(project_info.id)[0]
images_infos = api.image.get_list(dataset_info.id)
for i in images_infos:
print(f"{i.name}: {i.meta}")
Output:
# oranges-2.jpg: {'my-key': '5', 'customSort': '5'}
# oranges-1.jpg: {'my-key': '4', 'customSort': '4'}
# grapes-2.jpg: {'my-key': '1', 'customSort': '1'}
# lemons.jpg: {'my-key': '5', 'customSort': '5'}
# grapes-1.jpg: {'my-key': '2', 'customSort': '2'}
Here are several ways to modify meta for images
Source code:
meta = {"key-1": "a", "my-key": "b"}
new_meta = api.image.update_custom_sort(meta, "sort-value")
new_image_info = api.image.update_meta(id=images_infos[0].id, meta=new_meta)
print(new_image_info["meta"])
Output:
# {'key-1': 'a', 'my-key': 'b', 'customSort': 'sort-value'}
Source code:
api.image.set_custom_sort(new_image_info["id"], "new-sort-value")
updated_image_info = api.image.get_info_by_id(new_image_info["id"])
print(updated_image_info.meta)
Output:
# {'key-1': 'a', 'my-key': 'b', 'customSort': 'new-sort-value'}
Same as the previous case, but for more than one image
Source code:
image_ids = [image.id for image in images_infos]
sort_values = ["1st", "2nd", "3rd", "4th", "5th"]
api.image.set_custom_sort_bulk(image_ids, sort_values)
images_infos = api.image.get_list(dataset_info.id)
for i in images_infos:
print(f"{i.name}: {i.meta}")
Output:
# oranges-2.jpg: {'key-1': 'a', 'my-key': 'b', 'customSort': '1st'}
# oranges-1.jpg: {'my-key': '4', 'customSort': '2nd'}
# grapes-2.jpg: {'my-key': '1', 'customSort': '3rd'}
# lemons.jpg: {'my-key': '5', 'customSort': '4th'}
# grapes-1.jpg: {'my-key': '2', 'customSort': '5th'}