Skip to content

Commit

Permalink
feat(label): add "LabeledMultiPolygon" & "MultiPolygonSubcatalog"
Browse files Browse the repository at this point in the history
  • Loading branch information
edsn60 committed Jul 16, 2021
1 parent b447e64 commit d5b4f05
Show file tree
Hide file tree
Showing 8 changed files with 326 additions and 10 deletions.
6 changes: 3 additions & 3 deletions tensorbay/geometry/polygon.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ class MultiPolygon(MultiPointList2D[Polygon]): # pylint: disable=too-many-ances
Examples:
>>> MultiPolygon([[[1.0, 4.0], [2.0, 3.7], [7.0, 4.0]],
[[5.0, 7.0], [6.0, 7.0], [9.0, 8.0]]])
... [[5.0, 7.0], [6.0, 7.0], [9.0, 8.0]]])
MultiPolygon [
Polygon [...]
Polygon [...]
Expand Down Expand Up @@ -122,7 +122,7 @@ def loads(cls: Type[_P], contents: List[List[Dict[str, float]]]) -> _P:
Examples:
>>> contents = [[{'x': 1.0, 'y': 4.0}, {'x': 2.0, 'y': 3.7}, {'x': 7.0, 'y': 4.0}],
[{'x': 5.0, 'y': 7.0}, {'x': 6.0, 'y': 7.0}, {'x': 9.0, 'y': 8.0}]]
... [{'x': 5.0, 'y': 7.0}, {'x': 6.0, 'y': 7.0}, {'x': 9.0, 'y': 8.0}]]
>>> multipolygon = MultiPolygon.loads(contents)
>>> multipolygon
MultiPolygon [
Expand All @@ -142,7 +142,7 @@ def dumps(self) -> List[List[Dict[str, float]]]:
Examples:
>>> multipolygon = MultiPolygon([[[1.0, 4.0], [2.0, 3.7], [7.0, 4.0]],
>>> [[5.0, 7.0], [6.0, 7.0], [9.0, 8.0]]])
... [[5.0, 7.0], [6.0, 7.0], [9.0, 8.0]]])
>>> multipolygon.dumps()
[
[{'x': 1.0, 'y': 4.0}, {'x': 2.0, 'y': 3.7}, {'x': 7.0, 'y': 4.0}],
Expand Down
11 changes: 9 additions & 2 deletions tensorbay/label/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@
from .label_box import Box2DSubcatalog, Box3DSubcatalog, LabeledBox2D, LabeledBox3D
from .label_classification import Classification, ClassificationSubcatalog
from .label_keypoints import Keypoints2DSubcatalog, LabeledKeypoints2D
from .label_polygon import LabeledPolygon, PolygonSubcatalog
from .label_polygon import (
LabeledMultiPolygon,
LabeledPolygon,
MultiPolygonSubcatalog,
PolygonSubcatalog,
)
from .label_polyline import (
LabeledMultiPolyline2D,
LabeledPolyline2D,
Expand All @@ -30,7 +35,6 @@
"CategoryInfo",
"Classification",
"ClassificationSubcatalog",
"Items",
"Keypoints2DSubcatalog",
"KeypointsInfo",
"Label",
Expand All @@ -43,6 +47,9 @@
"LabeledPolyline2D",
"LabeledSentence",
"MultiPolyline2DSubcatalog",
"LabeledMultiPolygon",
"Items",
"MultiPolygonSubcatalog",
"PolygonSubcatalog",
"Polyline2DSubcatalog",
"SentenceSubcatalog",
Expand Down
1 change: 1 addition & 0 deletions tensorbay/label/basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class LabelType(TypeEnum):
POLYLINE2D = "polyline2d"
MULTI_POLYLINE2D = "multi_polyline2d"
KEYPOINTS2D = "keypoints2d"
MULTI_POLYGON = "multi_polygon"
SENTENCE = "sentence"

@property
Expand Down
5 changes: 4 additions & 1 deletion tensorbay/label/catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
:class:`.Keypoints2DSubcatalog` subcatalog for 2D keypoints type of label
:class:`.PolygonSubcatalog` subcatalog for polygon type of label
:class:`.Polyline2DSubcatalog` subcatalog for 2D polyline type of label
:class:`.MultiPolygonSubcatalog` subcatalog for multiple polygon type of label
:class:`.MultiPolyline2DSubcatalog` subcatalog for 2D multiple polyline type of label
:class:`.SentenceSubcatalog` subcatalog for transcripted sentence type of label
=================================== ==================================================
Expand All @@ -38,7 +39,7 @@
from .label_box import Box2DSubcatalog, Box3DSubcatalog
from .label_classification import ClassificationSubcatalog
from .label_keypoints import Keypoints2DSubcatalog
from .label_polygon import PolygonSubcatalog
from .label_polygon import MultiPolygonSubcatalog, PolygonSubcatalog
from .label_polyline import MultiPolyline2DSubcatalog, Polyline2DSubcatalog
from .label_sentence import SentenceSubcatalog

Expand All @@ -50,6 +51,7 @@
Polyline2DSubcatalog,
MultiPolyline2DSubcatalog,
Keypoints2DSubcatalog,
MultiPolygonSubcatalog,
SentenceSubcatalog,
]

Expand Down Expand Up @@ -101,6 +103,7 @@ class Catalog(ReprMixin, AttrsMixin):
polyline2d: Polyline2DSubcatalog = _attr()
multi_polyline2d: MultiPolyline2DSubcatalog = _attr()
keypoints2d: Keypoints2DSubcatalog = _attr()
multi_polygon: MultiPolygonSubcatalog = _attr()
sentence: SentenceSubcatalog = _attr()

def __bool__(self) -> bool:
Expand Down
3 changes: 2 additions & 1 deletion tensorbay/label/label.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
from .label_box import LabeledBox2D, LabeledBox3D
from .label_classification import Classification
from .label_keypoints import LabeledKeypoints2D
from .label_polygon import LabeledPolygon
from .label_polygon import LabeledMultiPolygon, LabeledPolygon
from .label_polyline import LabeledMultiPolyline2D, LabeledPolyline2D
from .label_sentence import LabeledSentence

Expand Down Expand Up @@ -75,6 +75,7 @@ class Label(ReprMixin, AttrsMixin):
polyline2d: List[LabeledPolyline2D] = _attr()
multi_polyline2d: List[LabeledMultiPolyline2D] = _attr()
keypoints2d: List[LabeledKeypoints2D] = _attr()
multi_polygon: List[LabeledMultiPolygon] = _attr()
sentence: List[LabeledSentence] = _attr()

def __bool__(self) -> bool:
Expand Down
183 changes: 182 additions & 1 deletion tensorbay/label/label_polygon.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

from typing import Any, Dict, Iterable, Optional, Type, TypeVar

from ..geometry import Polygon
from ..geometry import MultiPolygon, Polygon
from ..utility import ReprType, SubcatalogTypeRegister, TypeRegister, attr_base, common_loads
from .basic import LabelType, SubcatalogBase, _LabelBase
from .supports import AttributesMixin, CategoriesMixin, IsTrackingMixin
Expand Down Expand Up @@ -86,6 +86,68 @@ def __init__(self, is_tracking: bool = False) -> None:
IsTrackingMixin.__init__(self, is_tracking)


@SubcatalogTypeRegister(LabelType.MULTI_POLYGON)
class MultiPolygonSubcatalog( # pylint: disable=too-many-ancestors
SubcatalogBase, IsTrackingMixin, CategoriesMixin, AttributesMixin
):
"""This class defines the subcatalog for multiple polygon type of labels.
Arguments:
is_tracking: A boolean value indicates whether the corresponding
subcatalog contains tracking information.
Attributes:
description: The description of the entire multiple polygon subcatalog.
categories: All the possible categories in the corresponding dataset
stored in a :class:`~tensorbay.utility.name.NameList`
with the category names as keys
and the :class:`~tensorbay.label.supports.CategoryInfo` as values.
category_delimiter: The delimiter in category values indicating parent-child relationship.
attributes: All the possible attributes in the corresponding dataset
stored in a :class:`~tensorbay.utility.name.NameList`
with the attribute names as keys
and the :class:`~tensorbay.label.attribute.AttributeInfo` as values.
is_tracking: Whether the Subcatalog contains tracking information.
Examples:
*Initialization Method 1:* Init from ``MultiPolygonSubcatalog.loads()`` method.
>>> catalog = {
... "MULTI_POLYGON": {
... "isTracking": True,
... "categories": [{"name": "0"}, {"name": "1"}],
... "attributes": [{"name": "gender", "enum": ["male", "female"]}],
... }
... }
>>> MultiPolygonSubcatalog.loads(catalog["MULTI_POLYGON"])
MultiPolygonSubcatalog(
(is_tracking): True,
(categories): NameList [...],
(attributes): NameList [...]
)
*Initialization Method 2:* Init an empty MultiPolygonSubcatalog
and then add the attributes.
>>> from tensorbay.label import CategoryInfo, AttributeInfo
>>> multi_polygon_subcatalog = MultiPolygonSubcatalog()
>>> multi_polygon_subcatalog.is_tracking = True
>>> multi_polygon_subcatalog.add_category("a")
>>> multi_polygon_subcatalog.add_attribute("gender", enum=["female", "male"])
>>> multi_polygon_subcatalog
MultiPolyline2DSubcatalog(
(is_tracking): True,
(categories): NameList [...],
(attributes): NameList [...]
)
"""

def __init__(self, is_tracking: bool = False) -> None:
SubcatalogBase.__init__(self)
IsTrackingMixin.__init__(self, is_tracking)


@TypeRegister(LabelType.POLYGON)
class LabeledPolygon(_LabelBase, Polygon): # pylint: disable=too-many-ancestors
"""This class defines the concept of polygon label.
Expand Down Expand Up @@ -198,3 +260,122 @@ def dumps(self) -> Dict[str, Any]: # type: ignore[override]
"""
return self._dumps()


@TypeRegister(LabelType.MULTI_POLYGON)
class LabeledMultiPolygon( # type: ignore[misc]
_LabelBase, MultiPolygon
): # pylint: disable=too-many-ancestors
"""This class defines the concept of multiple polygon label.
:class:`LabeledMultiPolygon` is the multipolygon type of label,
which is often used for CV tasks such as semantic segmentation.
Arguments:
points: A list of 2D points representing the vertices of the polygon.
category: The category of the label.
attributes: The attributs of the label.
instance: The instance id of the label.
Attributes:
category: The category of the label.
attributes: The attributes of the label.
instance: The instance id of the label.
Examples:
>>> LabeledMultiPolygon(
... [[(1.0, 2.0), (2.0, 3.0), (1.0, 3.0)], [(1.0, 4.0), (2.0, 3.0), (1.0, 8.0)]],
... category = "example",
... attributes = {"key": "value"},
... instance = "12345",
... )
LabeledMultiPolygon [
Polygon [...],
Polygon [...]
](
(category): 'example',
(attributes): {...},
(instance): '12345'
)
"""

_T = TypeVar("_T", bound="LabeledMultiPolygon")
_repr_type = ReprType.SEQUENCE
_repr_attrs = _LabelBase._repr_attrs
_attrs_base: MultiPolygon = attr_base(key="multiPolygon")

def __init__(
self,
polygons: Optional[Iterable[Iterable[Iterable[float]]]] = None,
*,
category: Optional[str] = None,
attributes: Optional[Dict[str, Any]] = None,
instance: Optional[str] = None,
):
MultiPolygon.__init__(self, polygons=polygons)
_LabelBase.__init__(self, category, attributes, instance)

@classmethod
def loads(cls: Type[_T], contents: Dict[str, Any]) -> _T: # type: ignore[override]
"""Loads a LabeledMultiPolygon from a list of dict containing the information of the label.
Arguments:
contents: A dict containing the information of the multipolygon label.
Returns:
The loaded :class:`LabeledMultiPolygon` object.
Examples:
>>> contents = {
... "multiPolygon": [
... [
... {"x": 1.0, "y": 2.0},
... {"x": 2.0, "y": 3.0},
... {"x": 1.0, "y": 3.0},
... ],
... [{"x": 1.0, "y": 4.0}, {"x": 2.0, "y": 3.0}, {"x": 1.0, "y": 8.0}],
... ],
... "category": "example",
... "attributes": {"key": "value"},
... "instance": "12345",
... }
>>> LabeledMultiPolygon.loads(contents)
LabeledMultiPolygon [
Polygon [...],
Polygon [...]
](
(category): 'example',
(attributes): {...},
(instance): '12345'
)
"""
return common_loads(cls, contents)

def dumps(self) -> Dict[str, Any]: # type: ignore[override]
"""Dumps the current multipolygon label into a dict.
Returns:
A dict containing all the information of the multipolygon label.
Examples:
>>> labeledmultipolygon = LabeledMultiPolygon(
... [[(1, 2), (2, 3), (1, 3)],[(1, 2), (2, 3), (1, 3)]],
... category = "example",
... attributes = {"key": "value"},
... instance = "123",
... )
>>> labeledmultipolygon.dumps()
{
'category': 'example',
'attributes': {'key': 'value'},
'instance': '123',
'multiPolygon': [
[{'x': 1, 'y': 2}, {'x': 2, 'y': 3}, {'x': 1, 'y': 3}],
[{"x": 1.0, "y": 4.0}, {"x": 2.0, "y": 3.0}, {"x": 1.0, "y": 8.0}]
]
}
"""
return self._dumps()
Loading

0 comments on commit d5b4f05

Please sign in to comment.