from __future__ import annotations
import uuid
from typing import Dict, Optional, Union
from supervisely._utils import take_with_default
from supervisely.annotation.tag import Tag, TagJsonFields
from supervisely.annotation.tag_meta import TagMeta
from supervisely.annotation.tag_meta_collection import TagMetaCollection
from supervisely.pointcloud_annotation.constants import ID, KEY
from supervisely.video_annotation.key_id_map import KeyIdMap
[docs]
class PointcloudTag(Tag):
"""Tag on point cloud annotation (meta, value). Immutable."""
def __init__(
self,
meta: TagMeta,
value: Optional[Union[str, int, float]] = None,
key: Optional[uuid.UUID] = None,
sly_id: Optional[int] = None,
labeler_login: Optional[str] = None,
updated_at: Optional[str] = None,
created_at: Optional[str] = None,
):
"""
Tag on point cloud annotation.
:param meta: Tag metadata (name, value type).
:type meta: :class:`~supervisely.annotation.tag_meta.TagMeta`
:param value: Tag value; type must match TagMeta.value_type.
:type value: str or int or float, optional
:param key: UUID key. Auto-generated if not provided.
:type key: uuid.UUID, optional
:param sly_id: Server-side tag ID.
:type sly_id: int, optional
:param labeler_login: Login of user who created the tag.
:type labeler_login: str, optional
:param updated_at: Last modification timestamp (ISO format).
:type updated_at: str, optional
:param created_at: Creation timestamp (ISO format).
:type created_at: str, optional
:raises ValueError: If value is incompatible with TagMeta.value_type.
:Usage Example:
.. code-block:: python
import supervisely as sly
meta_dog = sly.TagMeta('dog', sly.TagValueType.NONE)
tag_dog = sly.PointcloudTag(meta_dog)
meta_cat = sly.TagMeta('cat', sly.TagValueType.ANY_STRING)
tag_cat = sly.PointcloudTag(meta_cat, value="Fluffy")
"""
super(PointcloudTag, self).__init__(
meta,
value=value,
sly_id=sly_id,
labeler_login=labeler_login,
updated_at=updated_at,
created_at=created_at,
)
self._key = take_with_default(key, uuid.uuid4())
[docs]
def get_compact_str(self) -> str:
"""
Get string with information about PointcloudTag name and value.
:returns: Information about :class:`~supervisely.pointcloud_annotation.pointcloud_tag.PointcloudTag` object
:rtype: str
:Usage Example:
.. code-block:: python
import supervisely as sly
meta_cat = sly.TagMeta('cat', sly.TagValueType.ANY_STRING)
tag_cat = sly.PointcloudTag(meta_cat, value="Fluffy")
compact_tag_cat = tag_cat.get_compact_str()
print(compact_tag_cat) # cat:Fluffy
"""
return super(PointcloudTag, self).get_compact_str()
def __eq__(self, other: PointcloudTag) -> bool:
"""
Checks that 2 Pointcloud Tags are equal by comparing their meta and value.
:param other: Pointcloud tag.
:type other: :class:`~supervisely.pointcloud_annotation.pointcloud_tag.PointcloudTag`
:returns: True if comparable objects are equal, otherwise False
:rtype: bool
:Usage Example:
.. code-block:: python
import supervisely as sly
# Let's create 2 identical Tags
meta_lemon_1 = sly.TagMeta('Lemon', sly.TagValueType.NONE)
tag_lemon_1 = sly.PointcloudTag(meta_lemon_1)
meta_lemon_2 = sly.TagMeta('Lemon', sly.TagValueType.NONE)
tag_lemon_2 = sly.PointcloudTag(meta_lemon_2)
# and 1 different Tag to compare them
meta_cucumber = sly.TagMeta('Cucumber', sly.TagValueType.ANY_STRING)
tag_cucumber = sly.PointcloudTag(meta_cucumber, value="Fresh")
# Compare identical Pointcloud Tags
tag_lemon_1 == tag_lemon_2 # True
# Compare unidentical Pointcloud Tags
tag_lemon_1 == tag_cucumber # False
"""
return super(PointcloudTag, self).__eq__(other)
def __ne__(self, other: PointcloudTag) -> bool:
"""
Checks that 2 Pointcloud Tags are opposite.
:param other: Pointcloud tag.
:type other: :class:`~supervisely.pointcloud_annotation.pointcloud_tag.PointcloudTag`
:returns: True if comparable objects are not equal, otherwise False
:rtype: bool
:Usage Example:
.. code-block:: python
import supervisely as sly
# Let's create 2 identical Tags
meta_lemon_1 = sly.TagMeta('Lemon', sly.TagValueType.NONE)
tag_lemon_1 = sly.PointcloudTag(meta_lemon_1)
meta_lemon_2 = sly.TagMeta('Lemon', sly.TagValueType.NONE)
tag_lemon_2 = sly.PointcloudTag(meta_lemon_2)
# and 1 different Tag to compare them
meta_cucumber = sly.TagMeta('Cucumber', sly.TagValueType.ANY_STRING)
tag_cucumber = sly.PointcloudTag(meta_cucumber, value="Fresh")
# Compare identical Pointcloud Tags
tag_lemon_1 != tag_lemon_2 # False
# Compare unidentical Pointcloud Tags
tag_lemon_1 != tag_cucumber # True
"""
return super(PointcloudTag, self).__ne__(other)
[docs]
def key(self) -> uuid.UUID:
"""
Get PointcloudTag key value.
:returns: PointcloudTag key value
:rtype: uuid.UUID
:Usage Example:
.. code-block:: python
import supervisely as sly
weather_conditions = ["Sunny", "Cloudy", "Snowy", "Foggy", "Rainy"]
meta_weather = sly.TagMeta("weather", sly.TagValueType.ONEOF_STRING, possible_values=weather_conditions)
tag_weather = sly.Tag(meta_weather, value="Sunny")
key = tag_weather.key()
print(key)
# Output: 5c7988e0-eee4-4eb1-972c-b1e3e879f78c
"""
return self._key
[docs]
def to_json(self, key_id_map: Optional[KeyIdMap] = None) -> Dict:
"""
Convert the PointcloudTag to a json dict.
Read more about `Supervisely format <https://docs.supervisely.com/data-organization/00_ann_format_navi>`_.
:param key_id_map: Key ID map.
:type key_id_map: :class:`~supervisely.video_annotation.key_id_map.KeyIdMap`, optional
:returns: Json format as a dict
:rtype: dict
:Usage Example:
.. code-block:: python
import supervisely as sly
meta_dog = sly.TagMeta('dog', sly.TagValueType.NONE)
tag_dog = sly.PointcloudTag(meta_dog)
tag_dog_json = tag_dog.to_json()
print(tag_dog_json)
# Output: {
# "name": "dog",
# "key": "058ad7993a534082b4d94cc52542a97d"
# }
"""
data_json = super(PointcloudTag, self).to_json()
if type(data_json) is str:
# case when tag has no value, super.to_json() returns tag name
data_json = {TagJsonFields.TAG_NAME: data_json}
data_json[KEY] = self.key().hex
if key_id_map is not None:
item_id = key_id_map.get_tag_id(self.key())
if item_id is not None:
data_json[ID] = item_id
return data_json
[docs]
@classmethod
def from_json(
cls,
data: Dict,
tag_meta_collection: TagMetaCollection,
key_id_map: Optional[KeyIdMap] = None,
) -> PointcloudTag:
"""
Convert a json dict to VideoTag. Read more about `Supervisely format <https://docs.supervisely.com/data-organization/00_ann_format_navi>`_.
:param data: PointcloudTag in json format as a dict.
:type data: dict
:param tag_meta_collection: Tag metadata collection.
:type tag_meta_collection: :class:`~supervisely.annotation.tag_meta_collection.TagMetaCollection`
:param key_id_map: Key ID map.
:type key_id_map: :class:`~supervisely.video_annotation.key_id_map.KeyIdMap`, optional
:returns: Pointcloud tag.
:rtype: :class:`~supervisely.pointcloud_annotation.pointcloud_tag.PointcloudTag`
:Usage Example:
.. code-block:: python
import supervisely as sly
tag_cat_json = {"name": "cat", "value": "Fluffy"}
meta_cat = sly.TagMeta('cat', sly.TagValueType.ANY_STRING)
meta_collection = sly.TagMetaCollection([meta_cat])
tag_cat = sly.PointcloudTag.from_json(tag_cat_json, meta_collection)
"""
temp = super(PointcloudTag, cls).from_json(data, tag_meta_collection)
key = uuid.UUID(data[KEY]) if KEY in data else uuid.uuid4()
if key_id_map is not None:
key_id_map.add_tag(key, data.get(ID, None))
return cls(
meta=temp.meta,
value=temp.value,
key=key,
sly_id=temp.sly_id,
labeler_login=temp.labeler_login,
updated_at=temp.updated_at,
created_at=temp.created_at,
)
[docs]
def clone(
self,
meta: Optional[TagMeta] = None,
value: Optional[Union[str, int, float]] = None,
key: Optional[uuid.UUID] = None,
sly_id: Optional[int] = None,
labeler_login: Optional[str] = None,
updated_at: Optional[str] = None,
created_at: Optional[str] = None,
) -> PointcloudTag:
"""
Clone makes a copy of pointcloud tag with new fields, if fields are given, otherwise it will use original tag fields.
:param meta: General information about pointcloud tag.
:type meta: :class:`~supervisely.annotation.tag_meta.TagMeta`, optional
:param value: Pointcloud tag value. Depends on TagValueType of :class:`~supervisely.annotation.tag_meta.TagMeta`.
:type value: str or int or float or None, optional
:param key: uuid.UUID object.
:type key: uuid.UUID, optional
:param sly_id: Pointcloud tag ID in Supervisely.
:type sly_id: int, optional
:param labeler_login: Login of user who created pointcloud tag.
:type labeler_login: str, optional
:param updated_at: Date and Time when Pointcloud Tag was modified last. Date Format: Year:Month:Day:Hour:Minute:Seconds. Example: '2021-01-22T19:37:50.158Z'.
:type updated_at: str, optional
:param created_at: Date and Time when Pointcloud Tag was created. Date Format is the same as in "updated_at" parameter.
:type created_at: str, optional
:returns: New instance of pointcloud tag.
:rtype: :class:`~supervisely.pointcloud_annotation.pointcloud_tag.PointcloudTag`
:raises ValueError: If pointcloud tag value is incompatible to :class:`~supervisely.annotation.tag_meta.TagMeta` value type.
:Usage Example:
.. code-block:: python
import supervisely as sly
# Original Pointcloud Tag
weather_conditions = ["Sunny", "Cloudy", "Snowy", "Foggy", "Rainy"]
meta_weather = sly.TagMeta("weather", sly.TagValueType.ONEOF_STRING, possible_values=weather_conditions)
tag_weather = sly.PointcloudTag(meta_weather, value="Sunny")
# Let's create some more tags by cloning our original Pointcloud Tag
# Remember that PointcloudTag class object is immutable, and we need to assign new instance of PointcloudTag to a new variable
clone_weather_1 = tag_weather.clone(value="Snowy")
clone_weather_2 = tag_weather.clone(value="Cloudy")
clone_weather_3 = tag_weather.clone(value="Rainy")
"""
return PointcloudTag(
meta=take_with_default(meta, self.meta),
value=take_with_default(value, self.value),
key=take_with_default(key, self.key()),
sly_id=take_with_default(sly_id, self.sly_id),
labeler_login=take_with_default(labeler_login, self.labeler_login),
updated_at=take_with_default(updated_at, self.updated_at),
created_at=take_with_default(created_at, self.created_at),
)