# coding: utf-8
"""Labeling object for :class:`Annotation<supervisely.annotation.annotation.Annotation>`"""
# docs
from __future__ import annotations
from typing import Dict, List, Optional, Tuple, Union
import numpy as np
from PIL.ImageFont import FreeTypeFont
from supervisely._utils import take_with_default
from supervisely.annotation.json_geometries_map import GET_GEOMETRY_FROM_STR
from supervisely.annotation.obj_class import ObjClass
from supervisely.annotation.tag import Tag
from supervisely.annotation.tag_collection import TagCollection
from supervisely.geometry.any_geometry import AnyGeometry
from supervisely.geometry.constants import GEOMETRY_SHAPE, GEOMETRY_TYPE
from supervisely.geometry.geometry import Geometry
from supervisely.geometry.image_rotator import ImageRotator
from supervisely.geometry.multichannel_bitmap import MultichannelBitmap
from supervisely.geometry.rectangle import Rectangle
from supervisely.imaging import font as sly_font
from supervisely.imaging import image as sly_image
from supervisely.project.project_meta import ProjectMeta
[docs]class LabelJsonFields:
"""Json fields for :class:`Annotation<supervisely.annotation.label.Label>`"""
OBJ_CLASS_NAME = "classTitle"
""""""
OBJ_CLASS_ID = "classId"
""""""
DESCRIPTION = "description"
""""""
TAGS = "tags"
""""""
INSTANCE_KEY = "instance"
""""""
class LabelBase:
"""
Labeling object for :class:`Annotation<supervisely.annotation.annotation.Annotation>`. :class:`Label<Label>` object is immutable.
:param geometry: Label :class:`geometry<supervisely.geometry.geometry.Geometry>`.
:type geometry: Geometry
:param obj_class: Label :class:`class<supervisely.annotation.obj_class.ObjClass>`.
:type obj_class: ObjClass
:param tags: Label :class:`tags<supervisely.annotation.tag_collection.TagCollection>`.
:type tags: TagCollection or List[Tag]
:param description: Label description.
:type description: str, optional
:Usage example:
.. code-block:: python
import supervisely as sly
# Simple Label example
class_kiwi = sly.ObjClass('kiwi', sly.Rectangle)
figure = sly.Rectangle(0, 0, 300, 300)
label_kiwi = sly.Label(figure, class_kiwi)
# More complex Label example
# Tag
meta_kiwi = sly.TagMeta('kiwi_tag', sly.TagValueType.ANY_STRING)
tag_kiwi = sly.Tag(meta_kiwi, 'Hello')
# ObjClass
class_kiwi = sly.ObjClass('kiwi', sly.Rectangle)
# Label
geometry_figure = sly.Rectangle(0, 0, 300, 300)
label = sly.Label(figure, class_kiwi, sly.TagCollection([tag_kiwi]), 'Label description')
# or sly.Label(figure, class_kiwi, [tag_kiwi], 'Label description')
"""
def __init__(
self,
geometry: Geometry,
obj_class: ObjClass,
tags: Optional[Union[TagCollection, List[Tag]]] = None,
description: Optional[str] = "",
binding_key=None,
):
self._geometry = geometry
self._obj_class = obj_class
self._tags = take_with_default(tags, TagCollection())
self._description = description
self._validate_geometry_type()
self._validate_geometry()
if not isinstance(tags, TagCollection):
self._tags = TagCollection(tags)
self._binding_key = binding_key
def _validate_geometry(self):
"""
The function checks the name of the Object for compliance.
:return: generate ValueError error if name is mismatch
"""
self._geometry.validate(
self._obj_class.geometry_type.geometry_name(), self.obj_class.geometry_config
)
def _validate_geometry_type(self):
raise NotImplementedError()
@property
def obj_class(self) -> ObjClass:
"""
ObjClass of the current Label.
:return: ObjClass object
:rtype: :class:`ObjClass<supervisely.annotation.obj_class.ObjClass>`
:Usage example:
.. code-block:: python
class_dog = sly.ObjClass('dog', sly.Rectangle)
label_dog = sly.Label(sly.Rectangle(150, 150, 400, 500), class_dog)
label_dog_json = label_dog.obj_class.to_json()
print(label_dog_json)
# Output: {
# "title": "dog",
# "shape": "rectangle",
# "color": "#0F8A12",
# "geometry_config": {},
# "hotkey": ""
# }
"""
return self._obj_class
@property
def description(self) -> str:
"""
Description of the current Label.
:return: Description
:rtype: :class:`str`
:Usage example:
.. code-block:: python
class_dog = sly.ObjClass('dog', sly.Rectangle)
label_dog = sly.Label(sly.Rectangle(150, 150, 400, 500), class_dog, description="Insert Label description here")
print(label_dog.description)
# Output: 'Insert Label description here'
"""
return self._description
@property
def geometry(self) -> Geometry:
"""
Geometry of the current Label.
:return: Geometry object
:rtype: :class:`Geometry<supervisely.geometry>`
:Usage example:
.. code-block:: python
class_dog = sly.ObjClass('dog', sly.Rectangle)
label_dog = sly.Label(sly.Rectangle(150, 150, 400, 500), class_dog)
label_json = label_dog.geometry.to_json()
print(label_json)
# Output: {
# "points": {
# "exterior": [
# [
# 150,
# 150
# ],
# [
# 500,
# 400
# ]
# ],
# "interior": []
# }
# }
"""
return self._geometry
@property
def tags(self) -> TagCollection:
"""
TagCollection of the current Label.
:return: TagCollection object
:rtype: :class:`TagCollection<supervisely.annotation.tag.TagCollection>`
:Usage example:
.. code-block:: python
meta_dog = sly.TagMeta('dog', sly.TagValueType.ANY_STRING)
tag_dog = sly.Tag(meta_dog, 'Woof')
class_dog = sly.ObjClass('dog', sly.Rectangle)
label_dog = sly.Label(sly.Rectangle(100, 100, 700, 900), class_dog, sly.TagCollection([tag_dog]))
label_dog_json = label_dog.tags.to_json()
print(label_dog_json)
# Output: [
# {
# "name": "dog",
# "value": "Woof"
# }
# ]
"""
return self._tags.clone()
def to_json(self) -> Dict:
"""
Convert the Label to a json dict. Read more about `Supervisely format <https://docs.supervise.ly/data-organization/00_ann_format_navi>`_.
:return: Json format as a dict
:rtype: :class:`dict`
:Usage example:
.. code-block:: python
import supervisely as sly
meta_dog = sly.TagMeta('dog', sly.TagValueType.ANY_STRING)
tag_dog = sly.Tag(meta_dog, 'Woof')
class_dog = sly.ObjClass('dog', sly.Rectangle)
label_dog = sly.Label(sly.Rectangle(100, 100, 700, 900), class_dog, sly.TagCollection([tag_dog]), description='Insert Label description here')
label_dog_json = label_dog.to_json()
print(label_dog_json)
# Output: {
# "classTitle": "dog",
# "description": "",
# "tags": [
# {
# "name": "dog",
# "value": "Woof"
# }
# ],
# "points": {
# "exterior": [[100, 100],[900, 700]],
# "interior": []
# },
# "geometryType": "rectangle",
# "shape": "rectangle"
# }
"""
res = {
LabelJsonFields.OBJ_CLASS_NAME: self.obj_class.name,
LabelJsonFields.DESCRIPTION: self.description,
LabelJsonFields.TAGS: self.tags.to_json(),
**self.geometry.to_json(),
GEOMETRY_TYPE: self.geometry.geometry_name(),
GEOMETRY_SHAPE: self.geometry.geometry_name(),
}
if self.obj_class.sly_id is not None:
res[LabelJsonFields.OBJ_CLASS_ID] = self.obj_class.sly_id
if self.binding_key is not None:
res[LabelJsonFields.INSTANCE_KEY] = self.binding_key
return res
@classmethod
def from_json(cls, data: Dict, project_meta: ProjectMeta) -> LabelBase:
"""
Convert a json dict to Label. Read more about `Supervisely format <https://docs.supervise.ly/data-organization/00_ann_format_navi>`_.
:param data: Label in json format as a dict.
:type data: dict
:param project_meta: Input ProjectMeta.
:type project_meta: ProjectMeta
:return: Label object
:rtype: :class:`Label<LabelBase>`
:Usage example:
.. code-block:: python
import supervisely as sly
address = 'https://app.supervise.ly/'
token = 'Your Supervisely API Token'
api = sly.Api(address, token)
meta = api.project.get_meta(PROJECT_ID)
data = {
"classTitle": "dog",
"tags": [
{
"name": "dog",
"value": "Woof"
}
],
"points": {
"exterior": [[100, 100], [900, 700]],
"interior": []
}
}
label_dog = sly.Label.from_json(data, 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 Label object from JSON: "
f"label class name {obj_class_name} was not found in the given project meta."
)
if obj_class.geometry_type is AnyGeometry:
geometry_type_actual = GET_GEOMETRY_FROM_STR(
data[GEOMETRY_TYPE] if GEOMETRY_TYPE in data else data[GEOMETRY_SHAPE]
)
geometry = geometry_type_actual.from_json(data)
else:
geometry = obj_class.geometry_type.from_json(data)
binding_key = data.get(LabelJsonFields.INSTANCE_KEY)
return cls(
geometry=geometry,
obj_class=obj_class,
tags=TagCollection.from_json(data[LabelJsonFields.TAGS], project_meta.tag_metas),
description=data.get(LabelJsonFields.DESCRIPTION, ""),
binding_key=binding_key,
)
def add_tag(self, tag: Tag) -> LabelBase:
"""
Adds Tag to the current Label.
:param tag: Tag to be added.
:type tag: Tag
:return: Label object
:rtype: :class:`Label<LabelBase>`
:Usage example:
.. code-block:: python
import supervisely as sly
# Create label
class_dog = sly.ObjClass('dog', sly.Rectangle)
label_dog = sly.Label(sly.Rectangle(0, 0, 500, 600), class_dog)
# Create tag
meta_dog = sly.TagMeta('dog', sly.TagValueType.NONE)
tag_dog = sly.Tag(meta_dog)
# Add Tag
# Remember that Label object is immutable, and we need to assign new instance of Label to a new variable
new_label = label_dog.add_tag(tag_dog)
"""
return self.clone(tags=self._tags.add(tag))
def add_tags(self, tags: List[Tag]) -> LabelBase:
"""
Adds multiple Tags to the current Label.
:param tags: List of Tags to be added.
:type tags: List[Tag]
:return: Label object
:rtype: :class:`Label<LabelBase>`
:Usage example:
.. code-block:: python
import supervisely as sly
# Create label
class_dog = sly.ObjClass('dog', sly.Rectangle)
label_dog = sly.Label(sly.Rectangle(0, 0, 500, 600), class_dog)
# Create tags
meta_dog = sly.TagMeta('dog', sly.TagValueType.NONE)
tag_dog = sly.Tag(meta_dog)
meta_cat = sly.TagMeta('cat', sly.TagValueType.NONE)
tag_cat = sly.Tag(meta_cat)
tags_arr = [tag_dog, tag_cat]
# Add Tags
# Remember that Label object is immutable, and we need to assign new instance of Label to a new variable
new_label = label_dog.add_tags(tags_arr)
"""
return self.clone(tags=self._tags.add_items(tags))
def clone(
self,
geometry: Optional[Geometry] = None,
obj_class: Optional[ObjClass] = None,
tags: Optional[Union[TagCollection, List[Tag]]] = None,
description: Optional[str] = None,
binding_key: Optional[str] = None,
) -> LabelBase:
"""
Makes a copy of Label with new fields, if fields are given, otherwise it will use fields of the original Label.
:param geometry: Label :class:`geometry<supervisely.geometry.geometry.Geometry>`.
:type geometry: Geometry
:param obj_class: Label :class:`class<supervisely.annotation.obj_class.ObjClass>`.
:type obj_class: ObjClass
:param tags: Label :class:`tags<supervisely.annotation.tag.TagCollection>`.
:type tags: TagCollection or List[Tag]
:param description: Label description.
:type description: str, optional
:return: New instance of Label
:rtype: :class:`Label<LabelBase>`
:Usage example:
.. code-block:: python
import supervisely as sly
import numpy as np
# Original Label
class_dog = sly.ObjClass('dog', sly.Rectangle)
label_dog = sly.Label(sly.Rectangle(150, 150, 500, 400), class_dog)
# Let's clone our Label, but with different Geometry coordinates
# Remember that Label object is immutable, and we need to assign new instance of Label to a new variable
clone_label_dog = label_dog.clone(sly.Rectangle(100, 100, 500, 500), class_dog)
# Let's clone our Label with new TagCollection and description
meta_breed = sly.TagMeta('breed', sly.TagValueType.ANY_STRING)
tag_breed = sly.Tag(meta_breed, 'German Shepherd')
tags = sly.TagCollection([tag_breed])
# Remember that Label object is immutable, and we need to assign new instance of Label to a new variable
clone_label_dog_2 = label_dog.clone(tags=tags, description='Dog breed german shepherd')
# Note that you can't clone Label if ObjClass geometry type differ from the new given geometry
mask = np.array([[0, 0, 0, 0, 0],
[0, 1, 1, 1, 0],
[0, 1, 0, 1, 0],
[0, 1, 1, 1, 0],
[0, 0, 0, 0, 0]], dtype=np.uint8)
mask_bool = mask==1
clone_label_dog = label_dog.clone(sly.Label(sly.Bitmap(mask_bool), class_dog))
# In this case RuntimeError will be raised
"""
return self.__class__(
geometry=take_with_default(geometry, self.geometry),
obj_class=take_with_default(obj_class, self.obj_class),
tags=take_with_default(tags, self.tags),
description=take_with_default(description, self.description),
binding_key=take_with_default(binding_key, self.binding_key),
)
def crop(self, rect: Rectangle) -> List[LabelBase]:
"""
Clones the current Label and crops it. Mostly used for internal implementation. See usage example in :class:`Annotation<supervisely.annotation.annotation.Annotation.crop_labels>`.
:param rect: Rectangle object.
:type rect: Rectangle
:return: List of Labels with new geometries
:rtype: :class:`List[Label]<LabelBase>`
"""
if rect.contains(self.geometry.to_bbox()):
return [self]
else:
# for compatibility of old slightly invalid annotations, some of them may be out of image bounds.
# will correct it automatically
result_geometries = self.geometry.crop(rect)
if len(result_geometries) == 1:
result_geometries[0]._copy_creation_info_inplace(self.geometry)
return [self.clone(geometry=result_geometries[0])]
else:
return [self.clone(geometry=g) for g in self.geometry.crop(rect)]
def relative_crop(self, rect: Rectangle) -> List[LabelBase]:
"""
Clones the current Label and crops it, but return results with coordinates relative to the given Rectangle. Mostly used for internal implementation. See usage example in :class:`Annotation<supervisely.annotation.annotation.Annotation.relative_crop>`.
:param rect: Rectangle object.
:type rect: Rectangle
:return: List of Labels with new geometries
:rtype: :class:`List[Label]<LabelBase>`
"""
return [self.clone(geometry=g) for g in self.geometry.relative_crop(rect)]
def rotate(self, rotator: ImageRotator) -> LabelBase:
"""
Clones the current Label and rotates it. Mostly used for internal implementation. See usage example in :class:`Annotation<supervisely.annotation.annotation.Annotation.rotate>`.
:param rotator: ImageRotator object.
:type rotator: ImageRotator
:return: New instance of Label with rotated geometry
:rtype: :class:`Label<LabelBase>`
"""
return self.clone(geometry=self.geometry.rotate(rotator))
def resize(self, in_size: Tuple[int, int], out_size: Tuple[int, int]) -> LabelBase:
"""
Clones the current Label and resizes it. Mostly used for internal implementation. See usage example in :class:`Annotation<supervisely.annotation.annotation.Annotation.resize>`.
:param in_size: Input image size (height, width) of the Annotation to which Label belongs.
:type in_size: Tuple[int, int]
:param out_size: Desired output image size (height, width) of the Annotation to which Label belongs.
:type out_size: Tuple[int, int]
:return: New instance of Label with resized geometry
:rtype: :class:`Label<LabelBase>`
"""
return self.clone(geometry=self.geometry.resize(in_size, out_size))
def scale(self, factor: float) -> LabelBase:
"""
Clones the current Label and scales it. Mostly used for internal implementation. See usage example in :class:`Annotation<supervisely.annotation.annotation.Annotation.scale>`.
:param factor: Scale factor.
:type factor: float
:return: New instance of Label with scaled geometry
:rtype: :class:`Label<LabelBase>`
"""
return self.clone(geometry=self.geometry.scale(factor))
def translate(self, drow: int, dcol: int) -> LabelBase:
"""
Clones the current Label and shifts it by a certain number of pixels. Mostly used for internal implementation.
:param drow: Horizontal shift.
:type drow: int
:param dcol: Vertical shift.
:type dcol: int
:return: New instance of Label with translated geometry
:rtype: :class:`Label<LabelBase>`
:Usage example:
.. code-block:: python
import supervisely as sly
address = 'https://app.supervise.ly/'
token = 'Your Supervisely API Token'
api = sly.Api(address, token)
# Get image and annotation from API
project_id = 117139
image_id = 194190568
meta_json = api.project.get_meta(project_id)
meta = sly.ProjectMeta.from_json(meta_json)
ann_info = api.annotation.download(image_id)
ann = sly.Annotation.from_json(ann_info.annotation, meta)
img = api.image.download_np(image_id)
new_img = copy.deepcopy(img)
ann.draw_pretty(img, thickness=3) # before
# Translate label with name 'lemon'
new_labels = []
for label in ann.labels:
if label.obj_class.name == 'lemon':
translate_label = label.translate(250, -350)
new_labels.append(translate_label)
else:
new_labels.append(label)
ann = ann.clone(labels=new_labels)
ann.draw_pretty(new_img, thickness=3) # after
"""
return self.clone(geometry=self.geometry.translate(drow=drow, dcol=dcol))
def fliplr(self, img_size: Tuple[int, int]) -> LabelBase:
"""
Clones the current Label and flips it horizontally. Mostly used for internal implementation. See usage example in :class:`Annotation<supervisely.annotation.annotation.Annotation.fliplr>`.
:param img_size: Input image size (height, width) of the Annotation to which Label belongs.
:type img_size: Tuple[int, int]
:return: New instance of Label with flipped geometry
:rtype: :class:`Label<LabelBase>`
"""
return self.clone(geometry=self.geometry.fliplr(img_size))
def flipud(self, img_size: Tuple[int, int]) -> LabelBase:
"""
Clones the current Label and flips it vertically. Mostly used for internal implementation. See usage example in :class:`Annotation<supervisely.annotation.annotation.Annotation.flipud>`.
:param img_size: Input image size (height, width) of the Annotation to which Label belongs.
:type img_size: Tuple[int, int]
:return: New instance of Label with flipped geometry
:rtype: :class:`Label<LabelBase>`
"""
return self.clone(geometry=self.geometry.flipud(img_size))
def _get_font(self, img_size):
"""
The function get size of font for image with given size
:return: font for drawing
"""
return sly_font.get_font(font_size=sly_font.get_readable_font_size(img_size))
def _draw_tags(self, bitmap, font, add_class_name=False):
bbox = self.geometry.to_bbox()
texts = [t.get_compact_str() for t in self.tags]
texts = texts if add_class_name is False else [self.obj_class.name] + texts
sly_image.draw_text_sequence(
bitmap=bitmap,
texts=texts,
anchor_point=(bbox.top, bbox.left),
corner_snap=sly_image.CornerAnchorMode.BOTTOM_LEFT,
font=font,
)
def _draw_class_name(self, bitmap, font):
bbox = self.geometry.to_bbox()
sly_image.draw_text(
bitmap,
self.obj_class.name,
(bbox.top, bbox.left),
corner_snap=sly_image.CornerAnchorMode.BOTTOM_LEFT,
font=font,
)
def draw(
self,
bitmap: np.ndarray,
color: Optional[List[int, int, int]] = None,
thickness: Optional[int] = 1,
draw_tags: Optional[bool] = False,
tags_font: Optional[FreeTypeFont] = None,
draw_class_name: Optional[bool] = False,
class_name_font: Optional[FreeTypeFont] = None,
) -> None:
"""
Draws current Label on image. Modifies Mask. Mostly used for internal implementation. See usage example in :class:`Annotation<supervisely.annotation.annotation.Annotation.draw>`.
:param bitmap: image.
:type bitmap: np.ndarray
:param color: Drawing color in :class:`[R, G, B]`.
:type color: List[int, int, int], optional
:param thickness: Thickness of the drawing figure.
:type thickness: int, optional
:param draw_tags: Determines whether to draw tags on bitmap or not.
:type draw_tags: bool, optional
:param tags_font: Font of tags to be drawn, uses `FreeTypeFont <https://pillow.readthedocs.io/en/stable/reference/ImageFont.html#PIL.ImageFont.FreeTypeFont>`_ from `PIL <https://pillow.readthedocs.io/en/stable/index.html>`_.
:type tags_font: FreeTypeFont, optional
:param draw_class_name: Draw the class name on the bitmap. If the draw_tags parameter is set to True, the class name will use the same font as the tags_font.
:type draw_class_name: bool, optional
:param class_name_font: Font of class name to be drawn, uses `FreeTypeFont <https://pillow.readthedocs.io/en/stable/reference/ImageFont.html#PIL.ImageFont.FreeTypeFont>`_ from `PIL <https://pillow.readthedocs.io/en/stable/index.html>`_.
:type class_name_font: FreeTypeFont, optional
:return: :class:`None<None>`
:rtype: :class:`NoneType<NoneType>`
"""
effective_color = take_with_default(color, self.obj_class.color)
self.geometry.draw(
bitmap, effective_color, thickness, config=self.obj_class.geometry_config
)
if draw_tags:
if tags_font is None:
tags_font = self._get_font(bitmap.shape[:2])
self._draw_tags(bitmap, tags_font, add_class_name=draw_class_name)
elif draw_class_name:
if class_name_font is None:
class_name_font = self._get_font(bitmap.shape[:2])
self._draw_class_name(bitmap, class_name_font)
def get_mask(self, img_size: Tuple[int, int]) -> np.ndarray:
"""Returns 2D boolean mask of the label.
With shape as img_size (height, width) and filled
with True values inside the label and False values outside.
dtype = np.bool
shape = img_size
:param img_size: size of the image (height, width)
:type img_size: Tuple[int, int]
:return: 2D boolean mask of the Label
:rtype: np.ndarray
"""
bitmap = np.zeros(img_size + (3,), dtype=np.uint8)
self.draw(bitmap, thickness=-1, color=[255, 255, 255])
return np.any(bitmap != 0, axis=-1)
def draw_contour(
self,
bitmap: np.ndarray,
color: Optional[List[int, int, int]] = None,
thickness: Optional[int] = 1,
draw_tags: Optional[bool] = False,
tags_font: Optional[FreeTypeFont] = None,
draw_class_name: Optional[bool] = False,
class_name_font: Optional[FreeTypeFont] = None,
) -> None:
"""
Draws Label geometry contour on the given image. Modifies mask. Mostly used for internal implementation. See usage example in :class:`Annotation<supervisely.annotation.annotation.Annotation.draw_contour>`.
:param bitmap: image.
:type bitmap: np.ndarray
:param color: Drawing color in :class:`[R, G, B]`.
:type color: List[int, int, int], optional
:param thickness: Thickness of the drawn contour.
:type thickness: int, optional
:param draw_tags: Determines whether to draw tags on bitmap or not.
:type draw_tags: bool, optional
:param tags_font: Font of tags to be drawn, uses `FreeTypeFont <https://pillow.readthedocs.io/en/stable/reference/ImageFont.html#PIL.ImageFont.FreeTypeFont>`_ from `PIL <https://pillow.readthedocs.io/en/stable/index.html>`_.
:type tags_font: FreeTypeFont, optional
:param draw_class_name: Draw the class name on the bitmap. If the draw_tags parameter is set to True, the class name will use the same font as the tags_font.
:type draw_class_name: bool, optional
:param class_name_font: Font of class name to be drawn, uses `FreeTypeFont <https://pillow.readthedocs.io/en/stable/reference/ImageFont.html#PIL.ImageFont.FreeTypeFont>`_ from `PIL <https://pillow.readthedocs.io/en/stable/index.html>`_.
:type class_name_font: FreeTypeFont, optional
:return: :class:`None<None>`
:rtype: :class:`NoneType<NoneType>`
"""
effective_color = take_with_default(color, self.obj_class.color)
self.geometry.draw_contour(
bitmap, effective_color, thickness, config=self.obj_class.geometry_config
)
if draw_tags:
if tags_font is None:
tags_font = self._get_font(bitmap.shape[:2])
self._draw_tags(bitmap, tags_font, add_class_name=draw_class_name)
elif draw_class_name:
if class_name_font is None:
class_name_font = self._get_font(bitmap.shape[:2])
self._draw_class_name(bitmap, class_name_font)
@property
def area(self) -> float:
"""
Label area.
:return: Area of current geometry in Label.
:rtype: :class:`float`
:Usage example:
.. code-block:: python
import supervisely as sly
# Create label
class_dog = sly.ObjClass('dog', sly.Rectangle)
label_dog = sly.Label(sly.Rectangle(0, 0, 500, 600), class_dog)
figure_area = label_dog.area
print(figure_area)
# Output: 301101.0
"""
return self.geometry.area
def convert(self, new_obj_class: ObjClass) -> List[LabelBase]:
"""
Converts Label geometry to another geometry shape.
:param new_obj_class: ObjClass with new geometry shape.
:type new_obj_class: ObjClass
:return: List of Labels with converted geometries
:rtype: :class:`List[Label]<LabelBase>`
:Usage example:
.. code-block:: python
import supervisely as sly
# Create label
class_dog = sly.ObjClass('dog', sly.Rectangle)
label_dog = sly.Label(sly.Rectangle(0, 0, 500, 600), class_dog)
print(label_dog.geometry.to_json())
# {'geometryType': 'rectangle'}
label_cat = sly.ObjClass('cat', sly.Bitmap)
convert_label = label_dog.convert(label_cat)
for label_bitmap in convert_label:
print(label_bitmap.geometry.to_json())
# Output: {'geometryType': 'bitmap'}
"""
labels = []
geometries = self.geometry.convert(new_obj_class.geometry_type)
for g in geometries:
labels.append(self.clone(geometry=g, obj_class=new_obj_class))
return labels
@property
def binding_key(self):
return self._binding_key
@binding_key.setter
def binding_key(self, key: Union[str, None]):
if key is not None and type(key) is not str:
raise TypeError("Key has to be of type string or None")
self._binding_key = key
@property
def labeler_login(self):
return self.geometry.labeler_login
[docs]class Label(LabelBase):
def _validate_geometry_type(self):
"""
Checks geometry type for correctness
"""
if self._obj_class.geometry_type != AnyGeometry:
if type(self._geometry) is not self._obj_class.geometry_type:
raise RuntimeError(
"Input geometry type {!r} != geometry type of ObjClass {}".format(
type(self._geometry), self._obj_class.geometry_type
)
)
class PixelwiseScoresLabel(LabelBase):
def _validate_geometry_type(self):
if type(self._geometry) is not MultichannelBitmap:
raise RuntimeError(
"Input geometry type {!r} != geometry type of ObjClass {}".format(
type(self._geometry), MultichannelBitmap
)
)