Source code for supervisely.project.project_settings

# coding: utf-8

from __future__ import annotations

from typing import Dict, Optional

from jsonschema import ValidationError, validate

from supervisely._utils import take_with_default
from supervisely.annotation.tag_meta import TagValueType
from supervisely.collection.str_enum import StrEnum
from supervisely.io.json import JsonSerializable
from supervisely.project.project_type import ProjectType
from supervisely.sly_logger import logger


[docs] class LabelingInterface(str, StrEnum): """Enumerates supported labeling UI interfaces for a project (images, multiview, medical, etc.).""" DEFAULT = "default" MEDICAL_IMAGING_SINGLE = "medical_imaging_single" IMAGES_WITH_16_COLOR = "images_with_16_color" MULTISPECTRAL = "multispectral" OVERLAY = "overlay" MULTIVIEW = "multi_view" IMAGE_MATTING = "image_matting" FISHEYE = "fisheye"
class ProjectSettingsJsonFields: """JSON field names used in :class:`~supervisely.project.project_settings.ProjectSettings` serialization.""" MULTI_VIEW = "multiView" ENABLED = "enabled" TAG_ID = "tagId" TAG_NAME = "tagName" IS_SYNCED = "isSynced" LABELING_INTERFACE = "labelingInterface" class ProjectSettingsRequiredSchema: """JSON schema for validating serialized :class:`~supervisely.project.project_settings.ProjectSettings`.""" SCHEMA = { "type": "object", "properties": { ProjectSettingsJsonFields.MULTI_VIEW: { "type": "object", "properties": { ProjectSettingsJsonFields.ENABLED: {"type": "boolean"}, ProjectSettingsJsonFields.TAG_ID: {"type": ["integer", "null"]}, ProjectSettingsJsonFields.TAG_NAME: {"type": ["string", "null"]}, ProjectSettingsJsonFields.IS_SYNCED: {"type": "boolean"}, }, "required": [ ProjectSettingsJsonFields.ENABLED, ProjectSettingsJsonFields.TAG_ID, ProjectSettingsJsonFields.TAG_NAME, ProjectSettingsJsonFields.IS_SYNCED, ], "additionalProperties": False, }, ProjectSettingsJsonFields.LABELING_INTERFACE: {"type": ["string", "null"]}, }, "required": [ProjectSettingsJsonFields.MULTI_VIEW], "additionalProperties": False, } def validate_project_settings_schema(data: dict) -> None: try: validate(instance=data, schema=ProjectSettingsRequiredSchema.SCHEMA) except ValidationError as e: if e.json_path == "$": raise ValidationError( f"The validation has failed with the following message: {e.message}." ) msg = f"The validation of the field {e.json_path} has failed with the following message: {e.message}." if e.validator == "required": raise ValidationError( f"{msg} Check the correctness of the field names in the {ProjectSettingsJsonFields}." ) elif e.validator == "type": raise ValidationError( f"{msg} Check the correctness of the field value types in the {ProjectSettingsRequiredSchema}." ) else: raise ValidationError(msg)
[docs] class ProjectSettings(JsonSerializable): """Project settings: multi-view mode, labeling interface, etc.""" def __init__( self, multiview_enabled: bool = False, multiview_tag_name: Optional[str] = None, multiview_tag_id: Optional[int] = None, multiview_is_synced: bool = False, labeling_interface: Optional[LabelingInterface] = None, ): """:param multiview_enabled: Enable multi-view mode. :type multiview_enabled: bool :param multiview_tag_name: Name of the tag used as group tag for multi-window mode. :type multiview_tag_name: str, optional :param multiview_tag_id: Id of the tag used as group tag for multi-window mode. :type multiview_tag_id: int, optional :param multiview_is_synced: Enable synchronization of views for multi-view mode. :type multiview_is_synced: bool :param labeling_interface: The interface for labeling images. :type labeling_interface: str, optional :raises ValidationError: if settings schema is invalid. :Usage Example: .. code-block:: python import supervisely as sly settings_json = {"multiView": {"enabled": True, "tagName": "group_tag", "tagId": None, "isSynced": False}} settings = sly.ProjectSettings.from_json(settings_json) """ self.multiview_enabled = multiview_enabled self.multiview_tag_name = multiview_tag_name self.multiview_tag_id = multiview_tag_id self.multiview_is_synced = multiview_is_synced if labeling_interface is not None: if labeling_interface not in LabelingInterface.values(): raise ValueError( f"Invalid labeling interface value: {labeling_interface}. The available values: {LabelingInterface.values()}" ) self.labeling_interface = labeling_interface if multiview_enabled is False and multiview_is_synced is True: logger.warning( "The 'Group Images sync mode' is enabled, but it won't effect while multi-view mode is disabled. Please enable the multi-view mode (a.k.a. 'Group Images mode')." ) @classmethod def from_json(cls, data: Dict) -> ProjectSettings: validate_project_settings_schema(data) d_multiview = data[ProjectSettingsJsonFields.MULTI_VIEW] labeling_interface = data.get(ProjectSettingsJsonFields.LABELING_INTERFACE) return cls( multiview_enabled=d_multiview[ProjectSettingsJsonFields.ENABLED], multiview_tag_name=d_multiview[ProjectSettingsJsonFields.TAG_NAME], multiview_tag_id=d_multiview[ProjectSettingsJsonFields.TAG_ID], multiview_is_synced=d_multiview[ProjectSettingsJsonFields.IS_SYNCED], labeling_interface=labeling_interface, ) def to_json(self) -> dict: data = { ProjectSettingsJsonFields.MULTI_VIEW: { ProjectSettingsJsonFields.ENABLED: self.multiview_enabled, ProjectSettingsJsonFields.TAG_NAME: self.multiview_tag_name, ProjectSettingsJsonFields.TAG_ID: self.multiview_tag_id, ProjectSettingsJsonFields.IS_SYNCED: self.multiview_is_synced, } } if self.labeling_interface is not None: data[ProjectSettingsJsonFields.LABELING_INTERFACE] = self.labeling_interface validate_project_settings_schema(data) return data def clone( self, multiview_enabled: bool = None, multiview_tag_name: Optional[str] = None, multiview_tag_id: Optional[int] = None, multiview_is_synced: bool = None, labeling_interface: Optional[LabelingInterface] = None, ): return ProjectSettings( multiview_enabled=take_with_default(multiview_enabled, self.multiview_enabled), multiview_tag_name=take_with_default(multiview_tag_name, self.multiview_tag_name), multiview_tag_id=take_with_default(multiview_tag_id, self.multiview_tag_id), multiview_is_synced=take_with_default(multiview_is_synced, self.multiview_is_synced), labeling_interface=take_with_default(labeling_interface, self.labeling_interface), ) def validate(self, meta): if meta.project_settings.multiview_enabled is True: # Images multiview if meta.project_type == ProjectType.IMAGES: mtag_name = meta.project_settings.multiview_tag_name if mtag_name is None: if meta.project_settings.multiview_tag_id is None: return # (tag_name, tag_id) == (None, None) is OK mtag_name = meta.get_tag_name_by_id(meta.project_settings.multiview_tag_id) if mtag_name is None: raise RuntimeError( f"The multi-view tag with ID={meta.project_settings.multiview_tag_id} was not found in the project meta. " "Please directly add the tag meta that will be used for image grouping for multi-view labeling interface." ) multi_tag = meta.get_tag_meta(mtag_name) if multi_tag is None: raise RuntimeError( f"The multi-view tag '{mtag_name}' was not found in the project meta. Please directly add the tag meta " "that will be used for image grouping for multi-view labeling interface." ) elif multi_tag.value_type != TagValueType.ANY_STRING: raise RuntimeError( f"The multi-view tag value type should be '{TagValueType.ANY_STRING}'. The provided type: '{multi_tag.value_type}'." ) # Video multiview elif meta.project_type == ProjectType.VIDEOS: if ( meta.project_settings.multiview_tag_name is not None or meta.project_settings.multiview_tag_id is not None ): raise RuntimeError( "For video projects, multiview_tag_name and multiview_tag_id should be None. " "Videos are grouped by datasets, not by tags." ) if meta.project_settings.labeling_interface is not None: if meta.project_settings.labeling_interface not in LabelingInterface.values(): raise RuntimeError( f"Invalid labeling interface value: {meta.project_settings.labeling_interface}. " f"The available values: {LabelingInterface.values()}" )