Source code for supervisely.mesh_annotation.mesh_annotation

# coding: utf-8
from __future__ import annotations

import json
import uuid
from typing import Dict, List, Optional

from supervisely._utils import take_with_default
from supervisely.mesh_annotation.constants import DESCRIPTION, FIGURES, KEY, LABELS, OBJECTS, TAGS
from supervisely.mesh_annotation.mesh_label import MeshLabel
from supervisely.mesh_annotation.mesh_tag_collection import MeshTagCollection
from supervisely.project.project_meta import ProjectMeta


[docs] class MeshAnnotation: """Annotation for a single mesh entity.""" def __init__( self, labels: Optional[List[MeshLabel]] = None, tags: Optional[MeshTagCollection] = None, description: Optional[str] = "", key: Optional[uuid.UUID] = None, ): """Initialize a mesh annotation as a flat list of labels and entity tags. :param labels: Mesh labels (geometry-backed objects) of the annotation. :type labels: Optional[List[:class:`~supervisely.mesh_annotation.mesh_label.MeshLabel`]] :param tags: Entity-level tags attached to the mesh. :type tags: Optional[:class:`~supervisely.mesh_annotation.mesh_tag_collection.MeshTagCollection`] :param description: Free-text description of the annotation. :type description: Optional[str] :param key: Unique identifier of the annotation. Generated automatically if not provided. :type key: Optional[uuid.UUID] """ self._description = take_with_default(description, "") self._tags = take_with_default(tags, MeshTagCollection()) self._labels = take_with_default(labels, []) self._key = take_with_default(key, uuid.uuid4()) @property def description(self) -> str: """Free-text description of the annotation. :rtype: str """ return self._description @property def tags(self) -> MeshTagCollection: """Entity-level tags attached to the mesh (returned as a copy). :rtype: :class:`~supervisely.mesh_annotation.mesh_tag_collection.MeshTagCollection` """ return self._tags.clone() @property def labels(self) -> List[MeshLabel]: """Mesh labels of the annotation (returned as a shallow copy of the list). :rtype: List[:class:`~supervisely.mesh_annotation.mesh_label.MeshLabel`] """ return self._labels.copy()
[docs] def key(self) -> uuid.UUID: """Return the unique identifier of the annotation. :returns: Annotation key. :rtype: uuid.UUID """ return self._key
[docs] def to_json(self) -> Dict: """Serialize the annotation to a JSON-serializable dict. :returns: Dict with description, key, tags and labels of the annotation. :rtype: dict """ return { DESCRIPTION: self.description, KEY: self.key().hex, TAGS: self.tags.to_json(), LABELS: [label.to_json() for label in self.labels], }
[docs] @classmethod def from_json(cls, data: Dict, project_meta: ProjectMeta) -> "MeshAnnotation": """Deserialize a mesh annotation from a JSON dict. :param data: Mesh annotation in JSON format. :type data: dict :param project_meta: Project meta used to resolve object classes and tag metas. :type project_meta: :class:`~supervisely.project.project_meta.ProjectMeta` :returns: Deserialized mesh annotation. :rtype: :class:`~supervisely.mesh_annotation.mesh_annotation.MeshAnnotation` :raises RuntimeError: If the JSON uses the unsupported legacy ``objects``/``figures`` schema. """ if OBJECTS in data or FIGURES in data: raise RuntimeError( "Legacy mesh annotation JSON with 'objects'/'figures' is not supported. " "Use the 'labels' mesh annotation schema." ) try: item_key = uuid.UUID(data[KEY]) except Exception: item_key = uuid.uuid4() description = data.get(DESCRIPTION, "") tags = MeshTagCollection.from_json(data.get(TAGS, []), project_meta.tag_metas) labels = [ MeshLabel.from_json(label_json, project_meta) for label_json in data.get(LABELS, []) ] return cls(labels=labels, tags=tags, description=description, key=item_key)
[docs] @classmethod def load_json_file(cls, path: str, project_meta: ProjectMeta) -> "MeshAnnotation": """Load and deserialize a mesh annotation from a JSON file. :param path: Path to the JSON file. :type path: str :param project_meta: Project meta used to resolve object classes and tag metas. :type project_meta: :class:`~supervisely.project.project_meta.ProjectMeta` :returns: Deserialized mesh annotation. :rtype: :class:`~supervisely.mesh_annotation.mesh_annotation.MeshAnnotation` """ with open(path) as fin: data = json.load(fin) return cls.from_json(data, project_meta)
[docs] def clone( self, labels: Optional[List[MeshLabel]] = None, tags: Optional[MeshTagCollection] = None, description: Optional[str] = None, ) -> "MeshAnnotation": """Return a copy of the annotation with the given fields overridden. :param labels: New mesh labels. Keeps current labels if not provided. :type labels: Optional[List[:class:`~supervisely.mesh_annotation.mesh_label.MeshLabel`]] :param tags: New entity tags. Keeps current tags if not provided. :type tags: Optional[:class:`~supervisely.mesh_annotation.mesh_tag_collection.MeshTagCollection`] :param description: New description. Keeps current description if not provided. :type description: Optional[str] :returns: New mesh annotation with the same key and the overridden fields. :rtype: :class:`~supervisely.mesh_annotation.mesh_annotation.MeshAnnotation` """ return MeshAnnotation( labels=take_with_default(labels, self.labels), tags=take_with_default(tags, self.tags), description=take_with_default(description, self.description), key=self.key(), )