Supervisely
About SuperviselyEcosystemContact usSlack
  • 💻Supervisely Developer Portal
  • 🎉Getting Started
    • Installation
    • Basics of authentication
    • Intro to Python SDK
    • Environment variables
    • Supervisely annotation format
      • Project Structure
      • Project Meta: Classes, Tags, Settings
      • Objects
      • Tags
      • Image Annotation
      • Video Annotation
      • Point Clouds Annotation
      • Point Cloud Episode Annotation
      • Volumes Annotation
    • Python SDK tutorials
      • Images
        • Images
        • Image and object tags
        • Spatial labels on images
        • Keypoints (skeletons)
        • Multispectral images
        • Multiview images
        • Advanced: Optimized Import
        • Advanced: Export
      • Videos
        • Videos
        • Video and object tags
        • Spatial labels on videos
      • Point Clouds
        • Point Clouds (LiDAR)
        • Point Cloud Episodes and object tags
        • 3D point cloud object segmentation based on sensor fusion and 2D mask guidance
        • 3D segmentation masks projection on 2D photo context image
      • Volumes
        • Volumes (DICOM)
        • Spatial labels on volumes
      • Common
        • Iterate over a project
        • Iterate over a local project
        • Progress Bar tqdm
        • Cloning projects for development
    • Command Line Interface (CLI)
      • Enterprise CLI Tool
        • Instance administration
        • Workflow automation
      • Supervisely SDK CLI
    • Connect your computer
      • Linux
      • Windows WSL
      • Troubleshooting
  • 🔥App development
    • Basics
      • Create app from any py-script
      • Configuration file
        • config.json
        • Example 1. Headless
        • Example 2. App with GUI
        • v1 - Legacy
          • Example 1. v1 Modal Window
          • Example 2. v1 app with GUI
      • Add private app
      • Add public app
      • App Compatibility
    • Apps with GUI
      • Hello World!
      • App in the Image Labeling Tool
      • App in the Video Labeling Tool
      • In-browser app in the Labeling Tool
    • Custom import app
      • Overview
      • From template - simple
      • From scratch - simple
      • From scratch GUI - advanced
      • Finding directories with specific markers
    • Custom export app
      • Overview
      • From template - simple
      • From scratch - advanced
    • Neural Network integration
      • Overview
      • Serving App
        • Introduction
        • Instance segmentation
        • Object detection
        • Semantic segmentation
        • Pose estimation
        • Point tracking
        • Object tracking
        • Mask tracking
        • Image matting
        • How to customize model inference
        • Example: Custom model inference with probability maps
      • Serving App with GUI
        • Introduction
        • How to use default GUI template
        • Default GUI template customization
        • How to create custom user interface
      • Inference API
      • Training App
        • Overview
        • Tensorboard template
        • Object detection
      • High level scheme
      • Custom inference pipeline
      • Train and predict automation model pipeline
    • Advanced
      • Advanced debugging
      • How to make your own widget
      • Tutorial - App Engine v1
        • Chapter 1 Headless
          • Part 1 — Hello world! [From your Python script to Supervisely APP]
          • Part 2 — Errors handling [Catching all bugs]
          • Part 3 — Site Packages [Customize your app]
          • Part 4 — SDK Preview [Lemons counter app]
          • Part 5 — Integrate custom tracker into Videos Annotator tool [OpenCV Tracker]
        • Chapter 2 Modal Window
          • Part 1 — Modal window [What is it?]
          • Part 2 — States and Widgets [Customize modal window]
        • Chapter 3 UI
          • Part 1 — While True Script [It's all what you need]
          • Part 2 — UI Rendering [Simplest UI Application]
          • Part 3 — APP Handlers [Handle Events and Errors]
          • Part 4 — State and Data [Mutable Fields]
          • Part 5 — Styling your app [Customizing the UI]
        • Chapter 4 Additionals
          • Part 1 — Remote Developing with PyCharm [Docker SSH Server]
      • Custom Configuration
        • Fixing SSL Certificate Errors in Supervisely
        • Fixing 400 HTTP errors when using HTTP instead of HTTPS
      • Autostart
      • Coordinate System
      • MLOps Workflow integration
    • Widgets
      • Input
        • Input
        • InputNumber
        • InputTag
        • BindedInputNumber
        • DatePicker
        • DateTimePicker
        • ColorPicker
        • TimePicker
        • ClassesMapping
        • ClassesColorMapping
      • Controls
        • Button
        • Checkbox
        • RadioGroup
        • Switch
        • Slider
        • TrainValSplits
        • FileStorageUpload
        • Timeline
        • Pagination
      • Text Elements
        • Text
        • TextArea
        • Editor
        • Copy to Clipboard
        • Markdown
        • Tooltip
        • ElementTag
        • ElementTagsList
      • Media
        • Image
        • LabeledImage
        • GridGallery
        • Video
        • VideoPlayer
        • ImagePairSequence
        • Icons
        • ObjectClassView
        • ObjectClassesList
        • ImageSlider
        • Carousel
        • TagMetaView
        • TagMetasList
        • ImageAnnotationPreview
        • ClassesMappingPreview
        • ClassesListPreview
        • TagsListPreview
        • MembersListPreview
      • Selection
        • Select
        • SelectTeam
        • SelectWorkspace
        • SelectProject
        • SelectDataset
        • SelectItem
        • SelectTagMeta
        • SelectAppSession
        • SelectString
        • Transfer
        • DestinationProject
        • TeamFilesSelector
        • FileViewer
        • Dropdown
        • Cascader
        • ClassesListSelector
        • TagsListSelector
        • MembersListSelector
        • TreeSelect
        • SelectCudaDevice
      • Thumbnails
        • ProjectThumbnail
        • DatasetThumbnail
        • VideoThumbnail
        • FolderThumbnail
        • FileThumbnail
      • Status Elements
        • Progress
        • NotificationBox
        • DoneLabel
        • DialogMessage
        • TaskLogs
        • Badge
        • ModelInfo
        • Rate
        • CircleProgress
      • Layouts and Containers
        • Card
        • Container
        • Empty
        • Field
        • Flexbox
        • Grid
        • Menu
        • OneOf
        • Sidebar
        • Stepper
        • RadioTabs
        • Tabs
        • TabsDynamic
        • ReloadableArea
        • Collapse
        • Dialog
        • IFrame
      • Tables
        • Table
        • ClassicTable
        • RadioTable
        • ClassesTable
        • RandomSplitsTable
        • FastTable
      • Charts and Plots
        • LineChart
        • GridChart
        • HeatmapChart
        • ApexChart
        • ConfusionMatrix
        • LinePlot
        • GridPlot
        • ScatterChart
        • TreemapChart
        • PieChart
      • Compare Data
        • MatchDatasets
        • MatchTagMetas
        • MatchObjClasses
        • ClassBalance
        • CompareAnnotations
      • Widgets demos on github
  • 😎Advanced user guide
    • Objects binding
    • Automate with Python SDK & API
      • Start and stop app
      • User management
      • Labeling Jobs
  • 🖥️UI widgets
    • Element UI library
    • Supervisely UI widgets
    • Apexcharts - modern & interactive charts
    • Plotly graphing library
  • 📚API References
    • REST API Reference
    • Python SDK Reference
Powered by GitBook
On this page
  • Introduction
  • How to debug this tutorial
  • Import libraries
  • Load environment variables
  • Init API client
  • Explore the directory with images
  • Create a new project and dataset
  • Enable multiview in the project settings
  • How to upload multiview images
  • Upload multiview images
  • Group existing images for multiview
  • Grouped view in the labeling interface
  • How to upload label groups
  • Summary

Was this helpful?

Edit on GitHub
  1. Getting Started
  2. Python SDK tutorials
  3. Images

Multiview images

PreviousMultispectral imagesNextAdvanced: Optimized Import

Last updated 3 months ago

Was this helpful?

Introduction

This easy-to-follow tutorial will show you how to upload multiview images and label groups to Supervisely using Python SDK and get the advantage of the multiview image annotaion in the Supervisely Labeling Toolbox, which allows you to label images quickly and efficiently on one screen. You will learn how to enable multiview in the project settings, upload multiview images and explore the multiview in the labeling interface.

In this tutorial, we will show you how to do it programmatically using Python, but you can also do it manually in the Web UI using app from Supervisely Ecosystem or using our Import Wizard in the Web UI. Here is an illustrated example of how to do it:

Import multiview images

How to debug this tutorial

git clone https://github.com/supervisely-ecosystem/import-multiview-images-tutorial.git

cd import-multiview-images-tutorial

sh create_venv.sh

Step 3. Open the repository directory in Visual Studio Code.

code -r .

Step 4. Change the Workspace ID in the local.env file by copying the ID from the context menu.

WORKSPACE_ID=942 # ⬅️ change value

Step 5. Start debugging src/main.py.

Supervisely instance version >= 6.9.14 Supervisely SDK version >= 6.72.214

In the tutorial, Supervisely Python SDK version is not directly defined in the requirements.txt. But when developing your app, we recommend defining the SDK version in the requirements.txt.

Import libraries

import os

from dotenv import load_dotenv

import supervisely as sly

Load environment variables

if sly.is_development():
    load_dotenv("local.env")
    load_dotenv(os.path.expanduser("~/supervisely.env"))

workspace_id = sly.env.workspace_id()

Init API client

api = sly.Api.from_env()

Explore the directory with images

here is the structure of the directory with images (src/images):

 📂 images
 ┣ 📂 audi
 ┃ ┣ 🏞️ audi_01.jpg
 ┃ ┣ 🏞️ audi_02.jpg
 ┃ ┗ 🏞️ audi_03.jpg
 ┣ 📂 mercedes
 ┃ ┣ 🏞️ mercedes_01.jpg
 ┃ ┣ 🏞️ mercedes_02.jpg
 ┃ ┣ 🏞️ mercedes_03.jpg
 ┃ ┣ 🏞️ mercedes_04.jpg
 ┃ ┣ 🏞️ mercedes_05.jpg
 ┃ ┗ 🏞️ mercedes_06.jpg
 ┣ 📂 renault
 ┃ ┣ 🏞️ renault_01.jpg
 ┃ ┣ 🏞️ renault_02.jpg
 ┃ ┣ 🏞️ renault_03.jpg
 ┃ ┗ 🏞️ renault_04.jpg
 ┗ 📂 ford
   ┣ 🏞️ ford_01.jpg
   ┣ 🏞️ ford_02.jpg
   ┣ 🏞️ ford_03.jpg
   ┣ 🏞️ ford_04.jpg
   ┗ 🏞️ ford_05.jpg

Create a new project and dataset

project = api.project.create(workspace_id, "Grouped cars", change_name_if_conflict=True)
dataset = api.dataset.create(project.id, "ds0")

Enable multiview in the project settings

api.project.set_multiview_settings(project.id)

You can also enable multiview in the Image Labeling Tool interface:

And now we're ready to upload images.

How to upload multiview images

In this tutorial, we'll be using the api.image.upload_multiview_images method to upload multiview images to Supervisely.

def upload_multiview_images(
    dataset_id: int,
    group_name: str,
    paths: Optional[List[str]] = None,
    metas: Optional[List[Dict]] = None,
    progress_cb: Optional[Union[tqdm, Callable]] = None,
    links: Optional[List[str]] = None,
    conflict_resolution: Optional[Literal["rename", "skip", "replace"]] = "rename",
    force_metadata_for_links: Optional[bool] = False,
) -> List[ImageInfo]:
Parameters
Type
Description

dataset_id

int

ID of the dataset to upload

group_name

str

Name of the group (tag value)

paths

Optional[List[str]]

List of paths to the images (optional)

metas

Optional[List[Dict]]

List of image metas (optional)

progress_cb

Optional[Union[tqdm, Callable]]

Function for tracking upload progress (optional)

links

Optional[List[str]]

List of links to the images (optional)

conflict_resolution

Literal["rename", "skip", "replace"]

Conflict resolution strategy (optional)

force_metadata_for_links

Optional[bool]

Force metadata for links (optional)

So, the method uploads images to Supervisely and returns a list of ImageInfo objects.

Upload multiview images

for group_dir in os.scandir("src/images"):
    if not group_dir.is_dir():
        continue
    images_paths = sly.fs.list_files(group_dir.path, valid_extensions=sly.image.SUPPORTED_IMG_EXTS)

    api.image.upload_multiview_images(dataset.id, group_dir.name, images_paths)

Group existing images for multiview

Available starting from version v6.73.236 of the Supervisely Python SDK.

If you already have images uploaded to Supervisely and you want to group them for multiview, you can use the api.image.group_images_for_multiview method.

images = [2389126, 2389127, 2389128, 2389129, 2389130, ...]

for idx, batch_ids in enumerate(sly.batched(images, batch_size=6)):
    api.image.group_images_for_multiview(batch_ids, f"group_{idx}")
  • Default tag name is multiview. You can change it by passing the multiview_tag_name argument.

  • If the tag does not exist, it will be created automatically.

  • Automatically enables multiview mode in the project settings.

Grouped view in the labeling interface

So now, that we've uploaded all the images, let's take a look at the labeling interface.

As you can see, the images in the Labeling tool are grouped in the same way as in your images in folders (images from one folder are combined into one group). When importing, each image from the folders will be assigned tags with the same values, which allows them to be grouped into one group.

Multiview labeling can be very useful when annotating objects of multiple classes simultaneously on several images. You don't need to shift your attention to find the necessary class every time you switch between images, allowing you to increase efficiency and save time and effort.

How to upload label groups

Available starting from version v6.73.293 of the Supervisely Python SDK.

There are many cases when you need to group labels together. For example, if you have some labels captured from different perspectives that represent one object on different images and you want to analyze the object as a whole and not as separate instances, you can join them into a single group.

Label group - is a simple group of objects, that displays the relationship between objects and helps you to quickly locate the object on different images and to avoid labeling the same object multiple times.

Using the api.annotation.append_labels_group method, you can upload labels as a group to images.

def append_labels_group(
    self,
    dataset_id: int,
    image_ids: List[int],
    labels: List[Label],
    project_meta: Optional[ProjectMeta] = None,
    group_name: Optional[str] = None,
) -> None:
Parameters
Type
Description

dataset_id

int

Destination Dataset ID

image_ids

List[int]

Multiview images IDs

labels

List[Label]

group of labels (should be the same length as images_ids)

project_meta

Optional[ProjectMeta]

Project Meta (optional). Provide to avoid extra API calls

group_name

Optional[str]

Group name (optional). Labels will be assigned by tag with this value.

Let's group it all together and upload local images and labels to Supervisely using this method.

Our sample data directory structure:

 📂 data
 ┣ 📂 images
 ┃ ┣ 🏞️ car_01.jpeg
 ┃ ┣ 🏞️ car_02.jpeg
 ┃ ┗ 🏞️ car_03.jpeg
 ┗ 📂 masks
   ┣ 🏞️ car_01.png
   ┣ 🏞️ car_02.png
   ┗ 🏞️ car_03.png

Follow the code below to upload images and labels to Supervisely.

project_id = 56
dataset_id = 196

# GET PROJECT META
meta = sly.ProjectMeta.from_json(api.project.get_meta(project_id, with_settings=True))

# GET OBJ CLASS FROM META BY NAME
obj_cls = meta.get_obj_class("car")
# OR CREATE NEW OBJ CLASS IF NOT EXISTS
# obj_cls = sly.ObjClass(name="car", geometry_type=sly.Rectangle, color=[255, 0, 0])
# UPDATE PROJECT META IF CREATING NEW OBJ CLASS
# meta = meta.add_obj_classes([obj_cls])
# api.project.update_meta(project_id, meta.to_json())

# SET MULTIVIEW SETTINGS
api.project.set_multiview_settings(project_id)

# GET IMAGES AND MASKS PATHS
image_dir = os.path.join("data", "images")
mask_dir = os.path.join("data", "masks")

# SORT PATHS FOR CORRECT LABELS ORDER
image_paths = sorted([os.path.join(image_dir, path) for path in os.listdir(image_dir)])
mask_paths =  sorted([os.path.join(mask_dir, path) for path in os.listdir(mask_dir)])

# CREATE LABELS
labels = []
for image_path, mask_path in zip(image_paths, mask_paths):
    # READ MASK
    bitmap = sly.Bitmap.from_path(mask_path)
    # CREATE LABEL
    label = sly.Label(geometry=bitmap, obj_class=obj_cls)
    labels.append(label)

# UPLOAD IMAGES
image_infos = api.image.upload_multiview_images(dataset_id, "white_car", image_paths)
images_ids = [image_info.id for image_info in image_infos]

# APPEND LABELS TO IMAGES
api.annotation.append_labels_group(
    dataset_id=dataset_id,
    image_ids=images_ids,
    labels=labels,
    project_meta=meta,
)

Summary

In this tutorial, you learned how to upload multiview images and label groups to Supervisely using Python SDK and get the advantage of the multiview image annotation in the labeling interface, which allows you to label images quickly and efficiently on one screen. Let's recap the steps we did:

  1. Create a new project and dataset.

  2. Set multiview settings for the project using the api.project.set_multiview_settings method.

  3. Upload images using the api.image.upload_multiview_images method.

  4. Group existing images for multiview using the api.image.group_images_for_multiview method.

  5. Upload label groups using the api.annotation.append_labels_group method.

And that's it! Now you can upload your multview images to Supervisely using Python SDK.

Everything you need to reproduce : source code and additional app files.

Step 1. Prepare ~/supervisely.env file with credentials.

Step 2. Clone the with source code and demo data and create a .

Enable multiview mode in Labeling Toolbox
Multiview mode in the labeling interface
Multiview labeling
label group example
data sample

⬇️ You can download this sample here:

result
🎉
this tutorial is on GitHub
Learn more here.
repository
Virtual Environment
data.zip
Import Images Groups