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
  • Function signature
  • Parameters
  • slider_title
  • enable_zoom
  • opacity
  • sync_views
  • widget_id
  • Methods and attributes
  • Mini App Example
  • Import libraries
  • Init API client
  • Get project ID and dataset ID from environment variables
  • Create static directory (optional)
  • Create Button widgets for controlling ImagePairSequence
  • Prepare images and annotations for ImagePairSequence widget
  • Initialize ImagePairSequence widget we will use in UI
  • Create app layout
  • Create app using layout
  • Add function to add predictions
  • Run the app

Was this helpful?

Edit on GitHub
  1. App development
  2. Widgets
  3. Media

ImagePairSequence

PreviousVideoPlayerNextIcons

Last updated 1 year ago

Was this helpful?

Introduction

The ImagePairSequence widget is a widget in Supervisely designed for displaying pairs of images and annotations. It is useful for comparing. For example, it can be used to compare ground truth and predictions in a grid format. It allows users to navigate through multiple pages of predictions and provides zooming functionality, making it convenient for visualizing annotated image results.

All images will be saved in the Team Files in the offline-sessions directory: /offline-sessions/{task_id}/app-template/sly/css/app/widgets/image_pair_sequence/{image_name}

Function signature

ImagePairSequence(
    opacity=0.4,
    enable_zoom=False,
    sync_views=True,
    slider_title="pairs",
    widget_id=None,
)

Parameters

Parameters
Type
Description

opacity

Optional[float]

Objects opacity

enable_zoom

Optional[bool]

Enable zoom on ImagePairSequence

sync_views

Optional[bool]

Enable sync zoom on ImagePairSequence images

slider_title

Optional[str]

Measurement units in the widget controls

widget_id

Optional[str]

Id of the widget

slider_title

Measurement units in the widget controls.

type: Optional[str]

default value: epochs

image_pair_sequence = ImagePairSequence(slider_title="predictions")

enable_zoom

Enable zoom on ImagePairSequence.

type: Optional[bool]

default value: False

image_pair_sequence = ImagePairSequence(enable_zoom=True)

opacity

Objects opacity.

type: Optional[float]

default value: 0.4

image_pair_sequence = ImagePairSequence(opacity=0.8)

sync_views

Enable sync zoom on ImagePairSequence images.

type: Optional[bool]

default value: True

image_pair_sequence = ImagePairSequence(sync_views=False)

widget_id

ID of the widget.

type: str

default value: None

Methods and attributes

By using the ImagePairSequence widget, you can set the images, annotations and titles to display on the left and right sides of the widget. You can also set a batch of images, annotations and titles to display on the left and right sides of the widget. The widget also provides methods for clearing the widget.

All the images will be saved in the Team Files in the offline-sessions directory:

/offline-sessions/{task_id}/app-template/sly/css/app/widgets/image_pair_sequence/{image_name}

Attributes and Methods
Description

append_left(path: str, ann: sly.Annotation, title: str)

Sets the image, annotation and title to display on the left side of ImagePairSequence.

append_right(path: str, ann: sly.Annotation, title: str)

Sets the image, annotation aand title to display on the right side of ImagePairSequence.

extend_left(paths: List[str], anns: Optional[List[sly.Annotation]], titles: Optional[List[str]])

Sets a batch of images, annotations and titles to display on the left side of ImagePairSequence.

extend_right(paths: List[str], anns: Optional[List[sly.Annotation]], titles: Optional[List[str]])

Sets a batch of images, annotations and titles to display on the right side of ImagePairSequence.

append_pair(left: Tuple[str, sly.Annotation, str], right: Tuple[str, sly.Annotation, str])

Sets a pair of images, annotations and titles to display on the ImagePairSequence.

extend_pairs(left: List[Tuple], right: List[Tuple])

Sets a batch of pairs of images, annotations and titles to display on the ImagePairSequence.

clean_up()

Clears the ImagePairSequence widget.

disable()

Disables the ImagePairSequence widget controls.

enable()

Enables the ImagePairSequence widget controls.

Mini App Example

You can find this example in our Github repository:

Import libraries

import os

import supervisely as sly
from dotenv import load_dotenv
from supervisely.app.widgets import Button, Card, Container, Flexbox, ImagePairSequence, Text

Init API client

First, we load environment variables with credentials and init API for communicating with Supervisely Instance:

load_dotenv("local.env")
load_dotenv(os.path.expanduser("~/supervisely.env"))

api = sly.Api()

Get project ID and dataset ID from environment variables

project_id = sly.env.project_id()
dataset_id = sly.env.dataset_id()
project_meta = sly.ProjectMeta.from_json(data=api.project.get_meta(id=project_id))

Create static directory (optional)

data_dir = sly.app.get_data_dir()
static_dir = os.path.join(data_dir, "static")
if not os.path.exists(static_dir):
    os.makedirs(static_dir)

