# coding: utf-8
from __future__ import annotations
from typing import List, Dict, Optional
import uuid
from bidict import bidict
from supervisely.annotation.label import LabelJsonFields
from supervisely.annotation.obj_class import ObjClass
from supervisely.project.project_meta import ProjectMeta
from supervisely._utils import take_with_default
from supervisely.video_annotation.constants import KEY, ID, OBJECTS_MAP
from supervisely.video_annotation.video_tag_collection import VideoTagCollection
from supervisely.video_annotation.video_tag import VideoTag
from supervisely.collection.key_indexed_collection import KeyObject
from supervisely.video_annotation.key_id_map import KeyIdMap
from supervisely.geometry.constants import (
LABELER_LOGIN,
UPDATED_AT,
CREATED_AT,
CLASS_ID,
)
[docs]class VideoObject(KeyObject):
"""
VideoObject object for :class:`VideoAnnotation<supervisely.video_annotation.video_annotation.VideoAnnotation>`. :class:`VideoObject<VideoObject>` object is immutable.
:param obj_class: VideoObject :class:`class<supervisely.annotation.obj_class.ObjClass>`.
:type obj_class: ObjClass
:param tags: VideoObject :class:`tags<supervisely.video_annotation.video_tag_collection.VideoTagCollection>`.
:type tags: VideoTagCollection, optional
:param key: KeyIdMap object.
:type key: KeyIdMap, optional
:param class_id: ID of :class:`ObjClass<supervisely.annotation.obj_class.ObjClass>` to which VideoObject belongs.
:type class_id: int, optional
:param labeler_login: Login of the user who created VideoObject.
:type labeler_login: str, optional
:param updated_at: Date and Time when VideoObject 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 VideoObject was created. Date Format is the same as in "updated_at" parameter.
:type created_at: str, optional
:Usage example:
.. code-block:: python
import supervisely as sly
obj_class_car = sly.ObjClass('car', sly.Rectangle)
video_obj_car = sly.VideoObject(obj_class_car)
video_obj_car_json = video_obj_car.to_json()
print(video_obj_car_json)
# Output: {
# "key": "6b819f1840f84d669b32cdec225385f0",
# "classTitle": "car",
# "tags": []
# }
"""
def __init__(self, obj_class: ObjClass, tags: Optional[VideoTagCollection] = None, key: Optional[uuid.UUID]=None,
class_id: Optional[int]=None, labeler_login: Optional[str]=None, updated_at: Optional[str]=None,
created_at: Optional[str]=None):
self.labeler_login = labeler_login
self.updated_at = updated_at
self.created_at = created_at
self._obj_class = obj_class
self._key = take_with_default(key, uuid.uuid4())
self._tags = take_with_default(tags, VideoTagCollection())
self._class_id = take_with_default(class_id, None)
def _add_creation_info(self, d):
if self.labeler_login is not None:
d[LABELER_LOGIN] = self.labeler_login
if self.updated_at is not None:
d[UPDATED_AT] = self.updated_at
if self.created_at is not None:
d[CREATED_AT] = self.created_at
@property
def obj_class(self) -> ObjClass:
"""
ObjClass of the current VideoObject.
:return: ObjClass object
:rtype: :class:`ObjClass<supervisely.annotation.obj_class.ObjClass>`
:Usage example:
.. code-block:: python
import supervisely as sly
obj_class_car = sly.ObjClass('car', sly.Rectangle)
video_obj_car = sly.VideoObject(obj_class_car)
obj_car_json = video_obj_car.obj_class.to_json()
print(obj_car_json)
# Output: {
# "title": "car",
# "shape": "rectangle",
# "color": "#8A0F7B",
# "geometry_config": {},
# "hotkey": ""
# }
"""
return self._obj_class
[docs] def key(self) -> uuid.UUID:
"""
Object key.
:return: Object key
:rtype: uuid.UUID
:Usage example:
.. code-block:: python
import supervisely as sly
obj_class_car = sly.ObjClass('car', sly.Rectangle)
video_obj_car = sly.VideoObject(obj_class_car)
key = video_obj_car.key()
print(key)
# Output: 158e6cf4f4ac4c639fc6994aad127c16
"""
return self._key
@property
def tags(self) -> VideoTagCollection:
"""
VideoTagCollection of the current VideoObject.
:return: VideoTagCollection object
:rtype: :class:`VideoTagCollection<supervisely.video_annotation.video_tag_collection.VideoTagCollection>`
:Usage example:
.. code-block:: python
import supervisely as sly
# Create VideoTagCollection
meta_car = sly.TagMeta('car_tag', sly.TagValueType.ANY_STRING)
from supervisely.video_annotation.video_tag import VideoTag
car_tag = VideoTag(meta_car, value='acura')
from supervisely.video_annotation.video_tag_collection import VideoTagCollection
video_tags = VideoTagCollection([car_tag])
# Create VideoObject
obj_class_car = sly.ObjClass('car', sly.Rectangle)
video_obj_car = sly.VideoObject(obj_class_car, video_tags)
# Get VideoTagCollection
tags = video_obj_car.tags
tags_json = tags.to_json()
print(tags_json)
# Output: [
# {
# "name": "car_tag",
# "value": "acura",
# "key": "4f82fbcab74c44259d7a0e29d604602e"
# }
# ]
"""
return self._tags.clone()
@property
def class_id(self) -> int:
"""
Object class ID.
:return: Object class ID.
:rtype: int
:Usage example:
.. code-block:: python
import supervisely as sly
obj_class_car = sly.ObjClass('car', sly.Rectangle)
video_obj_car = sly.VideoObject(obj_class_car)
class_id = video_obj_car.class_id
"""
return self._class_id
[docs] def add_tag(self, tag: VideoTag) -> VideoObject:
"""
Adds VideoTag to the current VideoObject.
:param tag: VideoTag to be added.
:type tag: VideoTag
:return: VideoObject object
:rtype: :class:`VideoObject<VideoObject>`
:Usage example:
.. code-block:: python
import supervisely as sly
# Create VideoObject
obj_class_car = sly.ObjClass('car', sly.Rectangle)
video_obj_car = sly.VideoObject(obj_class_car)
# Create VideoTag
meta_car = sly.TagMeta('car_tag', sly.TagValueType.ANY_STRING)
from supervisely.video_annotation.video_tag import VideoTag
car_tag = VideoTag(meta_car, value='acura')
# Add VideoTag
new_obj_car = video_obj_car.add_tag(car_tag)
new_obj_car_json = new_obj_car.to_json()
print(new_obj_car_json)
# Output: {
# "key": "1ab52285ee634c93b724fa655b785eae",
# "classTitle": "car",
# "tags": [
# {
# "name": "car_tag",
# "value": "acura",
# "key": "d9e52b275e074c538f162a6d679aed9e"
# }
# ]
# }
"""
return self.clone(tags=self._tags.add(tag))
[docs] def to_json(self, key_id_map: Optional[KeyIdMap] = None) -> Dict:
"""
Convert the VideoObject to a json dict. Read more about `Supervisely format <https://docs.supervise.ly/data-organization/00_ann_format_navi>`_.
:param key_id_map: KeyIdMap object.
:type key_id_map: KeyIdMap, optional
:return: Json format as a dict
:rtype: :class:`dict`
:Usage example:
.. code-block:: python
import supervisely as sly
obj_class_car = sly.ObjClass('vehicle', sly.Rectangle)
video_obj_car = sly.VideoObject(obj_class_car)
obj_car_json = video_obj_car.to_json()
print(obj_car_json)
# Output: {
# "key": "ce26e77a45bc45e88e3e17da1672d01f",
# "classTitle": "vehicle",
# "tags": []
# }
"""
data_json = {
KEY: self.key().hex,
LabelJsonFields.OBJ_CLASS_NAME: self.obj_class.name,
LabelJsonFields.TAGS: self.tags.to_json(key_id_map),
}
if key_id_map is not None:
item_id = key_id_map.get_object_id(self.key())
if item_id is not None:
data_json[ID] = item_id
self._add_creation_info(data_json)
return data_json
[docs] @classmethod
def from_json(cls, data: Dict, project_meta: ProjectMeta, key_id_map: Optional[KeyIdMap] = None) -> VideoObject:
"""
Convert a json dict to VideoObject. Read more about `Supervisely format <https://docs.supervise.ly/data-organization/00_ann_format_navi>`_.
:param data: Dict in json format.
:type data: dict
:param project_meta: Input :class:`ProjectMeta<supervisely.project.project_meta.ProjectMeta>`.
:type project_meta: ProjectMeta
:param key_id_map: KeyIdMap object.
:type key_id_map: KeyIdMap, optional
:raises: :class:`RuntimeError`, if object class name is not found in the given project meta
:return: VideoObject object
:rtype: :class:`VideoObject`
:Usage example:
.. code-block:: python
import supervisely as sly
obj_car_json = {
"classTitle": "vehicle",
"tags": []
}
obj_class_car = sly.ObjClass('vehicle', sly.Rectangle)
obj_collection = sly.ObjClassCollection([obj_class_car])
meta = sly.ProjectMeta(obj_classes=obj_collection)
video_obj_from_json = sly.VideoObject.from_json(obj_car_json, meta)
"""
obj_class_name = data[LabelJsonFields.OBJ_CLASS_NAME]
obj_class = project_meta.get_obj_class(obj_class_name)
if obj_class is None:
raise RuntimeError(
f"Failed to deserialize a object from JSON: class name {obj_class_name!r} "
f"was not found in the given project meta."
)
key = uuid.UUID(data[KEY]) if KEY in data else uuid.uuid4()
if key_id_map is not None:
key_id_map.add_object(key, data.get(ID, None))
class_id = data.get(CLASS_ID, None)
labeler_login = data.get(LABELER_LOGIN, None)
updated_at = data.get(UPDATED_AT, None)
created_at = data.get(CREATED_AT, None)
return cls(
obj_class=obj_class,
key=key,
tags=VideoTagCollection.from_json(
data[LabelJsonFields.TAGS], project_meta.tag_metas
),
class_id=class_id,
labeler_login=labeler_login,
updated_at=updated_at,
created_at=created_at,
)
[docs] def clone(self, obj_class: Optional[ObjClass]=None, tags: Optional[VideoTagCollection] = None, key: Optional[KeyIdMap]=None,
class_id: Optional[int]=None, labeler_login: Optional[str]=None, updated_at: Optional[str]=None, created_at: Optional[str]=None) -> VideoObject:
"""
Makes a copy of VideoObject with new fields, if fields are given, otherwise it will use fields of the original VideoObject.
:param obj_class: VideoObject :class:`class<supervisely.annotation.obj_class.ObjClass>`.
:type obj_class: ObjClass, optional
:param tags: VideoObject :class:`tags<supervisely.video_annotation.video_tag_collection.VideoTagCollection>`.
:type tags: VideoTagCollection, optional
:param key: KeyIdMap object.
:type key: KeyIdMap, optional
:param class_id: ID of :class:`ObjClass<supervisely.annotation.obj_class.ObjClass>` to which VideoObject belongs.
:type class_id: int, optional
:param labeler_login: Login of the user who created VideoObject.
:type labeler_login: str, optional
:param updated_at: Date and Time when VideoObject 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 VideoObject was created. Date Format is the same as in "updated_at" parameter.
:type created_at: str, optional
:return: VideoObject object
:rtype: :class:`VideoObject`
:Usage example:
.. code-block:: python
import supervisely as sly
obj_class_car = sly.ObjClass('vehicle', sly.Rectangle)
video_obj_car = sly.VideoObject(obj_class_car)
# New ObjClass to clone
obj_class_bus = sly.ObjClass('bus', sly.Rectangle)
# New VideoTagCollection to clone
from supervisely.video_annotation.video_tag import VideoTag
meta_car = sly.TagMeta('car_tag', sly.TagValueType.ANY_STRING)
car_tag = VideoTag(meta_car, value='acura')
from supervisely.video_annotation.video_tag_collection import VideoTagCollection
tags = VideoTagCollection([car_tag])
# Clone
new_obj_vehicle = video_obj_car.clone(obj_class=obj_class_bus, tags=tags)
new_obj_vehicle_json = new_obj_vehicle.to_json()
print(new_obj_vehicle_json)
# Output: {
# "key": "39ae5b9ce1ca405c9f53544374b3f5be",
# "classTitle": "bus",
# "tags": [
# {
# "name": "car_tag",
# "value": "acura",
# "key": "3119b6e38fe24fe7a220e881154fd9ba"
# }
# ]
# }
"""
return self.__class__(obj_class=take_with_default(obj_class, self.obj_class),
key=take_with_default(key, self._key),
tags=take_with_default(tags, self.tags),
class_id=take_with_default(class_id, self.class_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))