Create Button widgets for controlling ImagePairSequence

left_btn = Button(text="add 1 prediction to left")
right_btn = Button(text="add 1 prediction to right")
left_three_btn = Button(text="add 3 predictions to left")
right_three_btn = Button(text="add 3 predictions to right")
pair_btn = Button(text="add 1 pair")
pairs_batch_btn = Button(text="add 3 pairs")
clean_btn = Button(text="clean up")

btn_container = Flexbox(
    [left_btn, right_btn, left_three_btn, right_three_btn, pair_btn, pairs_batch_btn, clean_btn]
)

Prepare images and annotations for ImagePairSequence widget

# get all image infos in dataset
used_names = set()
images_infos = api.image.get_list(dataset_id=dataset_id)
images_infos = sorted(images_infos, key=lambda image_info: image_info.name)
image_ids = [image_info.id for image_info in images_infos]
urls = [img.full_storage_url for img in images_infos]
paths = [
    os.path.join(static_dir, sly.generate_free_name(used_names, image_info.name, with_ext=True))
    for image_info in images_infos
]
static_paths = [os.path.join("static", os.path.basename(path)) for path in paths]

api.image.download_paths(dataset_id, image_ids, paths)

# get annotations for all images
anns_json = api.annotation.download_json_batch(dataset_id=dataset_id, image_ids=image_ids)
anns = [sly.Annotation.from_json(ann_json, project_meta) for ann_json in anns_json]

Initialize ImagePairSequence widget we will use in UI

image_pair_sequence = ImagePairSequence()

Create app layout

Prepare a layout for app using Card widget with the content parameter and place widget that we've just created in the Container widget.

text = Text()

card = Card(
    title="Image Pair Sequence",
    content=Container([image_pair_sequence]),
)
layout = Container(widgets=[btn_container, card, text])

Create app using layout

Create an app object with layout parameter. We also pass the static_dir parameter to the app object so that the app can serve static files (optional).

app = sly.Application(layout=layout, static_dir=static_dir)

Add function to add predictions

left_urls_generator = (url for url in static_paths)
right_urls_generator = (url for url in static_paths)
left_anns_generator = (ann for ann in anns)
right_anns_generator = (ann for ann in anns)


left_num = 0
right_num = 0


def get_next_prediction(side):
    global left_num, right_num
    path, ann, title = None, None, None
    path_gen = left_urls_generator if side == "left" else right_urls_generator
    ann_gen = left_anns_generator if side == "left" else right_anns_generator
    try:
        path = next(path_gen)
        ann = next(ann_gen)
        if side == "left":
            title = f"Predictions {left_num}"
            left_num += 1
        else:
            title = f"Predictions {right_num}"
            right_num += 1
    except StopIteration:
        sly.logger.info("No more predictions.")
        text.set(text="No more predictions.", status="info")
    finally:
        return path, ann, title


@pair_btn.click
def pair_btn_click_handler():
    left = get_next_prediction("left")
    right = get_next_prediction("right")
    if left[0] is not None and right[0] is not None:
        image_pair_sequence.append_pair(left=left, right=right)


@pairs_batch_btn.click
def pairs_batch_btn_click_handler():
    lefts = []
    rights = []

    for _ in range(3):
        left = get_next_prediction("left")
        right = get_next_prediction("right")

        if left[0] is not None and right[0] is not None:
            lefts.append(left)
            rights.append(right)

    if len(lefts) > 0 and len(rights) > 0:
        image_pair_sequence.set_pairs_batch(lefts, rights)


@left_btn.click
def left_btn_click_handler():
    path, ann, title = get_next_prediction("left")
    if path is not None:
        image_pair_sequence.append_left(path, ann, title)


@right_btn.click
def right_btn_click_handler():
    path, ann, title = get_next_prediction("right")
    if path is not None:
        image_pair_sequence.append_right(path, ann, title)


@left_three_btn.click
def left_three_btn_click_handler():
    data = []

    for _ in range(3):
        left = get_next_prediction("left")

        if left[0] is not None:
            data.append(left)

    if len(data) > 0:
        paths, anns, titles = zip(*data)
        image_pair_sequence.extend_left(paths=paths, anns=anns, titles=titles)


@right_three_btn.click
def right_three_btn_click_handler():
    data = []

    for _ in range(3):
        right = get_next_prediction("right")

        if right[0] is not None:
            data.append(right)

    if len(data) > 0:
        paths, anns, titles = zip(*data)
        image_pair_sequence.extend_right(paths=paths, anns=anns, titles=titles)


@clean_btn.click
def clean_btn_click_handler():
    image_pair_sequence.clean_up()

Run the app

opacity

🔥
supervisely-ecosystem/ui-widgets-demos/media/007_image_pair_sequence/src/main.py